From ae49f93dd2aecdca0b4917539961b038b95a3beb Mon Sep 17 00:00:00 2001
From: Weicao-CatilGrass <1992414357@qq.com>
Date: Wed, 10 Jun 2026 15:11:18 +0800
Subject: Add README code block testing to CI pipeline
---
README.md | 772 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 737 insertions(+), 35 deletions(-)
(limited to 'README.md')
diff --git a/README.md b/README.md
index 81c2414..62b8b7f 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,6 @@
-
> [!WARNING]
>
> **Note**: Mingling is still under active development, and its API may change. Feel free to try it out and give us feedback!
@@ -38,22 +37,50 @@
### Mingling's Core Capabilities
1. **Separation of Concerns, Clear Logic**: Mingling decouples logic by responsibility, helping you organize your CLI program more clearly.
-See example: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-basic/src/main.rs)
+ See example: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-basic/src/main.rs)
2. **"All Logic is Functions"**: Execution logic, rendering logic, completion logic, help logic — everything is a function. Just attach the corresponding attribute macro to bind them to your program.
3. **Fully Dynamic Completion System**: With the `comp` feature, you can flexibly implement dynamic completion logic for any subcommand.
-See examples: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-completion/src/main.rs)
+ See examples: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-completion/src/main.rs)
4. **Lightning-Fast Subcommand Dispatch**: With the `dispatch_tree` feature, Mingling hardens the subcommand structure into a prefix tree at **compile time**, enabling blazing-fast subcommand lookup.
-See examples: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-dispatch-tree/src/main.rs)
+ See examples: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-dispatch-tree/src/main.rs)
5. **Lightweight Dependencies, On-Demand Importing**: Minimal core dependencies keep builds fast; enhanced features are imported on demand through fine-grained feature flags.
6. **Structured Output**: Enabling the `general_renderer` feature adds support for flags like `--json` and `--yaml`, providing structured output capabilities.
-See examples: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-general-renderer/src/main.rs)
+ See examples: [Example](https://github.com/catilgrass/mingling/blob/main/examples/example-general-renderer/src/main.rs)
+
+
+ ✍️ Writing with Mingling ✍️
+
+
+### The Big Picture
+
+Mingling organizes your CLI program into three distinct phases:
+
+```
+User Input → [Dispatcher] → Entry → [Chain(s)] → Result → [Renderer] → Output
+```
+
+The user's raw arguments flow in. A **Dispatcher** picks them up, wraps them into an **Entry** type, and hands it off to a **Chain** function. The chain processes the entry and produces a **Result**. A **Renderer** takes that result and writes it to the terminal.
+
+Everything in this pipeline is a plain Rust function with an attribute macro on top. You never need to manually implement traits or construct boilerplate.
+
+---
+### 1. Defining Commands — `dispatcher!`
-### What does Mingling look like?
+The entry point for every subcommand is the `dispatcher!` macro. It generates two structs for you: a **Dispatcher** (used to register the command with the program) and an **Entry** (a wrapper around `Vec` that holds the raw arguments).
-Here is a basic project written using **Mingling**:
-- When the user types `greet`, the program outputs `Hello, World!`
-- When the user types `greet Alice`, the program outputs `Hello, Alice!`
+```rust
+use mingling::prelude::*;
+
+// "command.name" dispatcher entry type
+// │ │ │
+dispatcher!("greet", CMDGreet => EntryGreet);
+
+// Nested subcommand: `remote add`
+dispatcher!("remote.add", CMDRemoteAdd => EntryRemoteAdd);
+```
+
+Then in `main()`, register the dispatcher with the program:
```rust
use mingling::prelude::*;
@@ -65,58 +92,733 @@ fn main() {
program.with_dispatcher(CMDGreet);
program.exec_and_exit();
}
+```
+
+Mingling also supports an abbreviated form (with the `extra_macros` feature):
+
+```rust
+// Features: ["extra_macros"]
+
+use mingling::prelude::*;
+
+// Auto-generates CMDGreet / EntryGreet from "greet"
+dispatcher!("greet");
+```
+
+---
+
+### 2. The Chain — "#[chain]" — Where Logic Lives
+
+The `#[chain]` attribute turns a plain function into an execution step. Think of it as "the logic that transforms one typed value into another."
+
+```rust
+use mingling::prelude::*;
+
+dispatcher!("greet", CMDGreet => EntryGreet);
pack!(ResultGreeting = String);
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
- let greeting = args.pick_or::((), "World").unpack();
+ let greeting = args
+ .inner
+ .first()
+ .cloned()
+ .unwrap_or_else(|| "World".to_string());
ResultGreeting::new(greeting)
}
+```
+
+Key points:
+
+- The return type is `Next` — a type alias for `ChainProcess`.
+- You chain results by calling `.to_chain()` on any `pack!`-ed type.
+- You can have **multiple chain functions** for the same command, each transforming the data further.
+- With the `async` feature, chain functions can be `async fn`.
+
+---
+
+### 3. The Renderer — "#[renderer]" — How Output Works
+
+The `#[renderer]` attribute turns a function into an output handler. It receives the final result of a chain and writes it to the terminal.
+
+```rust
+use mingling::prelude::*;
+
+pack!(ResultGreeting = String);
#[renderer]
fn render_greeting(greeting: ResultGreeting) {
r_println!("Hello, {}!", *greeting);
}
+```
+
+Inside a renderer, use `r_print!` / `r_println!` to write to the output buffer. This is not `println!` — it writes into Mingling's internal `RenderResult` buffer, which is flushed at the end of the pipeline.
+
+You can write renderers for **any type** in your program, including error types:
+
+```rust
+use mingling::prelude::*;
+
+#[renderer]
+fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) {
+ r_println!("Command not found: [{}]", err.join(" "));
+}
+```
+
+---
+
+### 4. Parsing Arguments — The Picker
+
+Mingling provides a **Picker** for zero-cost argument extraction. You use `pick()` or `pick_or()` on an entry to extract typed values, then `unpack()` to get the final tuple.
+
+```rust
+// Features: ["parser"]
+
+use mingling::prelude::*;
+use mingling::parser::Picker;
+
+dispatcher!("greet", CMDGreet => EntryGreet);
+pack!(ResultGreeting = String);
+
+#[chain]
+fn handle_greet(args: EntryGreet) -> Next {
+ let (name, count) = Picker::new(args.inner)
+ .pick::(()) // positional: first string
+ .pick_or::(["-r", "--repeat"], 1) // optional flag with default
+ .unpack();
+ ResultGreeting::new(format!("{} x{}", name, count))
+}
+```
+
+With the `parser` feature, the `AsPicker` trait provides a shorthand directly on entries:
+
+```rust
+// Features: ["parser"]
+
+use mingling::prelude::*;
+
+dispatcher!("greet", CMDGreet => EntryGreet);
+pack!(ResultGreeting = String);
+
+#[chain]
+fn handle(args: EntryGreet) -> Next {
+ let (name, count) = args
+ .pick::