diff options
Diffstat (limited to 'mingling')
| -rw-r--r-- | mingling/src/example_docs.rs | 173 | ||||
| -rw-r--r-- | mingling/src/lib.rs | 4 |
2 files changed, 170 insertions, 7 deletions
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index 806553f..ab725de 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -294,7 +294,7 @@ pub mod example_completion {} /// /// ```bash /// cargo expand --manifest-path examples/example-dispatch-tree/Cargo.toml > expanded.rs -/// cat expanded.rs | grep dispatch_args_trie -A 264 +/// cat expanded.rs /// ``` /// /// Cargo.toml @@ -317,11 +317,10 @@ pub mod example_completion {} /// fn main() { /// let mut program = ThisProgram::new(); /// -/// // After enabling `dispatch_tree`, this method will no longer exist +/// // // After enabling `dispatch_tree`, this method will no longer exist /// // program.with_dispatcher(CommandGreet); /// // -/// // The `CompletionDispatcher` automatically generated by `comp` will also be imported -/// // automatically +/// // // The `CompletionDispatcher` automatically generated by `comp` will also be imported automatically /// // program.with_dispatcher(CompletionDispatcher); /// /// program.exec(); @@ -370,7 +369,7 @@ pub mod example_dispatch_tree {} /// ```ignore /// use mingling::prelude::*; /// use mingling::{ -/// res::{exit_code, update_exit_code}, +/// res::{ExitCode, exit_code}, /// setup::ExitCodeSetup, /// }; /// @@ -385,8 +384,8 @@ pub mod example_dispatch_tree {} /// pack!(ResultError = ()); /// /// #[chain] -/// fn handle_error_entry(_prev: ErrorEntry) -> Next { -/// update_exit_code::<ThisProgram>(1); +/// fn handle_error_entry(_prev: ErrorEntry, ec: &mut ExitCode) -> Next { +/// ec.exit_code = 1; /// return ResultError::default(); /// } /// @@ -569,6 +568,166 @@ pub mod example_general_renderer {} /// gen_program!(); /// ``` pub mod example_picker {} + +/// +/// Cargo.toml +/// ```ignore +/// [package] +/// name = "example-repl" +/// version = "0.0.1" +/// edition = "2024" +/// +/// [dependencies] +/// mingling = { path = "../../mingling", features = ["repl", "parser"] } +/// just_fmt = "0.1.2" +/// ``` +/// +/// main.rs +/// ```ignore +/// use mingling::{REPL, hook::ProgramHook, prelude::*, this}; +/// use std::{env::current_dir, path::PathBuf}; +/// +/// // Resource to store the current directory +/// #[derive(Clone)] +/// struct CurrentDir { +/// dir: PathBuf, +/// } +/// +/// impl Default for CurrentDir { +/// fn default() -> Self { +/// Self { +/// dir: current_dir().unwrap(), +/// } +/// } +/// } +/// +/// fn main() { +/// let mut program = ThisProgram::new(); +/// +/// // Add resource +/// program.with_resource(CurrentDir::default()); +/// +/// // Add dispatchers +/// program.with_dispatcher(ChangeDirectoryCommand); +/// program.with_dispatcher(ListCommand); +/// program.with_dispatcher(ExitCommand); +/// +/// // Add hooks to handle REPL-related events +/// program.with_hook( +/// ProgramHook::empty() +/// .on_repl_begin(|| { +/// // Print welcome message +/// println!("Welcome!") +/// }) +/// .on_repl_pre_readline(|| { +/// // Print prompt +/// let res = this::<ThisProgram>().res::<CurrentDir>().unwrap(); +/// let dir_str: String = res.dir.to_string_lossy().into(); +/// let prompt = format!( +/// "{}> ", +/// dir_str +/// .replace(&['/', '\\'][..], ">") +/// .trim_start_matches('>') +/// .trim_end_matches('>') +/// ); +/// print!("{}", prompt) +/// }) +/// .on_repl_receive_result(|r| { +/// // Print output +/// if !r.is_empty() { +/// println!("{}", r.trim()) +/// } +/// }), +/// ); +/// +/// // Start the REPL loop +/// program.exec_repl(); +/// } +/// +/// // Create error route +/// pack!(ErrorDirectoryNotExist = PathBuf); +/// +/// // Create commands: cd ls exit +/// dispatcher!("cd", ChangeDirectoryCommand => ChangeDirectoryEntry); +/// dispatcher!("ls", ListCommand => ListEntry); +/// dispatcher!("exit", ExitCommand => ExitEntry); +/// +/// // Define data needed for the cd command's execution phase +/// pack!(StateChangeDirectory = String); +/// +/// // Define data needed for the ls command's rendering phase +/// pack!(ResultList = Vec<String>); +/// +/// // Parse cd command arguments +/// #[chain] +/// fn parse_cd_args(prev: ChangeDirectoryEntry) -> Next { +/// let join = prev.pick(()).unpack(); +/// StateChangeDirectory::new(join) +/// } +/// +/// // Execute directory change +/// #[chain] +/// fn handle_cd(prev: StateChangeDirectory, current_dir: &mut CurrentDir) -> Next { +/// let join = prev.inner; +/// let new_dir = just_fmt::fmt_path::fmt_path(current_dir.dir.join(join)).unwrap_or_default(); +/// +/// // If the path is not found, route to error handling +/// if !new_dir.exists() { +/// return ErrorDirectoryNotExist::new(new_dir).to_render(); +/// } +/// +/// current_dir.dir = new_dir; +/// empty_result!() +/// } +/// +/// // Get directory contents via the CurrentDir resource +/// #[chain] +/// fn handle_ls(_prev: ListEntry, current_dir: &CurrentDir) -> Next { +/// let dir = ¤t_dir.dir; +/// let entries: Vec<String> = std::fs::read_dir(dir) +/// .into_iter() +/// .flat_map(|rd| rd.filter_map(|e| e.ok())) +/// .map(|e| { +/// let name = e.file_name().to_string_lossy().to_string(); +/// if e.file_type().map(|t| t.is_dir()).unwrap_or(false) { +/// format!("{}/", name) +/// } else { +/// name +/// } +/// }) +/// .collect(); +/// +/// // Render ResultList +/// ResultList::new(entries).to_render() +/// } +/// +/// // Render ResultList data +/// #[renderer] +/// fn render_list(list: ResultList) { +/// for item in list.inner { +/// r_println!("{}", item) +/// } +/// } +/// +/// // Handle exit command event +/// #[chain] +/// fn handle_exit( +/// _prev: ExitEntry, +/// repl: &mut REPL, // Import REPL resource, registered in `exec_repl`, usable directly +/// ) { +/// // Set the REPL exit flag; REPL will exit after this loop iteration +/// repl.exit = true; +/// } +/// +/// // Handle path not found event +/// #[renderer] +/// fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) { +/// r_println!("Directory not found: {}", err.inner.display()) +/// } +/// +/// gen_program!(); +/// ``` +pub mod example_repl {} /// `Mingling` Example - Global Resource Injection /// /// This example demonstrates how to use global resource injection in `#[chain]` functions. diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs index 4803c23..a8579d4 100644 --- a/mingling/src/lib.rs +++ b/mingling/src/lib.rs @@ -83,6 +83,8 @@ pub mod macros { /// Used to create a dispatcher with clap argument parsing #[cfg(feature = "clap")] pub use mingling_macros::dispatcher_clap; + /// Used to create an empty result value for early return from a chain function + pub use mingling_macros::empty_result; /// Used to collect data and create a command-line context pub use mingling_macros::gen_program; /// Used to generate a struct implementing the `HelpRequest` trait via a method @@ -211,6 +213,8 @@ pub mod prelude { pub use crate::macros::chain; /// Re-export of the `dispatcher` macro for routing commands. pub use crate::macros::dispatcher; + /// Re-export of the `empty_result` macro for creating an empty result value for early return. + pub use crate::macros::empty_result; /// Re-export of the `gen_program` macro for generating the program entry point. pub use crate::macros::gen_program; /// Re-export of the `pack` macro for creating wrapper types. |
