aboutsummaryrefslogtreecommitdiff
path: root/mingling/src/example_docs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mingling/src/example_docs.rs')
-rw-r--r--mingling/src/example_docs.rs1174
1 files changed, 348 insertions, 826 deletions
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs
index c292598..055615d 100644
--- a/mingling/src/example_docs.rs
+++ b/mingling/src/example_docs.rs
@@ -1,129 +1,5 @@
// Auto generated
-/// Example Argument Parse
-///
-/// > This example demonstrates how to use the `parser` feature to parse user input
-///
-/// Run:
-/// ```bash
-/// cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- transfer README.md --size 32kib
-/// cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- transfer src/ --dir
-/// cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- strict-transfer README.md
-/// cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- strict-transfer --dir
-/// ```
-///
-/// Output:
-/// ```plaintext
-/// file: README.md (32768)
-/// dir: src/ (1048576)
-/// file: README.md (1048576)
-/// Error: name is not provided
-/// ```
-///
-/// Source code (./Cargo.toml)
-/// ```toml
-/// [package]
-/// name = "example-argument-parse"
-/// version = "0.1.0"
-/// edition = "2024"
-///
-/// [dependencies.mingling]
-/// path = "../../mingling"
-///
-/// # Enable `parser` features
-/// features = ["parser", "extras"]
-///
-/// [workspace]
-/// ```
-///
-/// Source code (./src/main.rs)
-/// ```ignore
-/// use mingling::{macros::route, prelude::*};
-/// use std::io::Write;
-///
-/// dispatcher!("transfer", CMDTransfer => EntryTransfer);
-/// dispatcher!("strict-transfer", CMDStrictTransfer => EntryStrictTransfer);
-///
-/// pack!(ResultFile = (bool, usize, String)); // (IsDir, Size, Name)
-///
-/// #[chain]
-/// fn handle_transfer_parse(args: EntryTransfer) -> Next {
-/// // --------- IMPORTANT ---------
-/// // First parse flag arguments (like --dir/-D), then positional arguments
-/// let result: ResultFile = args
-/// // Name --dir --size 20mib
-/// // ^^^^^^^^^^^^_ first
-/// .pick::<bool>(["--dir", "-D"])
-/// // Name --dir
-/// // ^^^^^_ second (or `-D`)
-/// .pick_or::<usize>("--size", 1024 * 1024_usize)
-/// // Name
-/// // ^^^^_ finally, pick positional arg
-/// .pick::<String>(())
-/// .after(|str| str.trim().replace(' ', ""))
-/// // Unpack to tuple (is_dir, size, name)
-/// .unpack()
-/// // Convert into ResultFile
-/// .into();
-/// // --------- IMPORTANT ---------
-/// result.into()
-/// }
-///
-/// pack!(ErrorNoNameProvided = ());
-///
-/// #[chain]
-/// fn handle_strict_transfer_parse(args: EntryStrictTransfer) -> Next {
-/// // --------- IMPORTANT ---------
-/// // Strict parsing: error immediately if the name is not provided
-/// let result: ResultFile = route! { // Use `route!` to wrap a Picker that contains `or_route`
-/// args
-/// .pick::<bool>(["--dir", "-D"])
-/// .pick_or::<usize>("--size", 1024 * 1024_usize)
-/// // Finally parse the positional argument; if not found, route to `ErrorNoNameProvided`
-/// .pick_or_route::<String, _>((), ErrorNoNameProvided::default())
-/// .after(|str| str.trim().replace(' ', ""))
-/// .unpack()
-/// }
-/// // Convert into ResultFile
-/// .into();
-/// // --------- IMPORTANT ---------
-/// result.to_chain()
-/// }
-///
-/// /// Renders the parsed transfer result (file/dir, size, name).
-/// #[renderer]
-/// fn render_result_file(result: ResultFile) -> RenderResult {
-/// let (is_dir, size, name) = result.into();
-/// let mut result = RenderResult::new();
-/// writeln!(
-/// result,
-/// "{}: {} ({})",
-/// if is_dir { "dir" } else { "file" },
-/// name,
-/// size
-/// )
-/// .ok();
-/// result
-/// }
-///
-/// /// Renders the error when no name is provided.
-/// #[renderer]
-/// fn render_error_no_name_provided(_: ErrorNoNameProvided) -> RenderResult {
-/// let mut result = RenderResult::new();
-/// writeln!(result, "Error: name is not provided").ok();
-/// result
-/// }
-///
-/// gen_program!();
-///
-/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDTransfer);
-/// program.with_dispatcher(CMDStrictTransfer);
-/// program.exec_and_exit();
-/// }
-/// ```
-pub mod example_argument_parse {}
/// Example Argument Picker
///
/// > Demonstrates how to use Mingling's `picker` feature and `Picker` to extract typed arguments from the command line.
@@ -186,19 +62,34 @@ pub mod example_argument_parse {}
///
/// // --------- IMPORTANT ---------
///
-/// dispatcher!("calc", CMDCalculate => EntryCalculate);
+/// dispatcher!("calc", EntryCalculate);
+///
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorNumberANotProvided;
+///
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorNumberBNotProvided;
///
-/// pack_err!(ErrorNumberANotProvided);
-/// pack_err!(ErrorNumberBNotProvided);
-/// pack_err!(ErrorNumberOperatorNotProvided);
-/// pack_err!(ErrorDivisionByZero);
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorNumberOperatorNotProvided;
///
-/// pack!(StateAdd = (f32, f32));
-/// pack!(StateSubtract = (f32, f32));
-/// pack!(StateMultiply = (f32, f32));
-/// pack!(StateDivide = (f32, f32));
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorDivisionByZero;
///
-/// pack!(ResultNumber = f32);
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateAdd((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateSubtract((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateMultiply((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateDivide((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultNumber(f32);
///
/// #[derive(Grouped)]
/// struct StateCalculate {
@@ -269,7 +160,6 @@ pub mod example_argument_parse {}
/// program.with_resource(ResNumberDisplaySetting { round: *round });
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDCalculate);
/// program.exec_and_exit();
/// }
///
@@ -280,13 +170,13 @@ pub mod example_argument_parse {}
/// // Use the arg! macro to define a positional argument of type f32
/// // |
/// // vvvvvvvvvv
-/// args.pick_or_route(&arg![f32], || ErrorNumberANotProvided::default().to_chain())
+/// args.pick_or_route(&arg![f32], || ErrorNumberANotProvided.to_chain())
/// .pick_or_route(&arg![Operator], || {
-/// ErrorNumberOperatorNotProvided::default().to_chain()
+/// ErrorNumberOperatorNotProvided.to_chain()
/// }) // Returns a routable type when not found or fails to parse
/// // |
-/// // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-/// .pick_or_route(&arg![f32], || ErrorNumberBNotProvided::default().to_chain())
+/// // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+/// .pick_or_route(&arg![f32], || ErrorNumberBNotProvided.to_chain())
/// // Use `to_result` to parse arguments
/// // and convert to Result<(Tuple, ...), Route> type
/// .to_result()
@@ -294,7 +184,7 @@ pub mod example_argument_parse {}
/// // --------- IMPORTANT ---------
///
/// if operator == Operator::Slash && number_b == 0. {
-/// return ErrorDivisionByZero::default().to_chain();
+/// return ErrorDivisionByZero.to_chain();
/// }
///
/// StateCalculate {
@@ -308,41 +198,41 @@ pub mod example_argument_parse {}
/// #[chain]
/// fn handle_state_calculate(state: StateCalculate) -> Next {
/// match (state.operator, state.number_a, state.number_b) {
-/// (Operator::Plus, a, b) => StateAdd::new((a, b)).to_chain(),
-/// (Operator::Dash, a, b) => StateSubtract::new((a, b)).to_chain(),
-/// (Operator::Slash, a, b) => StateDivide::new((a, b)).to_chain(),
-/// (Operator::Star, a, b) => StateMultiply::new((a, b)).to_chain(),
+/// (Operator::Plus, a, b) => StateAdd((a, b)).to_chain(),
+/// (Operator::Dash, a, b) => StateSubtract((a, b)).to_chain(),
+/// (Operator::Slash, a, b) => StateDivide((a, b)).to_chain(),
+/// (Operator::Star, a, b) => StateMultiply((a, b)).to_chain(),
/// }
/// }
///
/// #[chain]
/// fn handle_state_add(state_add: StateAdd) -> ResultNumber {
-/// let (a, b) = state_add.inner;
-/// ResultNumber::new(a + b)
+/// let (a, b) = state_add.0;
+/// ResultNumber(a + b)
/// }
///
/// #[chain]
/// fn handle_state_subtract(state_subtract: StateSubtract) -> ResultNumber {
-/// let (a, b) = state_subtract.inner;
-/// ResultNumber::new(a - b)
+/// let (a, b) = state_subtract.0;
+/// ResultNumber(a - b)
/// }
///
/// #[chain]
/// fn handle_state_multiply(state_multiply: StateMultiply) -> ResultNumber {
-/// let (a, b) = state_multiply.inner;
-/// ResultNumber::new(a * b)
+/// let (a, b) = state_multiply.0;
+/// ResultNumber(a * b)
/// }
///
/// #[chain]
/// fn handle_state_divide(state_divide: StateDivide) -> ResultNumber {
-/// let (a, b) = state_divide.inner;
-/// ResultNumber::new(a / b)
+/// let (a, b) = state_divide.0;
+/// ResultNumber(a / b)
/// }
///
/// #[renderer]
/// fn render_result_number(result: ResultNumber, setting: &ResNumberDisplaySetting) -> String {
/// let round = setting.round;
-/// let result = if round { result.round() } else { result.inner };
+/// let result = if round { result.round() } else { result.0 };
/// format!("Result: {}", result)
/// }
///
@@ -404,8 +294,8 @@ pub mod example_argument_picker {}
/// [dependencies.mingling]
/// path = "../../mingling"
///
-/// # Enable `parser` features
-/// features = ["async", "parser"]
+/// # Enable `picker` features
+/// features = ["async", "picker"]
///
/// # Import any async runtime, e.g. Tokio
/// [dependencies.tokio]
@@ -424,8 +314,6 @@ pub mod example_argument_picker {}
/// async fn main() {
/// let mut program = ThisProgram::new();
///
-/// program.with_dispatcher(CMDDownload);
-///
/// // Add a hook to display when the download begins
/// program.with_hook(ProgramHook::empty().on_begin::<_, ()>(|_| println!("Download begin")));
///
@@ -435,15 +323,16 @@ pub mod example_argument_picker {}
/// // --------- IMPORTANT ---------
/// }
///
-/// dispatcher!("download", CMDDownload => EntryDownload);
+/// dispatcher!("download", EntryDownload);
///
-/// pack!(ResultDownloaded = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultDownloaded(String);
///
/// // --------- IMPORTANT ---------
/// #[chain]
/// // vvvvv_ `async` keyword can be used directly here
/// pub async fn handle_download(args: EntryDownload) -> Next {
-/// let file_name = args.pick(()).unpack();
+/// let file_name = args.pick_or_default(&arg![String]).unwrap();
/// fake_download(file_name).await.into()
/// }
///
@@ -461,7 +350,7 @@ pub mod example_argument_picker {}
///
/// async fn fake_download(file_name: String) -> ResultDownloaded {
/// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
-/// ResultDownloaded::new(file_name)
+/// ResultDownloaded(file_name)
/// }
/// ```
pub mod example_async_support {}
@@ -499,40 +388,38 @@ pub mod example_async_support {}
/// use std::io::Write;
///
/// // Define the `greet` subcommand
-/// // _____________________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
-/// // / _____________________ dispatcher name
-/// // | / _________ entry, records raw arguments
-/// // | | / ^^^^^^^^^^^^^
-/// // vvvvv vvvvvvvv vvvvvvvvvv \_ equivalent to pack!(EntryGreet = Vec<String>)
-/// dispatcher!("greet", CMDGreet => EntryGreet);
+/// // _________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
+/// // /
+/// // | _________ entry, records raw arguments
+/// // | / ^^^^^^^^^^^^^
+/// // vvvvv vvvvvvvvvv \_ a newtype wrapper around Vec<String>
+/// dispatcher!("greet", EntryGreet);
///
/// fn main() {
/// // Create a new ThisProgram
-/// let mut program = ThisProgram::new();
-///
-/// // Add the CMDGreet dispatcher
-/// program.with_dispatcher(CMDGreet);
+/// let program = ThisProgram::new();
///
/// // Run the program, then exit the process
/// program.exec_and_exit();
/// }
///
/// // Quickly wrap a type into a type recognizable by the current program
-/// // ____________________ Wrapped type name
-/// // / _______ Wrapped type inner value
-/// // | /
-/// // vvvvvvvvvv vvvvvv
-/// pack!(ResultName = String);
+/// // ___________________ Registers this type into ThisProgram
+/// // / _______ Adds DerefMut, Deref, Into, From wrappers
+/// // | /
+/// // vvvvvvvvvv vvvvv
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// // Define the `handle_greet` chain for parsing input text
/// // ____________________ Previous type:
/// // / Mingling deduces types at runtime and routes them to this function
/// // | _____ will be expanded to:
-/// // | / impl Into<mingling::ChainProcess<ThisProgram>>
+/// // | / ChainProcess<ThisProgram>
/// #[chain] // vvvvvvvvvv vvvv
/// fn handle_greet(args: EntryGreet) -> Next {
/// let name: ResultName = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string())
@@ -645,7 +532,6 @@ pub mod example_basic {}
/// // Capture Clap's help information and write to RenderResult
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDGreet);
/// program.exec_and_exit();
/// }
///
@@ -657,7 +543,7 @@ pub mod example_basic {}
/// // vvvvvvv vvvvvvvvvvvv vvvvvvv
/// #[derive(Default, clap::Parser, Grouped)]
/// #[dispatcher_clap(
-/// "greet", CMDGreet, // Bind EntryGreet to "greet" command
+/// "greet", // Bind EntryGreet to "greet" command
/// help = true, // Generate clap help for EntryGreet
/// error = ErrorGreetParsed, // Generate and bind error type for parse failure
/// // ^^^^^\__ Using `error` intercepts parse failure information into the specified type,
@@ -709,11 +595,13 @@ pub mod example_clap_binding {}
/// > Types are defined in a submodule (`sub`), and `gen_program!()` resolves
/// > them automatically via pathf without explicit `use` imports.
/// >
-/// > **Important**: `dispatch_tree` must be enabled in BOTH `[dependencies]`
-/// > AND `[build-dependencies]` so that pathf's builder can detect
-/// > `__internal_dispatcher_*` types needed by the dispatch tree.
+/// > **Important**: `dispatch_tree` must be enabled so that pathf's builder can
+/// > detect `__internal_dispatcher_*` types needed by the dispatch tree.
/// >
/// > Also requires `extras` for the implicit `dispatcher!("hello")` form.
+/// >
+/// > With the `pathf` feature, `gen_program!()` automatically invokes
+/// > `build_pathf!()` at compile time — no `build.rs` needed.
///
/// Run:
/// ```bash
@@ -739,19 +627,6 @@ pub mod example_clap_binding {}
/// "pathf",
/// ] }
///
-/// [build-dependencies]
-/// mingling = { path = "../../mingling", features = [
-/// "builds",
-///
-/// # --------- IMPORTANT ---------
-/// # To use pathf under dispatch_tree
-/// # **must** enable the `dispatch_tree`
-/// # feature in build dependencies
-/// "dispatch_tree",
-/// "pathf",
-/// # --------- IMPORTANT ---------
-/// ] }
-///
/// [workspace]
/// ```
///
@@ -805,15 +680,6 @@ pub mod example_combine_pathf_dispatch_tree {}
/// "pathf",
/// ]
///
-/// [build-dependencies.mingling]
-/// path = "../../mingling"
-/// features = [
-/// # Enable the `build` feature for build-time support
-/// "build",
-/// # `pathf` must also be enabled in build-dependencies
-/// "pathf",
-/// ]
-///
/// [workspace]
/// ```
///
@@ -824,10 +690,7 @@ pub mod example_combine_pathf_dispatch_tree {}
/// use mingling::prelude::*;
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(sub::CMDHello);
-/// program.with_dispatcher(sub::CMDDescription);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -876,37 +739,33 @@ pub mod example_combine_pathf_metadata {}
/// use mingling::{macros::buffer, picker::IntoPicker, prelude::*};
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// // Import the dispatchers generated by the `#[command]` macro
-/// program.with_dispatcher(CMDHelloWorld);
-/// program.with_dispatcher(CMDGreetSomeone);
-/// program.with_dispatcher(CMDGoodBye);
-///
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
-/// pack!(ResultGreeting = String);
-/// pack!(ResultGoodbye = ());
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultGreeting(String);
+///
+/// #[derive(Grouped)]
+/// pub struct ResultGoodbye;
///
/// // --------- IMPORTANT ---------
-/// // Auto-generates dispatcher!("hello.world", CMDHelloWorld => EntryHelloWorld);
+/// // Auto-generates dispatcher!("hello.world", EntryHelloWorld);
/// #[command]
/// fn hello_world() -> ResultGreeting {
-/// ResultGreeting::new("World".to_string())
+/// ResultGreeting("World".to_string())
/// }
///
-/// // Auto-generates dispatcher!("hello-world", CMDGreetSomeone => EntryGreetSomeone);
+/// // Auto-generates dispatcher!("hello-world", EntryGreetSomeone);
/// #[command(node = "greet-someone")]
/// fn greet_someone(args: Vec<String>) -> ResultGreeting {
/// let name = args.pick_or(&arg![String], || "World".to_string()).unwrap();
-/// ResultGreeting::new(name)
+/// ResultGreeting(name)
/// }
///
-/// // Auto-generates dispatcher!("goodbye", CMDGoodBye => EntryGoodBye);
-/// #[command(name = CMDGoodBye, entry = EntryGoodBye)]
+/// // Auto-generates dispatcher!("goodbye", EntryGoodBye);
+/// #[command(entry = EntryGoodBye)]
/// fn goodbye() -> ResultGoodbye {
-/// ResultGoodbye::default()
+/// ResultGoodbye
/// }
/// // --------- IMPORTANT ---------
///
@@ -932,30 +791,15 @@ pub mod example_command_macro {}
/// To make your completions work, you need to generate a completion script using Mingling's tools
///
/// 1. Enable features
-/// You need to enable the `build` and `comp` features for `mingling` in `[build-dependencies]`
-///
-/// 2. Write `build.rs`
-/// Write the following in `build.rs`
-///
-/// ```rust,ignore
-/// fn main() {
-/// build_scripts();
-/// }
-///
-/// /// Generate completion scripts
-/// fn build_scripts() {
-/// // `env!("CARGO_PKG_NAME")` equals the crate name, which matches the binary name.
-/// // If your binary name differs from the crate name, specify it explicitly.
-/// mingling::build::build_comp_scripts(
-/// // Your binary name:
-/// env!("CARGO_PKG_NAME"),
-/// )
-/// .unwrap();
-/// }
-/// ```
+/// Enable the `comp` feature for `mingling` in `[dependencies]`
+///
+/// 2. Generate completion scripts
+/// When the `comp` feature is enabled, `gen_program!()` automatically invokes
+/// `build_comp!()` at compile time, which generates the completion scripts
+/// (named after `CARGO_PKG_NAME`) into `target/mingling/`.
///
/// 3. Verify
-/// Build your project with `cargo build --release`. The completion scripts will be generated in `target/release/`
+/// Build your project with `cargo build`. The completion scripts will be generated in `target/mingling/`
///
/// Execute the script or have it be automatically sourced by your Shell
///
@@ -982,19 +826,7 @@ pub mod example_command_macro {}
/// features = [
/// # Enable `comp` features
/// "comp",
-/// "parser",
-/// ]
-///
-/// [build-dependencies.mingling]
-/// path = "../../mingling"
-///
-/// features = [
-/// # Enable `comp` features
-/// "comp",
-///
-/// # If you want to build completion scripts,
-/// # enable `build` features
-/// "build",
+/// "picker",
/// ]
///
/// [workspace]
@@ -1002,19 +834,11 @@ pub mod example_command_macro {}
///
/// Source code (./src/main.rs)
/// ```ignore
-/// use mingling::{macros::suggest, prelude::*, ShellContext, Suggest};
+/// use mingling::{ShellContext, Suggest, macros::suggest, prelude::*};
/// use std::io::Write;
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// program.with_dispatcher(CMDGreet);
-///
-/// // --------- IMPORTANT ---------
-/// // The `comp` feature makes `gen_program!()` generate a CMDCompletion automatically
-/// // It adds a hidden `__comp` subcommand for communication with the completion script
-/// program.with_dispatcher(crate::CMDCompletion);
-/// // --------- IMPORTANT ---------
+/// let program = ThisProgram::new();
///
/// // TIP: Note that the completion script reads stdout,
/// // so make sure no output is produced before the CMDCompletion is dispatched.
@@ -1022,12 +846,12 @@ pub mod example_command_macro {}
/// }
///
/// // --------- IMPORTANT ---------
-/// // __________________________________________ Entry point bound to completion behavior
-/// // / _________________________ Shell context for obtaining user input state
-/// // | / ________ Suggest, used to return completion results
-/// // vvvvvvvvvv | /
-/// #[completion(EntryGreet)] // vvvvvvvvvvvv vvvvvvv
-/// fn complete_greet_entry(ctx: &ShellContext) -> Suggest {
+/// // _________________________________________ Entry point bound to completion behavior
+/// // / _________________________ Shell context for obtaining user input state
+/// // | / ________ Suggest, used to return completion results
+/// // vvvvvvvvvv | /
+/// #[completion(EntryGreet)] // vvvvvvvvvvvv vvvvvvv
+/// fn complete_greet_entry(ctx: ShellContext) -> Suggest {
/// // When the previous word is `greet` (the current command being typed)
/// if ctx.previous_word == "greet" {
/// // Return suggestions
@@ -1040,18 +864,22 @@ pub mod example_command_macro {}
/// }
///
/// // When the user is typing `--repeat`
-/// if ctx.filling_argument(["-r", "--repeat"]) {
+/// if ctx.previous_word == "-r" || ctx.previous_word == "--repeat" {
/// return suggest! {}; // Don't suggest anything
/// }
///
/// // When the user is typing `-`
-/// if ctx.typing_argument() {
-/// return suggest! {
+/// if ctx.current_word.starts_with('-') {
+/// // Remove arguments that have already been typed by the user
+/// let typed: Vec<&str> = ctx.all_words.iter().map(String::as_str).collect();
+/// let mut set = suggest! {
/// "-r": "Number of repetitions",
/// "--repeat": "Number of repetitions",
+/// };
+/// if let Suggest::Suggest(items) = &mut set {
+/// items.retain(|item| !typed.contains(&item.suggest().as_str()));
/// }
-/// // Remove arguments that have already been typed by the user
-/// .strip_typed_argument(ctx);
+/// return set;
/// }
///
/// // Otherwise, suggest nothing
@@ -1062,15 +890,16 @@ pub mod example_command_macro {}
/// }
/// // --------- IMPORTANT ---------
///
-/// dispatcher!("greet", CMDGreet => EntryGreet);
-/// pack!(ResultName = (u8, String));
+/// dispatcher!("greet", EntryGreet);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName((u8, String));
///
/// #[chain]
/// fn handle_greet(args: EntryGreet) -> Next {
/// let result: ResultName = args
-/// .pick_or(["-r", "--repeat"], 1)
-/// .pick_or((), "World")
-/// .unpack()
+/// .pick_or(&arg![repeat: u8, 'r'], || 1)
+/// .pick_or(&arg![String], || "World".to_string())
+/// .unwrap()
/// .into();
/// result.into()
/// }
@@ -1078,7 +907,7 @@ pub mod example_command_macro {}
/// /// Renders the greeting with the result name and repeat count.
/// #[renderer]
/// fn render_name(result: ResultName) -> RenderResult {
-/// let (repeat, name) = result.inner;
+/// let (repeat, name) = result.0;
/// let mut render_result = RenderResult::new();
/// let mut parts = Vec::with_capacity(repeat as usize);
/// for _ in 0..repeat {
@@ -1091,167 +920,14 @@ pub mod example_command_macro {}
/// gen_program!();
/// ```
pub mod example_completion {}
-/// Example Custom Pickable
-///
-/// > This example demonstrates how to use the Pickable trait to add parsing for your types
-///
-/// Run:
-/// ```bash
-/// cargo run --manifest-path examples/example-custom-pickable/Cargo.toml --quiet -- connect 127.0.0.1:5012
-/// cargo run --manifest-path examples/example-custom-pickable/Cargo.toml --quiet -- connect 127.0.0.1
-/// ```
-///
-/// Output:
-/// ```plaintext
-/// Connected to "127.0.0.1:5012"
-/// Failed to parse address
-/// ```
-///
-/// Source code (./Cargo.toml)
-/// ```toml
-/// [package]
-/// name = "example-custom-pickable"
-/// version = "0.1.0"
-/// edition = "2024"
-///
-/// [dependencies.mingling]
-/// path = "../../mingling"
-///
-/// features = ["parser", "extras"]
-///
-/// [workspace]
-/// ```
-///
-/// Source code (./src/main.rs)
-/// ```ignore
-/// use mingling::{macros::route, parser::Pickable, prelude::*, Grouped};
-/// use std::io::Write;
-///
-/// // Define types that can be recognized by Mingling
-/// // ________________________ `Pickable` trait needs to implement Default
-/// // / ________ The Grouped derive macro registers an ID for this type
-/// // | / Mingling uses this ID to identify the type
-/// // vvvvvvv vvvvvvv
-/// #[derive(Debug, Default, Clone, Grouped)]
-/// pub struct Address {
-/// pub ip: [u8; 4],
-/// pub port: u16,
-/// }
-///
-/// // --------- IMPORTANT ---------
-/// impl Pickable for Address {
-/// type Output = Address;
-/// fn pick(args: &mut mingling::parser::Argument, flag: mingling::Flag) -> Option<Self::Output> {
-/// // Extract the raw string from Argument using the Flag
-/// let raw: String = args.pick_argument(flag)?.clone();
-///
-/// // Use TryFrom to parse the address
-/// Address::try_from(raw).ok()
-/// }
-/// }
-/// // --------- IMPORTANT ---------
-///
-/// dispatcher!("connect", CMDConnect => EntryConnect);
-/// pack!(ErrorParseAddressFailed = ());
-///
-/// #[chain]
-/// fn handle_connect(prev: EntryConnect) -> Next {
-/// let connect: Address =
-/// route! { prev.pick_or_route((), ErrorParseAddressFailed::default()).unpack() };
-/// connect.to_chain()
-/// }
-///
-/// /// Renders the connected address.
-/// #[renderer]
-/// pub fn render_address(addr: Address) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// write!(render_result, "Connected to \"{}\"", addr).ok();
-/// render_result
-/// }
-///
-/// /// Renders the error message when address parsing fails.
-/// #[renderer]
-/// pub fn render_error_parse_address_failed(_: ErrorParseAddressFailed) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// write!(render_result, "Failed to parse address").ok();
-/// render_result
-/// }
-///
-/// gen_program!();
-///
-/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDConnect);
-/// program.exec_and_exit();
-/// }
-///
-/// // Address conversion
-///
-/// impl TryFrom<String> for Address {
-/// type Error = String;
-///
-/// fn try_from(raw: String) -> Result<Self, Self::Error> {
-/// // Expected format: "192.168.1.1:8080"
-/// let parts: Vec<&str> = raw.split(':').collect();
-/// if parts.len() != 2 {
-/// return Err("Invalid format: expected 'IP:PORT'".to_string());
-/// }
-///
-/// let ip_str = parts[0];
-/// let port_str = parts[1];
-///
-/// // Parse IP address (4 octets separated by dots)
-/// let ip_parts: Vec<&str> = ip_str.split('.').collect();
-/// if ip_parts.len() != 4 {
-/// return Err("Invalid IP address format".to_string());
-/// }
-///
-/// let mut ip = [0u8; 4];
-/// for (i, part) in ip_parts.iter().enumerate() {
-/// ip[i] = part
-/// .parse::<u8>()
-/// .map_err(|_| format!("Invalid IP octet: {part}"))?;
-/// }
-///
-/// // Parse port
-/// let port = port_str
-/// .parse::<u16>()
-/// .map_err(|_| format!("Invalid port: {port_str}"))?;
-///
-/// Ok(Address { ip, port })
-/// }
-/// }
-///
-/// impl From<Address> for String {
-/// fn from(addr: Address) -> String {
-/// format!(
-/// "{}.{}.{}.{}:{}",
-/// addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], addr.port
-/// )
-/// }
-/// }
-///
-/// impl std::fmt::Display for Address {
-/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-/// write!(
-/// f,
-/// "{}.{}.{}.{}:{}",
-/// self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port
-/// )
-/// }
-/// }
-/// ```
-pub mod example_custom_pickable {}
/// Example Dispatch Tree
///
/// > This example will introduce how to use `dispatch_tree`
/// > to optimize your command line lookup efficiency
///
-/// When the number of commands in your project increases, you can use `dispatch_tree` to complete command registration at compile time.
-/// It will generate a trie for quickly finding related commands by prefix.
-///
-/// Therefore, after enabling this feature,
-/// `Program` will no longer store a Dispatcher list internally, and the `with_dispatcher` function will not be compiled.
+/// When the number of commands in your project increases, you can enable
+/// `dispatch_tree` to switch command matching from a linear scan to a
+/// character-level trie.
///
/// Run:
/// ```bash
@@ -1287,30 +963,24 @@ pub mod example_custom_pickable {}
///
/// // --------- IMPORTANT ---------
/// // You have a large number of subcommands
-/// dispatcher!("cmd1", CMD1 => Entry1);
-/// dispatcher!("cmd2.sub1", CMD2Sub1 => Entry2Sub1);
-/// dispatcher!("cmd2.sub2", CMD2Sub2 => Entry2Sub2);
-/// dispatcher!("cmd3.sub1.leaf1", CMD3Sub1Leaf1 => Entry3Sub1Leaf1);
-/// dispatcher!("cmd3.sub1.leaf2", CMD3Sub1Leaf2 => Entry3Sub1Leaf2);
-/// dispatcher!("cmd3.sub2", CMD3Sub2 => Entry3Sub2);
-/// dispatcher!("cmd4.sub1.subsub1.deep", CMD4Deep => Entry4Deep);
-/// dispatcher!("cmd4.sub1.subsub2", CMD4SubSub2 => Entry4SubSub2);
-/// dispatcher!("cmd5", CMD5 => Entry5);
-/// dispatcher!("cmd5.extra", CMD5Extra => Entry5Extra);
-/// dispatcher!("nested.a.b.c", CMDA => EntryA);
-/// dispatcher!("nested.a.b.d", CMDB => EntryB);
-/// dispatcher!("nested.a.e", CMDC => EntryC);
-/// dispatcher!("nested.f", CMDD => EntryD);
+/// dispatcher!("cmd1", Entry1);
+/// dispatcher!("cmd2.sub1", Entry2Sub1);
+/// dispatcher!("cmd2.sub2", Entry2Sub2);
+/// dispatcher!("cmd3.sub1.leaf1", Entry3Sub1Leaf1);
+/// dispatcher!("cmd3.sub1.leaf2", Entry3Sub1Leaf2);
+/// dispatcher!("cmd3.sub2", Entry3Sub2);
+/// dispatcher!("cmd4.sub1.subsub1.deep", Entry4Deep);
+/// dispatcher!("cmd4.sub1.subsub2", Entry4SubSub2);
+/// dispatcher!("cmd5", Entry5);
+/// dispatcher!("cmd5.extra", Entry5Extra);
+/// dispatcher!("nested.a.b.c", EntryA);
+/// dispatcher!("nested.a.b.d", EntryB);
+/// dispatcher!("nested.a.e", EntryC);
+/// dispatcher!("nested.f", EntryD);
/// // --------- IMPORTANT ---------
///
/// fn main() {
/// let program = ThisProgram::new();
-///
-/// // --------- IMPORTANT ---------
-/// // // You no longer need to use `with_dispatcher` anymore;
-/// // // it'll be collected automatically once the `dispatch_tree` feature is enabled
-/// // program.with_dispatcher(...);
-///
/// program.exec_and_exit();
/// }
///
@@ -1354,7 +1024,7 @@ pub mod example_dispatch_tree {}
///
/// features = [
/// "comp",
-/// "parser"
+/// "picker"
/// ]
///
/// [workspace]
@@ -1363,8 +1033,10 @@ pub mod example_dispatch_tree {}
/// Source code (./src/main.rs)
/// ```ignore
/// use mingling::{
-/// macros::suggest_enum, parser::PickableEnum, prelude::*, EnumTag, Grouped, ShellContext,
-/// Suggest,
+/// EnumTag, Grouped, ShellContext, Suggest,
+/// macros::suggest_enum,
+/// picker::{PickerArgResult, SinglePickable},
+/// prelude::*,
/// };
/// use std::io::Write;
///
@@ -1404,9 +1076,7 @@ pub mod example_dispatch_tree {}
/// #[enum_desc("A general-purpose programming language with clean syntax, known for readability")]
/// Python,
///
-/// #[enum_desc(
-/// "An object-oriented scripting language, famous for its concise and elegant syntax"
-/// )]
+/// #[enum_desc("An object-oriented scripting language, famous for its concise and elegant syntax")]
/// Ruby,
///
/// #[default]
@@ -1415,17 +1085,39 @@ pub mod example_dispatch_tree {}
/// }
///
/// // --------- IMPORTANT ---------
-/// // Implement the PickableEnum trait for ProgrammingLanguages,
-/// // so that `Picker` can parse this enum
-/// impl PickableEnum for ProgrammingLanguages {}
+/// // NOTE: Due to the migration from the legacy `parser` to `picker`, the `EnumTag` -> `Picker` path
+/// // is not yet complete, so a manual implementation is used for now.
+/// // Once that path is complete, `#[derive(EnumTag)]` can automatically implement `SinglePickable`,
+/// // replacing this manual implementation.
+/// impl SinglePickable for ProgrammingLanguages {
+/// fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+/// let Some(str) = str else {
+/// return PickerArgResult::NotFound;
+/// };
+/// let lang = match str.to_lowercase().as_str() {
+/// "c" => Self::C,
+/// "c++" | "cpp" => Self::CPlusPlus,
+/// "c#" | "csharp" => Self::Csharp,
+/// "java" => Self::Java,
+/// "javascript" | "js" => Self::JavaScript,
+/// "kotlin" => Self::Kotlin,
+/// "ocaml" => Self::OCaml,
+/// "python" => Self::Python,
+/// "ruby" => Self::Ruby,
+/// "rust" => Self::Rust,
+/// _ => return PickerArgResult::NotFound,
+/// };
+/// PickerArgResult::Parsed(lang)
+/// }
+/// }
/// // --------- IMPORTANT ---------
///
-/// dispatcher!("lang-select", CMDLanguageSelection => EntryLanguageSelection);
+/// dispatcher!("lang-select", EntryLanguageSelection);
///
/// #[chain]
/// fn handle_language_selection(args: EntryLanguageSelection) -> Next {
/// // You can use Picker to directly parse ProgrammingLanguages
-/// let lang: ProgrammingLanguages = args.pick(()).unpack();
+/// let lang: ProgrammingLanguages = args.pick_or_default(&arg![ProgrammingLanguages]).unwrap();
/// lang.into()
/// }
///
@@ -1439,7 +1131,7 @@ pub mod example_dispatch_tree {}
/// }
///
/// #[completion(EntryLanguageSelection)]
-/// fn complete_language_selection(_: &ShellContext) -> Suggest {
+/// fn complete_language_selection(_: ShellContext) -> Suggest {
/// // Use `suggest_enum!` directly to generate enum suggestions
/// suggest_enum!(ProgrammingLanguages)
/// }
@@ -1447,10 +1139,7 @@ pub mod example_dispatch_tree {}
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDCompletion);
-/// program.with_dispatcher(CMDLanguageSelection);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
/// ```
pub mod example_enum_tag {}
@@ -1497,38 +1186,44 @@ pub mod example_enum_tag {}
/// // In Mingling, instead of using ? to propagate errors upward,
/// // errors are treated as branches that continue execution.
///
-/// dispatcher!("hello", CMDHello => EntryHello);
+/// dispatcher!("hello", EntryHello);
///
/// // Define error types
-/// pack!(ErrorNoNameProvided = ());
-/// pack!(ErrorNameTooLong = u16);
-/// pack!(ErrorNameNotAvailable = ());
+/// #[derive(Grouped)]
+/// pub struct ErrorNoNameProvided;
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ErrorNameTooLong(u16);
+///
+/// #[derive(Grouped)]
+/// pub struct ErrorNameNotAvailable;
///
/// // Define success type
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// // Pre-registered names
/// static VEC_REGISTERED_NAMES: &[&str] = &["Alice", "Bob", "Charlie", "David", "Eve"];
///
/// #[chain]
/// fn handle_hello(args: EntryHello) -> Next {
-/// let Some(name) = args.inner.first().cloned() else {
+/// let Some(name) = args.0.first().cloned() else {
/// // If no name is provided, pass ErrorNoNameProvided
-/// return ErrorNoNameProvided::default().to_render();
+/// return ErrorNoNameProvided.to_render();
/// };
///
/// if name.len() > 10 {
/// // If the name is too long, pass ErrorNameTooLong
-/// return ErrorNameTooLong::new(name.len() as u16).to_render();
+/// return ErrorNameTooLong(name.len() as u16).to_render();
/// }
///
/// if VEC_REGISTERED_NAMES.contains(&name.as_str()) {
/// // If the name already exists, pass ErrorNameNotAvailable
-/// return ErrorNameNotAvailable::default().to_render();
+/// return ErrorNameNotAvailable.to_render();
/// }
///
/// // If the name is valid, pass ResultName
-/// ResultName::new(name).to_render()
+/// ResultName(name).to_render()
/// }
///
/// /// Renders a successful greeting with the given name.
@@ -1567,21 +1262,14 @@ pub mod example_enum_tag {}
/// #[renderer]
/// fn render_entry_fallback(err: EntryFallback) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// writeln!(
-/// render_result,
-/// "Command not found: \"{}\"",
-/// err.inner.join(" ")
-/// )
-/// .ok();
+/// writeln!(render_result, "Command not found: \"{}\"", err.0.join(" ")).ok();
/// render_result
/// }
///
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDHello);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
/// ```
pub mod example_error_handling {}
@@ -1630,27 +1318,29 @@ pub mod example_error_handling {}
///
/// // --------- IMPORTANT ---------
/// // Register `ExitCodeSetup` for the program to enable exit codes
-/// program.with_setup(ExitCodeSetup::default());
+/// program.with_setup(ExitCodeSetup);
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDHello);
/// program.exec_and_exit();
/// }
///
-/// dispatcher!("hello", CMDHello => EntryHello);
+/// dispatcher!("hello", EntryHello);
+///
+/// #[derive(Grouped)]
+/// pub struct ErrorNoNameProvided;
///
-/// pack!(ErrorNoNameProvided = ());
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// #[chain]
/// fn handle_hello(args: EntryHello) -> Next {
-/// let Some(name) = args.inner.first().cloned() else {
+/// let Some(name) = args.0.first().cloned() else {
/// // If no name is provided, pass ErrorNoNameProvided
-/// return ErrorNoNameProvided::default().to_render();
+/// return ErrorNoNameProvided.to_render();
/// };
///
/// // If the name is valid, pass ResultName
-/// ResultName::new(name).to_render()
+/// ResultName(name).to_render()
/// }
///
/// /// Renders a successful greeting with the given name.
@@ -1719,7 +1409,7 @@ pub mod example_exitcode {}
/// use mingling::{macros::help, prelude::*, setup::BasicProgramSetup};
/// use std::io::Write;
///
-/// dispatcher!("greet", CMDGreet => EntryGreet);
+/// dispatcher!("greet", EntryGreet);
///
/// // Define help _________ When `program.user_context.help` is `true`
/// // / the command will not enter `#[chain]` / `#[renderer]`
@@ -1739,8 +1429,6 @@ pub mod example_exitcode {}
/// program.with_setup(BasicProgramSetup);
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDGreet);
-///
/// program.exec_and_exit();
/// }
///
@@ -1790,7 +1478,7 @@ pub mod example_help {}
/// };
/// use std::io::Write;
///
-/// dispatcher!("greet", CMDGreet => EntryGreet);
+/// dispatcher!("greet", EntryGreet);
///
/// fn main() {
/// let mut program = ThisProgram::new();
@@ -1814,16 +1502,16 @@ pub mod example_help {}
/// );
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDGreet);
/// program.exec_and_exit();
/// }
///
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// #[chain]
/// fn handle_greet(args: EntryGreet) -> Next {
/// let name: ResultName = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string())
@@ -1865,20 +1553,13 @@ pub mod example_hook {}
/// ```ignore
/// use mingling::prelude::*;
///
-/// // When using implicit syntax, the entry and dispatcher names will be automatically derived
-/// dispatcher!("remote.add" /*, CMDRemoteAdd => EntryRemoteAdd */);
-/// dispatcher!("remote.remove", CMDRemoteRemove => EntryRemoteRemove);
+/// // When using implicit syntax, the entry name will be automatically derived
+/// // from the command name (the dispatcher struct is generated internally)
+/// dispatcher!("remote.add" /* => EntryRemoteAdd */);
+/// dispatcher!("remote.remove", EntryRemoteRemove);
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// // --------- IMPORTANT ---------
-/// program.with_dispatcher(CMDRemoteAdd);
-/// // ^^^^^^^^^^^^\_ CMDRemoteAdd is implicitly created
-/// // --------- IMPORTANT ---------
-///
-/// program.with_dispatcher(CMDRemoteRemove);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -1951,10 +1632,11 @@ pub mod example_implicit_dispatcher {}
/// ResLargeData { data }
/// }
///
-/// dispatcher!("show", CMDShow => EntryShow);
-/// dispatcher!("none", CMDNone => EntryNone);
+/// dispatcher!("show", EntryShow);
+/// dispatcher!("none", EntryNone);
///
-/// pack!(ResultShow = BTreeMap<Key, Value>);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultShow(BTreeMap<Key, Value>);
///
/// fn main() {
/// let mut program = ThisProgram::new();
@@ -1966,7 +1648,6 @@ pub mod example_implicit_dispatcher {}
/// program.with_resource(ResLargeData::lazy_init(init_res_large_data));
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDShow).with_dispatcher(CMDNone);
/// program.exec_and_exit();
/// }
///
@@ -2042,20 +1723,16 @@ pub mod example_lazy_resources {}
/// use std::io::Write;
///
/// // Define the `greet` subcommand
-/// dispatcher!("greet", CMDGreet => EntryGreet);
+/// dispatcher!("greet", EntryGreet);
///
/// // Define the `desc` subcommand, which queries metadata bound to EntryGreet
-/// dispatcher!("desc", CMDDescription => EntryDescription);
+/// dispatcher!("desc", EntryDescription);
///
/// // Define the `nodoc` subcommand, which queries metadata for an entry that has none
-/// dispatcher!("nodoc", CMDNoDescription => EntryNoDescription);
+/// dispatcher!("nodoc", EntryNoDescription);
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDGreet);
-/// program.with_dispatcher(CMDDescription);
-/// program.with_dispatcher(CMDNoDescription);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// /// The metadata type attached to an entry.
@@ -2077,14 +1754,17 @@ pub mod example_lazy_resources {}
/// }
/// // --------- IMPORTANT ---------
///
-/// pack!(ResultName = String);
-/// pack!(DescResult = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct DescResult(String);
///
/// /// Chain for `greet` — reads the name and produces a `ResultName`.
/// #[chain]
/// fn handle_greet(args: EntryGreet) -> Next {
/// let name: ResultName = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string())
@@ -2102,7 +1782,7 @@ pub mod example_lazy_resources {}
/// None => "EntryGreet has no description".to_string(),
/// };
/// // --------- IMPORTANT ---------
-/// DescResult::new(msg).to_render()
+/// DescResult(msg).to_render()
/// }
///
/// /// Chain for `nodoc` — asks for metadata on an entry that has none.
@@ -2115,7 +1795,7 @@ pub mod example_lazy_resources {}
/// None => "EntryDescription has no description".to_string(),
/// };
/// // --------- IMPORTANT ---------
-/// DescResult::new(msg).to_render()
+/// DescResult(msg).to_render()
/// }
///
/// /// Renders the greeting message with the provided name.
@@ -2200,7 +1880,8 @@ pub mod example_metadata {}
/// // you can use this syntax to create an alias simultaneously
/// // --------- IMPORTANT ---------
///
-/// pack!(ParsedNumber = i32);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ParsedNumber(i32);
///
/// /// Parse the first argument as an `i32`
/// ///
@@ -2208,9 +1889,9 @@ pub mod example_metadata {}
/// /// On failure, routes to `render_parse_error` via the registered outside type.
/// #[chain]
/// fn parse_number(args: EntryParse) -> Next {
-/// let input = args.inner.first().cloned().unwrap_or_default();
+/// let input = args.0.first().cloned().unwrap_or_default();
/// match input.parse::<i32>() {
-/// Ok(num) => ParsedNumber::new(num).to_chain(),
+/// Ok(num) => ParsedNumber(num).to_chain(),
/// Err(e) => e.to_chain(),
/// }
/// }
@@ -2247,190 +1928,12 @@ pub mod example_metadata {}
/// }
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDParse);
-/// program.with_dispatcher(CMDError);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
/// ```
pub mod example_outside_type {}
-/// Example `pack_err!`
-///
-/// > This example demonstrates how to use the `pack_err!` macro to define error types
-/// > with automatic `name` field (set to snake_case at compile time) and optional `info` field.
-/// > Also demonstrates `--json` serialization when `structural_renderer` is enabled.
-///
-/// Run:
-/// ```bash
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find Cargo.toml
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find src
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural --json
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural Cargo.toml --json
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural src --json
-/// ```
-///
-/// Output:
-/// ```plaintext
-/// Search path not provided
-/// Not a directory: Cargo.toml
-/// Found directory: src
-/// {"name":"error_not_found"}
-/// {"name":"error_not_dir","info":"Cargo.toml"}
-/// {"inner":"src"}
-/// {"name":"error_not_found_structural"}
-/// {"name":"error_not_dir_structural","info":"Cargo.toml"}
-/// ```
-///
-/// Source code (./Cargo.toml)
-/// ```toml
-/// [package]
-/// name = "example-pack-err"
-/// version = "0.1.0"
-/// edition = "2024"
-///
-/// [dependencies]
-/// serde = { version = "1.0.228", features = ["derive"] }
-///
-/// [dependencies.mingling]
-/// path = "../../mingling"
-/// features = [
-/// "structural_renderer",
-/// "extras",
-/// ]
-///
-/// [workspace]
-/// ```
-///
-/// Source code (./src/main.rs)
-/// ```ignore
-/// use mingling::prelude::*;
-/// use mingling::setup::StructuralRendererSetup;
-/// use std::io::Write;
-/// use std::path::PathBuf;
-///
-/// dispatcher!("find", CMDFind => EntryFind);
-/// dispatcher!("find-structural", CMDFindStructural => EntryFindStructural);
-///
-/// // --------- IMPORTANT ---------
-/// // `pack_err!` is a convenient macro for defining error types.
-/// //
-/// // Simple form: pack_err!(ErrorNotFound);
-/// // Typed form: pack_err!(ErrorNotDir = PathBuf);
-/// //
-/// // The simple form generates a struct with `name: String` and `impl Default`.
-/// // name = "error_not_found" (automatically snake_cased at compile time)
-/// //
-/// // The typed form additionally generates `pub fn new(info)`.
-/// // name = "error_not_dir"
-/// //
-/// // When `structural_renderer` is enabled, the struct also gets
-/// // `#[derive(serde::Serialize)]` for --json / --yaml output.
-/// // --------- IMPORTANT ---------
-///
-/// // Simple form — name = "error_not_found"
-/// pack_err!(ErrorNotFound);
-///
-/// // Typed form — name = "error_not_dir"
-/// pack_err!(ErrorNotDir = PathBuf);
-///
-/// // Simple form — with StructuralData support for --json / --yaml
-/// pack_err_structural!(ErrorNotFoundStructural);
-///
-/// // Typed form — with StructuralData support for --json / --yaml
-/// pack_err_structural!(ErrorNotDirStructural = PathBuf);
-///
-/// // Success type with StructuralData support
-/// pack_structural!(ResultPath = PathBuf);
-///
-/// #[chain]
-/// fn handle_find(args: EntryFind) -> Next {
-/// let Some(path_str) = args.inner.first().cloned() else {
-/// // No path provided → use the simple error form (Default)
-/// return ErrorNotFound::default().to_render();
-/// };
-///
-/// let path = PathBuf::from(&path_str);
-/// if path.is_dir() {
-/// // Is a directory → success
-/// ResultPath::new(path).to_render()
-/// } else {
-/// // Not a directory (or doesn't exist) → use the typed error form
-/// ErrorNotDir::new(path).to_render()
-/// }
-/// }
-///
-/// #[chain]
-/// fn handle_find_structural(args: EntryFindStructural) -> Next {
-/// let Some(path_str) = args.inner.first().cloned() else {
-/// // No path provided → use the simple error form (Default)
-/// return ErrorNotFoundStructural::default().to_render();
-/// };
-///
-/// let path = PathBuf::from(&path_str);
-/// if path.is_dir() {
-/// // Is a directory → success
-/// ResultPath::new(path).to_render()
-/// } else {
-/// // Not a directory (or doesn't exist) → use the typed error form
-/// ErrorNotDirStructural::new(path).to_render()
-/// }
-/// }
-///
-/// /// Renders the successful result with the found directory path.
-/// #[renderer]
-/// fn render_result_path(path: ResultPath) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Found directory: {}", path.display()).ok();
-/// render_result
-/// }
-///
-/// /// Renders the error when no search path is provided.
-/// #[renderer]
-/// fn render_error_not_found(_: ErrorNotFound) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Search path not provided").ok();
-/// render_result
-/// }
-///
-/// /// Renders the error when the given path is not a directory.
-/// #[renderer]
-/// fn render_error_not_dir(err: ErrorNotDir) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
-/// render_result
-/// }
-///
-/// /// Renders the structural error when no search path is provided.
-/// #[renderer]
-/// fn render_error_not_found_structural(_: ErrorNotFoundStructural) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Search path not provided").ok();
-/// render_result
-/// }
-///
-/// /// Renders the structural error when the given path is not a directory.
-/// #[renderer]
-/// fn render_error_not_dir_structural(err: ErrorNotDirStructural) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
-/// render_result
-/// }
-///
-/// gen_program!();
-///
-/// fn main() {
-/// let mut program = ThisProgram::new();
-/// // Add StructuralRendererSetup to support --json / --yaml flags
-/// program.with_setup(StructuralRendererSetup);
-/// program.with_dispatcher(CMDFind);
-/// program.with_dispatcher(CMDFindStructural);
-/// let _ = program.exec();
-/// }
-/// ```
-pub mod example_pack_err {}
/// Example Panic Unwind
///
/// > This example introduces how to catch Panic in the Mingling program loop
@@ -2457,7 +1960,7 @@ pub mod example_pack_err {}
///
/// [dependencies.mingling]
/// path = "../../mingling"
-/// features = ["parser"]
+/// features = ["picker"]
///
/// # Enable panic unwinding in release builds
/// [profile.release]
@@ -2476,12 +1979,13 @@ pub mod example_pack_err {}
/// use mingling::{hook::ProgramHook, prelude::*};
/// use std::io::Write;
///
-/// dispatcher!("panic", CMDPanic => EntryPanic);
-/// pack!(NotPanic = ());
+/// dispatcher!("panic", EntryPanic);
+///
+/// #[derive(Grouped)]
+/// pub struct NotPanic;
///
/// fn main() {
/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDPanic);
///
/// // --------- IMPORTANT ---------
/// // Enable silence_panic to suppress automatic Panic output
@@ -2499,13 +2003,13 @@ pub mod example_pack_err {}
///
/// #[chain]
/// fn handle_panic(prev: EntryPanic) -> Next {
-/// let panic_info = prev.pick::<Option<String>>(()).unpack();
+/// let panic_info = prev.pick_or_default(&arg![Option<String>]).unwrap();
/// match panic_info {
/// Some(s) => {
/// // Panic happens here, will be caught
/// panic!("{}", s)
/// }
-/// None => NotPanic::default().into(),
+/// None => NotPanic.into(),
/// }
/// }
///
@@ -2553,17 +2057,6 @@ pub mod example_panic_unwind {}
/// "pathf",
/// ]
///
-/// [build-dependencies.mingling]
-/// path = "../../mingling"
-///
-/// features = [
-/// # Enable `pathf` features
-/// "pathf",
-///
-/// # Enable the `build` feature for build-time support
-/// "build",
-/// ]
-///
/// [workspace]
/// ```
///
@@ -2572,12 +2065,9 @@ pub mod example_panic_unwind {}
/// mod sub;
///
/// use mingling::macros::gen_program;
-/// use crate::sub::CMDGreet;
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDGreet);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -2601,7 +2091,7 @@ pub mod example_pathfinder {}
///
/// [dependencies.mingling]
/// path = "../../mingling"
-/// features = ["repl", "parser", "extras"]
+/// features = ["repl", "picker", "extras"]
///
/// [dependencies]
/// just_fmt = "0.1.2"
@@ -2641,12 +2131,6 @@ pub mod example_pathfinder {}
/// // Resource
/// program.with_resource(ResCurrentDir::default());
///
-/// // Dispatchers
-/// program.with_dispatcher(CMDCd);
-/// program.with_dispatcher(CMDLs);
-/// program.with_dispatcher(CMDExit);
-/// program.with_dispatcher(CMDClear);
-///
/// // Setups
/// // Enable basic std::io::stdin().read_line(&mut input)
/// program.with_setup(BasicREPLReadlineSetup);
@@ -2680,25 +2164,28 @@ pub mod example_pathfinder {}
/// }
///
/// // Create error route
-/// pack!(ErrorDirectoryNotExist = PathBuf);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ErrorDirectoryNotExist(PathBuf);
///
/// // Create commands: cd ls exit
-/// dispatcher!("cd", CMDCd => EntryCd);
-/// dispatcher!("ls", CMDLs => EntryLs);
-/// dispatcher!("exit", CMDExit => EntryExit);
-/// dispatcher!("clear", CMDClear => EntryClear);
+/// dispatcher!("cd", EntryCd);
+/// dispatcher!("ls", EntryLs);
+/// dispatcher!("exit", EntryExit);
+/// dispatcher!("clear", EntryClear);
///
/// // Define data needed for the cd command's execution phase
-/// pack!(StateChangeDirectory = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateChangeDirectory(String);
///
/// // Define data needed for the ls command's rendering phase
-/// pack!(ResultList = Vec<String>);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultList(Vec<String>);
///
/// // Parse cd command arguments
/// #[chain]
/// fn parse_cd_args(prev: EntryCd) -> Next {
-/// let join = prev.pick(()).unpack();
-/// StateChangeDirectory::new(join).into()
+/// let join = prev.pick_or_default(&arg![String]).unwrap();
+/// StateChangeDirectory(join).into()
/// }
///
/// // Execute directory change
@@ -2706,12 +2193,12 @@ pub mod example_pathfinder {}
/// fn handle_cd(prev: StateChangeDirectory, current_dir: &mut ResCurrentDir) -> Next {
/// use just_fmt::fmt_path::fmt_path;
///
-/// let join = prev.inner;
+/// let join = prev.0;
/// let new_dir = 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();
+/// return ErrorDirectoryNotExist(new_dir).to_render();
/// }
///
/// current_dir.dir = new_dir;
@@ -2736,14 +2223,14 @@ pub mod example_pathfinder {}
/// .collect();
///
/// // Render ResultList
-/// ResultList::new(entries).to_render()
+/// ResultList(entries).to_render()
/// }
///
/// /// Render ResultList data
/// #[renderer]
/// fn render_list(list: ResultList) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// for item in list.inner {
+/// for item in list.0 {
/// writeln!(render_result, "{}", item).ok();
/// }
/// render_result
@@ -2770,12 +2257,7 @@ pub mod example_pathfinder {}
/// #[renderer]
/// fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// writeln!(
-/// render_result,
-/// "Directory not found: {}",
-/// err.inner.display()
-/// )
-/// .ok();
+/// writeln!(render_result, "Directory not found: {}", err.0.display()).ok();
/// render_result
/// }
///
@@ -2816,7 +2298,7 @@ pub mod example_repl_basic {}
///
/// [dependencies.mingling]
/// path = "../../mingling"
-/// features = ["parser"]
+/// features = ["picker"]
///
/// [workspace]
/// ```
@@ -2846,14 +2328,11 @@ pub mod example_repl_basic {}
/// });
/// // --------- IMPORTANT ---------
///
-/// program
-/// .with_dispatcher(CMDCurrent)
-/// .with_dispatcher(CMDModifyCurrent);
/// program.exec_and_exit();
/// }
///
-/// dispatcher!("current", CMDCurrent => EntryCurrent);
-/// dispatcher!("modify-current", CMDModifyCurrent => EntryModifyCurrent);
+/// dispatcher!("current", EntryCurrent);
+/// dispatcher!("modify-current", EntryModifyCurrent);
///
/// // Define chain for modifying current directory _________________ Injected muttable resource
/// // /
@@ -2861,7 +2340,7 @@ pub mod example_repl_basic {}
/// fn render_modify_current(args: EntryModifyCurrent, current_dir: &mut ResCurrentDir) -> Next {
/// current_dir.current_dir = current_dir
/// .current_dir
-/// .join(args.pick::<String>(()).unpack());
+/// .join(args.pick_or_default(&arg![String]).unwrap());
/// EntryCurrent::default().into()
/// }
///
@@ -2885,7 +2364,8 @@ pub mod example_repl_basic {}
pub mod example_resources {}
/// Example Setup
///
-/// > This example demonstrates how to build a custom Setup for modular management of project components
+/// > This example demonstrates how to build a custom Setup that encapsulates a
+/// > group of related resources and registers them with `with_resource`.
///
/// Source code (./Cargo.toml)
/// ```toml
@@ -2903,6 +2383,25 @@ pub mod example_resources {}
/// Source code (./src/main.rs)
/// ```ignore
/// use mingling::{Program, macros::program_setup, prelude::*};
+/// use std::io::Write;
+///
+/// // A group of related resources — here, the demo app's identity.
+/// // Resource types are plain structs: any `Default + Clone + Send + Sync` type
+/// // can be used as a resource, and it is identified by its type.
+/// #[derive(Default, Clone)]
+/// struct ResAppName {
+/// name: String,
+/// }
+///
+/// #[derive(Default, Clone)]
+/// struct ResAppVersion {
+/// version: String,
+/// }
+///
+/// #[derive(Default, Clone)]
+/// struct ResGreetingPrefix {
+/// prefix: String,
+/// }
///
/// fn main() {
/// let mut program = ThisProgram::new();
@@ -2917,22 +2416,46 @@ pub mod example_resources {}
///
/// // --------- IMPORTANT ---------
/// // Define `CustomSetup` (inferred from `custom_setup`)
-/// // Package part of the program construction logic into this type for modular management
+/// // Package part of the program construction logic into this type for modular
+/// // management — e.g. register a group of related resources here.
/// #[program_setup]
/// fn custom_setup(program: &mut Program<ThisProgram>) {
-/// program.with_dispatcher(CMD1);
-/// program.with_dispatcher(CMD2);
-/// program.with_dispatcher(CMD3);
-/// program.with_dispatcher(CMD4);
-/// program.with_dispatcher(CMD5);
+/// program.with_resource(ResAppName {
+/// name: "mingling".to_string(),
+/// });
+/// program.with_resource(ResAppVersion {
+/// version: "0.5.0".to_string(),
+/// });
+/// program.with_resource(ResGreetingPrefix {
+/// prefix: "Hello".to_string(),
+/// });
/// }
/// // --------- IMPORTANT ---------
///
-/// dispatcher!("1", CMD1 => Entry1);
-/// dispatcher!("2", CMD2 => Entry2);
-/// dispatcher!("3", CMD3 => Entry3);
-/// dispatcher!("4", CMD4 => Entry4);
-/// dispatcher!("5", CMD5 => Entry5);
+/// dispatcher!("greet", EntryGreet);
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultGreeting(String);
+///
+/// /// Chain: reads the `ResAppName` and `ResAppVersion` resources.
+/// #[chain]
+/// fn handle_greet(args: EntryGreet, app: &ResAppName, version: &ResAppVersion) -> Next {
+/// let who = args
+/// .0
+/// .first()
+/// .cloned()
+/// .unwrap_or_else(|| "World".to_string());
+/// let greeting: ResultGreeting = format!("{} from {} v{}", who, app.name, version.version).into();
+/// greeting.into()
+/// }
+///
+/// /// Renderer: injects the `ResGreetingPrefix` resource to decorate the output.
+/// #[renderer]
+/// fn render_greet(greeting: ResultGreeting, prefix: &ResGreetingPrefix) -> RenderResult {
+/// let mut render_result = RenderResult::new();
+/// writeln!(render_result, "{}, {}!", prefix.prefix, *greeting).ok();
+/// render_result
+/// }
///
/// gen_program!();
/// ```
@@ -2971,7 +2494,7 @@ pub mod example_setup {}
/// features = [
/// "structural_renderer",
/// "yaml_serde_fmt",
-/// "parser",
+/// "picker",
/// ]
///
/// [workspace]
@@ -2979,23 +2502,23 @@ pub mod example_setup {}
///
/// Source code (./src/main.rs)
/// ```ignore
-/// use mingling::prelude::*;
-/// use mingling::{parser::Picker, setup::StructuralRendererSetup, Grouped, StructuralData};
+/// use mingling::setup::picker::StructuralRendererSetup;
+/// use mingling::{Grouped, StructuralData, prelude::*};
/// use serde::Serialize;
/// use std::io::Write;
///
-/// dispatcher!("render", CMDRender => EntryRender);
+/// dispatcher!("render", EntryRender);
///
/// fn main() {
/// let mut program = ThisProgram::new();
/// // Add `StructuralRendererSetup` to receive user input `--json` `--yaml` parameters
/// program.with_setup(StructuralRendererSetup);
-/// program.with_dispatcher(CMDRender);
/// let _ = program.exec();
/// }
///
/// // --------- IMPORTANT ---------
-/// // For beautiful output structure, do not use `pack!` to wrap the types that need to be output.
+/// // For beautiful output structure, do not wrap the types that need to be output
+/// // in a newtype; instead, use a named struct.
/// // Instead, manually implement
/// // ____________________________________ Mark as structured data so it can be rendered
/// // / ____________________ Implement serde::Serialize
@@ -3011,17 +2534,17 @@ pub mod example_setup {}
/// }
/// // This will output: {"member_name":"name","member_age":32} structure
///
-/// // If using pack!(Info = (String, i32));
+/// // If wrapping with a tuple newtype (e.g. `#[derive(Grouped, Wrap)] pub struct Info((String, i32));`)
/// // Output: {"inner":["name", 32]}
///
/// // --------- IMPORTANT ---------
///
/// #[chain]
/// fn parse_render(prev: EntryRender) -> Next {
-/// let (name, age) = Picker::new(prev.inner)
-/// .pick::<String>(())
-/// .pick::<i32>(())
-/// .unpack();
+/// let (name, age) = prev
+/// .pick_or_default(&arg![String])
+/// .pick_or_default(&arg![i32])
+/// .unwrap();
/// Info { name, age }.to_render()
/// }
///
@@ -3089,60 +2612,66 @@ pub mod example_structural_renderer {}
/// let hello_with_valid_name = handle_hello(entry!("Peter")).into();
/// assert_render_result!(hello_with_valid_name);
/// let result_name = unpack_chain_process!(hello_with_valid_name, ResultName);
-/// assert_eq!(result_name.inner, "Peter");
+/// assert_eq!(result_name.0, "Peter");
/// }
///
/// #[test]
/// fn test_render_result_name() {
-/// let r = render_result_name(ResultName::new("Peter".into()));
+/// let r = render_result_name(ResultName("Peter".into()));
/// assert_eq!(r.to_string().as_str(), "Hello, Peter!")
/// }
///
/// #[test]
/// fn test_render_error_no_name_provided() {
-/// let r = render_error_no_name_provided(ErrorNoNameProvided::default());
+/// let r = render_error_no_name_provided(ErrorNoNameProvided);
/// assert_eq!(r.to_string().as_str(), "No name provided")
/// }
///
/// #[test]
/// fn test_render_error_name_not_available() {
-/// let r = render_error_name_not_available(ErrorNameNotAvailable::default());
+/// let r = render_error_name_not_available(ErrorNameNotAvailable);
/// assert_eq!(r.to_string().as_str(), "Name not available")
/// }
///
/// #[test]
/// fn test_render_error_name_too_long() {
-/// let r = render_error_name_too_long(ErrorNameTooLong::new(17));
+/// let r = render_error_name_too_long(ErrorNameTooLong(17));
/// assert_eq!(r.to_string().as_str(), "Name too long: 17 > 10")
/// }
/// // --------- IMPORTANT ---------
/// }
///
-/// dispatcher!("hello", CMDHello => EntryHello);
+/// dispatcher!("hello", EntryHello);
+///
+/// #[derive(Grouped)]
+/// pub struct ErrorNoNameProvided;
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ErrorNameTooLong(u16);
///
-/// pack!(ErrorNoNameProvided = ());
-/// pack!(ErrorNameTooLong = u16);
-/// pack!(ErrorNameNotAvailable = ());
+/// #[derive(Grouped)]
+/// pub struct ErrorNameNotAvailable;
///
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// static VEC_REGISTERED_NAMES: &[&str] = &["Alice", "Bob", "Charlie", "David", "Eve"];
///
/// #[chain]
/// fn handle_hello(args: EntryHello) -> Next {
-/// let Some(name) = args.inner.first().cloned() else {
-/// return ErrorNoNameProvided::default().to_render();
+/// let Some(name) = args.0.first().cloned() else {
+/// return ErrorNoNameProvided.to_render();
/// };
///
/// if name.len() > 10 {
-/// return ErrorNameTooLong::new(name.len() as u16).to_render();
+/// return ErrorNameTooLong(name.len() as u16).to_render();
/// }
///
/// if VEC_REGISTERED_NAMES.contains(&name.as_str()) {
-/// return ErrorNameNotAvailable::default().to_render();
+/// return ErrorNameNotAvailable.to_render();
/// }
///
-/// ResultName::new(name).to_render()
+/// ResultName(name).to_render()
/// }
///
/// /// Renders a successful greeting with the given name.
@@ -3181,21 +2710,14 @@ pub mod example_structural_renderer {}
/// #[renderer]
/// fn render_entry_fallback(err: EntryFallback) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// writeln!(
-/// render_result,
-/// "Command not found: \"{}\"",
-/// err.inner.join(" ")
-/// )
-/// .ok();
+/// writeln!(render_result, "Command not found: \"{}\"", err.0.join(" ")).ok();
/// render_result
/// }
///
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDHello);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
/// ```
pub mod example_unit_test {}