aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/2-define-a-dispatcher.md
blob: 5aafb19928768a6daaa3830e33c0ebd901c9a00c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<h1 align="center">Declare a Dispatcher</h1>
<p align="center">
    Use the <code>dispatcher!</code> macro to declare commands and register them
</p>

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<String>`, serves as input for Chain |

The syntax is a fixed three-part pattern:

```rust
dispatcher!("command path", EntryType);
```
 
Here's a concrete example:

```rust
dispatcher!("greet", EntryGreet);
```
 
> [!NOTE]
> The command name (`"greet"`) is auto-converted to kebab-case. Even if you write `"GreetUser"`, matching will use `greet-user`.

## 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", EntryRemoteAdd);
dispatcher!("remote.rm",  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<String>`:

```rust
// Illustration of code generated by the dispatcher! macro
pub struct EntryGreet(pub Vec<String>);
```
 
When the user types `greet Alice Bob` on the command line, `EntryGreet`'s `.0` becomes `vec!["Alice", "Bob"]`.

> [!IMPORTANT]
> Entry's `.0` 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.0`.

## Advanced: Implicit Declaration

The above is the standard syntax. If you enable the `extras` feature, you can be more concise:

```rust
// Features: ["extras"]
// Omit CMDType and EntryType, names are auto-derived
   dispatcher!("greet");
// dispatcher!("greet", 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.

<p align="center" style="font-size: 0.85em; color: gray;">
    Written by @Weicao-CatilGrass
</p>