aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/4-render-result.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/pages/4-render-result.md')
-rw-r--r--docs/pages/4-render-result.md142
1 files changed, 142 insertions, 0 deletions
diff --git a/docs/pages/4-render-result.md b/docs/pages/4-render-result.md
new file mode 100644
index 0000000..5093a52
--- /dev/null
+++ b/docs/pages/4-render-result.md
@@ -0,0 +1,142 @@
+<h1 align="center">Rendering Results</h1>
+<p align="center">
+ Use the <code>#[renderer]</code> macro to declare a renderer and output results
+</p>
+
+Now that we've created a Dispatcher and a Chain, and produced a Result type via `pack!`, there's one final step: **presenting the result to the user**.
+
+## The `#[renderer]` Macro
+
+Similar to `#[chain]`, `#[renderer]` marks an output function:
+
+```rust
+pack!(ResultName = String);
+#[renderer]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
+}
+```
+
+A Renderer takes the result produced by a Chain and outputs it using `r_println!`. What's the difference between `r_println!` and the usual `println!`?
+
+## The `r_println!` and `r_print!` Macros
+
+`r_println!` and `r_print!` are printing macros provided by Mingling. They write content into a `RenderResult` instead of printing directly to the terminal. This offers several benefits:
+
+1. **RenderResult holds an exit code** — you can make the program exit with a specific code
+2. **Easier testing** — you can capture rendered output and make assertions
+3. **Post-processing** — you can capture results and apply uniform text post-processing
+
+> [!TIP]
+> For simple printing, you can think of it as a drop-in replacement for `println!`. Using `r_println!` instead of `println!` is a safe choice.
+
+## A Complete Runnable Program
+
+Putting the content of all three tutorials together, here's your first complete Mingling program:
+
+```rust
+// 1. Declare a command with Dispatcher
+dispatcher!("greet", CMDGreet => EntryGreet);
+
+// 2. Declare result data with pack!
+pack!(ResultName = String);
+
+// 3. Handle logic with Chain
+#[chain]
+fn handle_greet(args: EntryGreet) -> Next {
+ let name = args.inner
+ .first()
+ .cloned()
+ .unwrap_or_else(|| "World".to_string());
+ ResultName::new(name)
+}
+
+// 4. Output results with Renderer
+#[renderer]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
+}
+
+// 5. Assemble and run the program in main
+fn main() {
+ let mut program = ThisProgram::new();
+ program.with_dispatcher(CMDGreet);
+ program.exec_and_exit();
+}
+
+// 6. Generate the complete program with gen_program!
+gen_program!();
+```
+
+## Try It Out
+
+```bash
+~# cargo run -- greet Alice
+```
+
+```text
+Hello, Alice!
+```
+
+Try without arguments:
+
+```bash
+~# cargo run -- greet
+```
+
+```text
+Hello, World!
+```
+
+Try an unknown command:
+
+```bash
+cargo run -- great
+```
+
+```text
+# No output!
+```
+
+## Add a Fallback
+
+`gen_program!()` auto-generates an `ErrorDispatcherNotFound` type that wraps `Vec<String>` — it holds the user's unmatched input. You just need to write a Renderer for it:
+
+```rust
+#[renderer]
+fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) {
+ if err.inner.is_empty() {
+ r_println!("Unknown command");
+ } else {
+ r_println!("Command not found: \"{}\"", err.inner.join(" "));
+ }
+}
+```
+
+With that added, try the unknown command again:
+
+```bash
+cargo run -- great
+```
+
+```text
+Command not found: "great"
+```
+
+## Congratulations
+
+You've completed your first full Mingling program! Here's a recap of what you've learned:
+
+| Concept | Macro/Function | In a Nutshell |
+| --------------- | ---------------- | ------------------------------------- |
+| Declare command | `dispatcher!` | Tell the program what users can input |
+| Handle logic | `#[chain]` | What to do with the arguments |
+| Output results | `#[renderer]` | How to present results to users |
+| Type wrapper | `pack!` | Give your data a meaningful name |
+| Program entry | `gen_program!()` | Auto-generate the pipeline wiring |
+
+In real projects you'll also use advanced features like resource injection, hooks, autocompletion, REPL, etc., but the core skeleton stays the same: **Dispatcher → Chain → Renderer**.
+
+<p align="center" style="font-size: 0.85em; color: gray;">
+ Written by @Weicao-CatilGrass
+</p>