aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/5-multiple-commands.md
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-30 18:05:05 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-30 18:05:05 +0800
commit13408e79b940e9a33ca593ed30d1b20c54e01234 (patch)
tree282549991a3f31791401ca2f3255b9318679d2e9 /docs/pages/5-multiple-commands.md
parent29867ab5c0b40378a33318d989c809f90fc7d3aa (diff)
feat(docs): add Chinese and English documentation for Mingling tutorials
Add comprehensive documentation covering Declare a Dispatcher, Declare a Chain, Rendering Results, Multi-Command Program, Argument Parsing with Picker and Clap, Program Setup, Error Handling, Help Info, Resource System, Exit Code Control, Hook System, Testing, Completion, Structural Rendering, and Core Concepts
Diffstat (limited to 'docs/pages/5-multiple-commands.md')
-rw-r--r--docs/pages/5-multiple-commands.md109
1 files changed, 109 insertions, 0 deletions
diff --git a/docs/pages/5-multiple-commands.md b/docs/pages/5-multiple-commands.md
new file mode 100644
index 0000000..9ad7ef4
--- /dev/null
+++ b/docs/pages/5-multiple-commands.md
@@ -0,0 +1,109 @@
+<h1 align="center">Multi-Command Program</h1>
+<p align="center">
+ Adding multiple commands to a single program
+</p>
+
+Real-world CLIs rarely have just one command. Let's extend our previous greet program by adding a second command, and see what a multi-command program looks like.
+
+## Adding a Second Command
+
+Work in the same project:
+
+```rust
+// Declare two commands
+dispatcher!("greet", CMDGreet => EntryGreet);
+dispatcher!("add", CMDAdd => EntryAdd);
+
+pack!(ResultGreeting = String);
+pack!(ResultSum = i32);
+
+#[chain]
+fn handle_greet(args: EntryGreet) -> Next {
+ let name = args.inner.first().cloned().unwrap_or_else(|| "World".to_string());
+ ResultGreeting::new(name)
+}
+
+#[chain]
+fn handle_add(args: EntryAdd) -> Next {
+ let sum: i32 = args.inner.iter().filter_map(|s| s.parse::<i32>().ok()).sum();
+ ResultSum::new(sum)
+}
+
+#[renderer]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
+}
+
+#[renderer]
+fn render_sum(result: ResultSum) {
+ r_println!("Sum: {}", *result);
+}
+
+fn main() {
+ let mut program = ThisProgram::new();
+ program.with_dispatchers((CMDGreet, CMDAdd));
+ program.exec_and_exit();
+}
+
+gen_program!();
+```
+
+Both commands share the same pipeline model, but each has its own path:
+
+```text
+> my-cli greet Alice
+Hello, Alice!
+> my-cli add 1 2 3
+Sum: 6
+```
+
+## Registering Multiple Dispatchers
+
+Notice `with_dispatchers`? When you need to register multiple dispatchers, just pass them as a tuple:
+
+```rust
+@@@dispatcher!("greet", CMDGreet => EntryGreet);
+@@@dispatcher!("add", CMDAdd => EntryAdd);
+@@@pack!(ResultGreeting = String);
+@@@pack!(ResultSum = i32);
+@@@#[chain] fn handle_greet(_args: EntryGreet) -> Next { ResultGreeting::new("ok".into()) }
+@@@#[renderer] fn render_greet(_greeting: ResultGreeting) { r_println!("hi"); }
+@@@#[chain] fn handle_add(_args: EntryAdd) -> Next { ResultSum::new(0) }
+@@@#[renderer] fn render_sum(_sum: ResultSum) { r_println!("sum"); }
+fn main() {
+ let mut program = ThisProgram::new();
+ program.with_dispatchers((CMDGreet, CMDAdd));
+ program.exec_and_exit();
+}
+```
+
+This is equivalent to registering them one by one, same effect.
+
+> [!TIP]
+> The tuple supports up to 7 dispatchers. For more than 7, chain `with_dispatcher` calls instead.
+
+## Subcommands
+
+Multi-level commands work the same way—each dot-separated level is just part of the name:
+
+```rust
+dispatcher!("remote.add", CMDRemoteAdd => EntryRemoteAdd);
+dispatcher!("remote.rm", CMDRemoteRm => EntryRemoteRm);
+```
+
+Each subcommand's Entry, Chain, and Renderer are completely independent and don't interfere.
+
+## Type Independence
+
+Notice we used two different `pack!` macros:
+
+- `pack!(ResultGreeting = String)`
+- `pack!(ResultSum = i32)`
+
+They are independent types, and `gen_program!()` assigns them different enum variants.
+
+The dispatcher will never route `ResultGreeting` data to `render_sum` — **type safety is guaranteed from the naming stage**.
+
+<p align="center" style="font-size: 0.85em; color: gray;">
+ Written by @Weicao-CatilGrass
+</p>