From 13408e79b940e9a33ca593ed30d1b20c54e01234 Mon Sep 17 00:00:00 2001
From: 魏曹先生 <1992414357@qq.com>
Date: Tue, 30 Jun 2026 18:05:05 +0800
Subject: 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
---
docs/pages/3-define-a-chain.md | 131 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
create mode 100644 docs/pages/3-define-a-chain.md
(limited to 'docs/pages/3-define-a-chain.md')
diff --git a/docs/pages/3-define-a-chain.md b/docs/pages/3-define-a-chain.md
new file mode 100644
index 0000000..c6d3f8e
--- /dev/null
+++ b/docs/pages/3-define-a-chain.md
@@ -0,0 +1,131 @@
+
Declare a Chain
+
+ Use the chain macro to declare a chain and handle Entry input
+
+
+In the previous section, we declared `dispatcher!("greet", CMDGreet => EntryGreet)`.
+
+Now when a user types `greet`, it gets matched and wrapped into `EntryGreet`.
+
+But what happens after we get the Entry?
+
+We need a Chain to process it.
+
+## The `#[chain]` Macro
+
+`#[chain]` marks a handler function. The format is straightforward:
+
+```rust
+@@@dispatcher!("greet", CMDGreet => EntryGreet);
+pack!(ResultName = String);
+
+#[chain]
+fn handle_greet(args: EntryGreet) -> Next {
+ // args contains the remaining params after matching user input
+ let name = args.inner.first().cloned().unwrap_or_else(|| "World".to_string());
+ // Wrap the result into Next, telling the dispatcher where to go next
+ ResultName::new(name)
+}
+```
+
+Notice anything?
+
+The Chain function signature declares what it needs — `args: EntryGreet`.
+
+Then it returns a newtype via `ResultName::new(name)`.
+
+This returned `Next` expands into `impl Into>`.
+
+> [!TIP]
+> Wondering how `Into>` works?
+>
+> Check out the [Any Output Mechanism](pages/concepts/3-any-output) chapter to learn about `ChainProcess`.
+
+## The `pack!` Macro
+
+You've probably guessed it — `pack!(ResultName = String)` defines a type that flows through the pipeline:
+
+```rust
+// pack!(ResultName = String) generates code roughly like this
+
+#[derive(Groupped)]
+pub struct ResultName {
+ pub inner: String,
+}
+```
+
+Think of it as a **tagged** `String`.
+
+The dispatcher uses this tag for precise routing, ensuring data doesn't get mixed up — e.g., data sent to `RenderGreet` won't be misdelivered to `RenderError`.
+
+> [!NOTE]
+> Unlike a simple type alias (`type`), `pack!` generates a completely new type with its own `TypeId`.
+
+Here's a recommended naming convention:
+
+| Role | Naming Pattern | Example |
+| ------------ | ---------------------- | -------------------- |
+| Entry | `Entry` + command | `EntryGreet` |
+| Intermediate | `State` + description | `StateParsedArgs` |
+| Result | `Result` + description | `ResultGreetSomeone` |
+| Error | `Error` + description | `ErrorUserNotFound` |
+
+See [Naming Convention](pages/other/naming_rule) for details, but for now just remember: **use `pack!` to give your data a meaningful name**.
+
+## Extracting Params from Entry
+
+`EntryGreet`'s `inner` is a `Vec`, which you can freely process inside a Chain:
+
+```rust
+@@@dispatcher!("greet", CMDGreet => EntryGreet);
+@@@pack!(ResultName = String);
+#[chain]
+fn handle_greet(args: EntryGreet) -> Next {
+ // Take the first param, or use a default
+ let name = args
+ .inner
+ .first()
+ .cloned()
+ .unwrap_or_else(|| "World".to_string());
+
+ ResultName::new(name)
+}
+```
+
+If you enable the `parser` feature, you can also use `Picker` for more flexible param extraction — but that's a topic for later.
+
+## Putting It Together
+
+Now let's connect the Dispatcher and Chain:
+
+```rust
+// 1. Declare the command
+dispatcher!("greet", CMDGreet => EntryGreet);
+
+// 2. Declare the pipeline data type
+pack!(ResultName = String);
+
+// 3. Processing logic
+#[chain]
+fn handle_greet(args: EntryGreet) -> Next {
+ let name = args.inner
+ .first()
+ .cloned()
+ .unwrap_or_else(|| "World".to_string());
+ ResultName::new(name)
+}
+
+fn main() {
+ let mut program = ThisProgram::new();
+ program.with_dispatcher(CMDGreet);
+ program.exec_and_exit();
+}
+
+gen_program!();
+```
+
+But this code isn't complete yet — we only have the Dispatcher and Chain. One last step remains: **rendering the result**. That's what the next chapter, Renderer, covers.
+
+
+ Written by @Weicao-CatilGrass
+
--
cgit