Declare a Dispatcher

Use the dispatcher! macro to declare commands and register them

Mingling's pipeline starts with a Dispatcher. Its job is simple: **match the user's input command, wrap the arguments into an Entry type**. ## The `dispatcher!` Macro The `dispatcher!` macro generates two types at once: | Generated type | Purpose | | -------------- | -------------------------------------------------------------- | | `CMDType` | The dispatcher itself, needs to be registered to Program | | `EntryType` | The entry type, wraps `Vec`, serves as input for Chain | The syntax is a fixed three-part pattern: ```rust dispatcher!("command path", DispatcherType => EntryType); ``` Here's a concrete example: ```rust dispatcher!("greet", CMDGreet => EntryGreet); ``` > [!NOTE] > The command name (`"greet"`) is auto-converted to kebab-case. Even if you write `"GreetUser"`, matching will use `greet-user`. ## Registering with Program Once you have a dispatcher, you need to tell Program about it: ```rust @@@ dispatcher!("greet", CMDGreet => EntryGreet); @@@ fn main() { @@@ let mut program = ThisProgram::new(); // Register the dispatcher program.with_dispatcher(CMDGreet); @@@ } @@@ gen_program!(); ``` > [!TIP] > If you have many commands, use `with_dispatchers` to register multiple at once: `program.with_dispatchers((CMDGreet, CMDAdd, CMDRemoteRm))`. ## Multi-level Commands If your program has a hierarchy — e.g., `remote add`, `remote rm` — just separate the command name with dots: ```rust dispatcher!("remote.add", CMDRemoteAdd => EntryRemoteAdd); dispatcher!("remote.rm", CMDRemoteRm => EntryRemoteRm); ``` When the user types `remote add` in the terminal, Mingling matches `remote` and `add` as two levels in sequence. ## The Entry Type `EntryGreet` You might be curious about what's inside `EntryGreet`. It's essentially a struct wrapping `Vec`: ```rust // Illustration of code generated by the dispatcher! macro pub struct EntryGreet { pub inner: Vec, } ``` When the user types `greet Alice Bob` on the command line, `EntryGreet.inner` becomes `vec!["Alice", "Bob"]`. > [!IMPORTANT] > Entry's `inner` only contains **the remaining args after matching**. > > Take `remote add origin` as an example: `remote` and `add` are used for matching the command path, only `origin` goes into `EntryRemoteAdd.inner`. ## Advanced: Implicit Declaration The above is the standard syntax. If you enable the `extra_macros` feature, you can be more concise: ```rust // Features: ["extra_macros"] // Omit CMDType and EntryType, names are auto-derived dispatcher!("greet"); // dispatcher!("greet", CMDGreet => EntryGreet); ``` This syntax auto-generates `CMDGreet` and `EntryGreet`, with the same effect as the explicit declaration. But for the tutorial, we'll stick with explicit syntax — it's clearer and doesn't require extra features. See [Feature List](pages/other/features) for details. ## Next Step Next we'll write a Chain to receive the Entry and handle the actual business logic.

Written by @Weicao-CatilGrass