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/9-error-handling.md | 120 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 docs/pages/9-error-handling.md (limited to 'docs/pages/9-error-handling.md') diff --git a/docs/pages/9-error-handling.md b/docs/pages/9-error-handling.md new file mode 100644 index 0000000..ec1f422 --- /dev/null +++ b/docs/pages/9-error-handling.md @@ -0,0 +1,120 @@ +
+ Gracefully present errors to the user +
+ +A pipeline isn't just the happy path. When input is invalid, a resource isn't found, or an operation fails, you need a place to handle these "surprises" instead of letting the program panic. + +## Two Paths: Success vs. Error + +Recall the pipeline model: Chain's return value is `Next`, which has two destinations: + +| Route | Meaning | +| -------------- | ------------------------------------------- | +| `.to_render()` | Got a result, hand it to a Renderer to show | +| `.to_chain()` | Not done yet, hand it to the next Chain | + +Error values can also take either path—you can render the error msg directly, or pass it to the next Chain for potential recovery. + +## Distinguish Errors with Dedicated Types + +```rust +@@@dispatcher!("greet", CMDGreet => EntryGreet); +pack!(ResultGreeting = String); +pack!(ErrorNameEmpty = String); + +#[chain] +fn handle_greet(args: EntryGreet) -> Next { + let name = args.inner.first().cloned().unwrap_or_default(); + + if name.is_empty() { + ErrorNameEmpty::new("name is required".to_string()).to_render() + } else { + ResultGreeting::new(name).to_render() + } +} +``` + +Then write separate Renderers: + +```rust +@@@dispatcher!("greet", CMDGreet => EntryGreet); +@@@pack!(ResultGreeting = String); +@@@pack!(ErrorNameEmpty = String); +@@@#[chain] fn handle_greet(args: EntryGreet) -> Next { ResultGreeting::new(args.inner.first().cloned().unwrap_or_default()).to_render() } + +#[renderer] +fn render_greeting(result: ResultGreeting) { + r_println!("Hello, {}!", *result); +} + +#[renderer] +fn render_error_name_empty(err: ErrorNameEmpty) { + r_println!("Error: {}", *err); +} +``` + +Each Renderer does its own job; what the user sees depends on what the Chain returned. + +## Complete Example + +```rust +dispatcher!("greet", CMDGreet => EntryGreet); + +pack!(ResultGreeting = String); +pack!(ErrorNameEmpty = String); + +#[chain] +fn handle_greet(args: EntryGreet) -> Next { + let name = args.inner.first().cloned().unwrap_or_default(); + if name.is_empty() { + ErrorNameEmpty::new("name is required".to_string()).to_render() + } else { + ResultGreeting::new(name).to_render() + } +} + +#[renderer] +fn render_greeting(result: ResultGreeting) { + r_println!("Hello, {}!", *result); +} + +#[renderer] +fn render_error_name_empty(err: ErrorNameEmpty) { + r_println!("Error: {}", *err); +} + +fn main() { + let mut program = ThisProgram::new(); + program.with_dispatcher(CMDGreet); + program.exec_and_exit(); +} + +gen_program!(); +``` + +Output: + +```text +~# my-cli greet Alice +Hello, Alice! + +~# my-cli greet +Error: name is required +``` + +## About `pack_err!` + +If you've enabled `extra_macros`, you can use `pack_err!` to quickly declare an error type with an auto-generated `name` field: + +```rust +// Features: ["extra_macros"] +pack_err!(ErrorNotFound); +// Generates: struct ErrorNotFound { pub name: String } +``` + +See [Feature List](pages/other/features) for details. + ++ Written by @Weicao-CatilGrass +
-- cgit