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