From c385dcf15930d2754b68c2794986ad30fc65c141 Mon Sep 17 00:00:00 2001
From: 魏曹先生 <1992414357@qq.com>
Date: Mon, 20 Jul 2026 09:50:28 +0800
Subject: docs: migrate renderer examples to buffer macro and update docs
Update all documentation and code examples to use the new
`#[renderer(buffer)]`
pattern with `r_println!` instead of manually constructing
`RenderResult`
with `writeln!`.
---
GETTING_STARTED.md | 9 +-
README.md | 31 +++---
docs/_zh_CN/pages/10-help.md | 26 +++--
docs/_zh_CN/pages/11-resource-system.md | 18 ++--
docs/_zh_CN/pages/14-testing.md | 2 +-
docs/_zh_CN/pages/4-render-result.md | 49 +++++----
docs/_zh_CN/pages/5-multiple-commands.md | 17 ++-
docs/_zh_CN/pages/6-argument-parse-picker.md | 45 ++++----
docs/_zh_CN/pages/7-argument-parse-clap.md | 30 +++---
docs/_zh_CN/pages/9-error-handling.md | 34 +++---
.../_zh_CN/pages/advanced/2-structural-renderer.md | 18 ++--
docs/_zh_CN/pages/other/naming_rule.md | 17 ++-
docs/pages/10-help.md | 26 +++--
docs/pages/11-resource-system.md | 18 ++--
docs/pages/14-testing.md | 2 +-
docs/pages/4-render-result.md | 53 ++++++----
docs/pages/5-multiple-commands.md | 17 ++-
docs/pages/6-argument-parse-picker.md | 116 +++++++++------------
docs/pages/7-argument-parse-clap.md | 30 +++---
docs/pages/9-error-handling.md | 34 +++---
docs/pages/advanced/2-structural-renderer.md | 18 ++--
docs/pages/other/naming_rule.md | 19 ++--
mingling/src/lib.rs | 10 +-
23 files changed, 298 insertions(+), 341 deletions(-)
diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md
index bb2175f..1aad8d5 100644
--- a/GETTING_STARTED.md
+++ b/GETTING_STARTED.md
@@ -577,6 +577,7 @@ With the `structural_renderer` feature, users can add `--json` or `--yaml` flags
// serde = "1"
use mingling::prelude::*;
+use mingling::macros::buffer;
use mingling::setup::picker::StructuralRendererSetup;
use mingling::Grouped;
use mingling::StructuralData;
@@ -600,11 +601,9 @@ fn render_info(args: EntryRender) -> Next {
ResultInfo { name, age }.to_chain()
}
-#[renderer]
-fn render_info_result(info: ResultInfo) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "{} is {} years old", info.name, info.age).ok();
- result
+#[renderer(buffer)]
+fn render_info_result(info: ResultInfo) {
+ r_println!("{} is {} years old", info.name, info.age);
}
fn main() {
diff --git a/README.md b/README.md
index cb7efb0..2c21198 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,9 @@ You can use this approach to separate computation from result rendering, like th
```rust
// Features: ["picker"]
+use mingling::macros::buffer;
+use mingling::prelude::*;
+
dispatcher!("calc", CMDCalculate => EntryCalculate);
pack!(StateSumNumbers = Vec);
pack!(ResultNumber = i32);
@@ -82,11 +85,9 @@ fn handle_state_sum_numbers(sum: StateSumNumbers) -> ResultNumber {
}
// Renderer: return the render result and let the framework handle output
-#[renderer]
-fn render_number(number: ResultNumber) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "Number: {}", *number).ok();
- result
+#[renderer(buffer)]
+fn render_number(number: ResultNumber) {
+ r_println!("Number: {}", *number);
}
```
@@ -117,16 +118,16 @@ features = []
## Roadmap
- [x] Milestone.1 "MVP" 🎉
- - [x] [[0.1.4](https://docs.rs/mingling/0.1.4/mingling/)] [`core`] [`structural_renderer`] **Mingling** can render data into serializable formats via `--json` and `--yaml` flags
- - [x] [[0.1.5](https://docs.rs/mingling/0.1.5/mingling/)] [`core`] [`comp`] **Mingling** can dynamically invoke itself to provide completions for shells like `bash`, `zsh`, `fish`, and `pwsh`
- - [x] [[0.1.6](https://docs.rs/mingling/0.1.6/mingling/)] [`core`] [`comp`] **Mingling** can gather more context for smarter completions
- - [x] [[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)] [`clap`] Provides a **Clap** compatibility layer, allowing **Mingling** to reuse its powerful parsing capabilities
- - [x] [[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)] [`core`] **Mingling** can intercept `-h` or `--help` flags to display custom help text for each subcommand
- - [x] [[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)] [`mling`] Provides a basic scaffolding tool (`mling`) for rapid development and debugging
- - [x] [[0.1.8](https://docs.rs/mingling/0.1.8/mingling/)] [`core`] [`dispatch_tree`] Converts the subcommand list into a prefix tree to improve command matching speed
- - [x] [[0.1.9](https://docs.rs/mingling/0.1.9/mingling/)] [`core`] [`dev_toolkits`] Provides debugging interfaces for developers to capture invocation information when issues arise (`InvokeStackDisplay`) (indirectly implemented via `ProgramHook`)
- - [x] [[0.1.9](https://docs.rs/mingling/0.1.9/mingling/)] [`core`] [`repl`] Provides REPL capability (`program.exec_repl();`)
- - [x] [[0.2.0](https://docs.rs/mingling/0.2.0/mingling/)] Complete documentation, tests, and examples
+ - [x] [[0.1.4](https://docs.rs/mingling/0.1.4/mingling/)] [`core`] [`structural_renderer`] **Mingling** can render data into serializable formats via `--json` and `--yaml` flags
+ - [x] [[0.1.5](https://docs.rs/mingling/0.1.5/mingling/)] [`core`] [`comp`] **Mingling** can dynamically invoke itself to provide completions for shells like `bash`, `zsh`, `fish`, and `pwsh`
+ - [x] [[0.1.6](https://docs.rs/mingling/0.1.6/mingling/)] [`core`] [`comp`] **Mingling** can gather more context for smarter completions
+ - [x] [[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)] [`clap`] Provides a **Clap** compatibility layer, allowing **Mingling** to reuse its powerful parsing capabilities
+ - [x] [[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)] [`core`] **Mingling** can intercept `-h` or `--help` flags to display custom help text for each subcommand
+ - [x] [[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)] [`mling`] Provides a basic scaffolding tool (`mling`) for rapid development and debugging
+ - [x] [[0.1.8](https://docs.rs/mingling/0.1.8/mingling/)] [`core`] [`dispatch_tree`] Converts the subcommand list into a prefix tree to improve command matching speed
+ - [x] [[0.1.9](https://docs.rs/mingling/0.1.9/mingling/)] [`core`] [`dev_toolkits`] Provides debugging interfaces for developers to capture invocation information when issues arise (`InvokeStackDisplay`) (indirectly implemented via `ProgramHook`)
+ - [x] [[0.1.9](https://docs.rs/mingling/0.1.9/mingling/)] [`core`] [`repl`] Provides REPL capability (`program.exec_repl();`)
+ - [x] [[0.2.0](https://docs.rs/mingling/0.2.0/mingling/)] Complete documentation, tests, and examples
- [ ] Milestone.2 "More Comfortable Dev and User Experience"
- [ ] [`mling` / `mingling-cli`]
- [ ] **Mingling** Linter
diff --git a/docs/_zh_CN/pages/10-help.md b/docs/_zh_CN/pages/10-help.md
index 8cee2aa..1c4e410 100644
--- a/docs/_zh_CN/pages/10-help.md
+++ b/docs/_zh_CN/pages/10-help.md
@@ -13,18 +13,17 @@ Mingling 里用 `#[help]` 宏给命令添加帮助文本。
```rust
@@@use mingling::macros::help;
+@@@use mingling::macros::buffer;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
-#[help]
-fn help_greet(_entry: EntryGreet) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Usage: greet [name]").ok();
- writeln!(r, "Say hello to someone.").ok();
- r
+#[help(buffer)]
+fn help_greet(_entry: EntryGreet) {
+ r_println!("Usage: greet [name]");
+ r_println!("Say hello to someone.");
}
```
> [!NOTE]
-> 帮助函数同样通过 `writeln!` 向 `RenderResult` 写入内容,因为 `#[help]` 遵循渲染管线 —— 它是由 `--help` 标志提前触发的短路渲染,而不是管线之外的逻辑。
+> 帮助函数同样通过 `r_println!` 向 `RenderResult` 写入内容,因为 `#[help]` 遵循渲染管线 —— 它是由 `--help` 标志提前触发的短路渲染,而不是管线之外的逻辑。
## 全局帮助
@@ -32,14 +31,13 @@ fn help_greet(_entry: EntryGreet) -> RenderResult {
```rust
@@@use mingling::macros::help;
+@@@use mingling::macros::buffer;
// 用户直接输入 --help 时触发
-#[help]
-fn help_root(entry: ErrorDispatcherNotFound) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Usage: my-cli ").ok();
- writeln!(r, "Commands:").ok();
- writeln!(r, " greet Say hello").ok();
- r
+#[help(buffer)]
+fn help_root(entry: ErrorDispatcherNotFound) {
+ r_println!("Usage: my-cli ");
+ r_println!("Commands:");
+ r_println!(" greet Say hello");
}
```
diff --git a/docs/_zh_CN/pages/11-resource-system.md b/docs/_zh_CN/pages/11-resource-system.md
index a8aab4d..b127a3a 100644
--- a/docs/_zh_CN/pages/11-resource-system.md
+++ b/docs/_zh_CN/pages/11-resource-system.md
@@ -27,6 +27,7 @@ fn main() {
在 Chain 或 Renderer 中,只需在参数列表里声明你要的资源:
```rust
+@@@use mingling::macros::buffer;
@@@#[derive(Default, Clone)]
@@@struct ResCurrentDir(String);
@@@dispatcher!("pwd", CMDPrintWorkingDir => EntryPrintWorkingDir);
@@ -37,11 +38,9 @@ fn handle_pwd(_args: EntryPrintWorkingDir, cwd: &ResCurrentDir) -> Next {
ResultPath::new(cwd.0.clone()).to_render()
}
-#[renderer]
-fn render_path(result: ResultPath) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "{}", *result).ok();
- r
+#[renderer(buffer)]
+fn render_path(result: ResultPath) {
+ r_println!("{}", *result);
}
```
@@ -50,6 +49,7 @@ fn render_path(result: ResultPath) -> RenderResult {
用 `&mut T` 注入可修改资源:
```rust
+@@@use mingling::macros::buffer;
@@@#[derive(Default, Clone)]
@@@struct ResVisitCount(u32);
@@@dispatcher!("visit", CMDVisit => EntryVisit);
@@ -60,11 +60,9 @@ fn handle_visit(_args: EntryVisit, counter: &mut ResVisitCount) -> Next {
ResultDone::default().into()
}
-#[renderer]
-fn render_done(_done: ResultDone, counter: &ResVisitCount) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "visit count is : {}", counter.0).ok();
- r
+#[renderer(buffer)]
+fn render_done(_done: ResultDone, counter: &ResVisitCount) {
+ r_println!("visit count is : {}", counter.0);
}
```
diff --git a/docs/_zh_CN/pages/14-testing.md b/docs/_zh_CN/pages/14-testing.md
index 621d43e..031be59 100644
--- a/docs/_zh_CN/pages/14-testing.md
+++ b/docs/_zh_CN/pages/14-testing.md
@@ -16,7 +16,7 @@ Renderer 是最容易测试的——调用函数,断言返回结果:
#[renderer]
fn render_greet(result: ResultName) -> RenderResult {
let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
+ r_println!(r, "Hello, {}!", *result);
r
}
diff --git a/docs/_zh_CN/pages/4-render-result.md b/docs/_zh_CN/pages/4-render-result.md
index 81c5102..8b29fca 100644
--- a/docs/_zh_CN/pages/4-render-result.md
+++ b/docs/_zh_CN/pages/4-render-result.md
@@ -10,18 +10,31 @@
跟 `#[chain]` 类似,`#[renderer]` 用于标记一个输出函数:
```rust
-use std::io::Write;
+@@@use mingling::macros::buffer;
+@@@pack!(ResultName = String);
+#[renderer(buffer)]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
+}
+```
+
+Renderer 接收 Chain 产出的结果,然后返回一个 `RenderResult`。在函数内部,创建 `RenderResult`,用 `r_print!` / `r_println!` 写入内容,最后返回它。
+
+## `buffer` 拓展
+
+若您觉得显式创建并返回 `RenderResult` 过于繁琐,可以使用 `#[renderer(buffer)]` 在原始函数内植入一个缓冲区。
+
+```rust
+use mingling::macros::buffer;
@@@pack!(ResultName = String);
-#[renderer]
-fn render_name(name: ResultName) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "Hello, {}!", *name).ok();
- result
+#[renderer(buffer)]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
}
```
-Renderer 接收 Chain 产出的结果,然后返回一个 `RenderResult`。在函数内部,创建 `RenderResult`,用 `write!` / `writeln!`(来自 [`std::io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html))写入内容,最后返回它。
+这样,你的 renderer 函数就获得了更简洁的语法,但也引入了一个隐含机制:它会向函数内注入一个名为 `__render_result_buffer` 的可变 `RenderResult`。当 `r_print!` 宏没有显式指定 `RenderResult` 时,它便会按照约定向该缓冲区追加输出。
## `RenderResult` 类型
@@ -36,7 +49,7 @@ Renderer 接收 Chain 产出的结果,然后返回一个 `RenderResult`。在
把三篇教程的内容合在一起,你的第一个 Mingling 程序就完整了:
```rust
-use std::io::Write;
+use mingling::macros::buffer;
// 1. 用 Dispatcher 声明命令
dispatcher!("greet", CMDGreet => EntryGreet);
@@ -55,11 +68,9 @@ fn handle_greet(args: EntryGreet) -> Next {
}
// 4. 用 Renderer 输出结果
-#[renderer]
-fn render_name(name: ResultName) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "Hello, {}!", *name).ok();
- result
+#[renderer(buffer)]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
}
// 5. 在 main 函数内装配程序并运行
@@ -108,17 +119,15 @@ cargo run -- great
`gen_program!()` 自动生成了一个 `ErrorDispatcherNotFound` 类型,包裹 `Vec`——它存的是用户输入的那些没匹配到的命令。你只需要给它写一个 Renderer:
```rust
-use std::io::Write;
+use mingling::macros::buffer;
-#[renderer]
-fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) -> RenderResult {
- let mut result = RenderResult::new();
+#[renderer(buffer)]
+fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) {
if err.inner.is_empty() {
- writeln!(result, "Unknown command").ok();
+ r_println!("Unknown command");
} else {
- writeln!(result, "Command not found: \"{}\"", err.inner.join(" ")).ok();
+ r_println!("Command not found: \"{}\"", err.inner.join(" "));
}
- result
}
```
diff --git a/docs/_zh_CN/pages/5-multiple-commands.md b/docs/_zh_CN/pages/5-multiple-commands.md
index 38ce2cf..ff6596d 100644
--- a/docs/_zh_CN/pages/5-multiple-commands.md
+++ b/docs/_zh_CN/pages/5-multiple-commands.md
@@ -10,6 +10,7 @@
继续在同一个项目里操作:
```rust
+@@@use mingling::macros::buffer;
// 声明两个命令
dispatcher!("greet", CMDGreet => EntryGreet);
dispatcher!("add", CMDAdd => EntryAdd);
@@ -29,18 +30,14 @@ fn handle_add(args: EntryAdd) -> Next {
ResultSum::new(sum).into()
}
-#[renderer]
-fn render_greet(result: ResultGreeting) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
}
-#[renderer]
-fn render_sum(result: ResultSum) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Sum: {}", *result).ok();
- r
+#[renderer(buffer)]
+fn render_sum(result: ResultSum) {
+ r_println!("Sum: {}", *result);
}
fn main() {
diff --git a/docs/_zh_CN/pages/6-argument-parse-picker.md b/docs/_zh_CN/pages/6-argument-parse-picker.md
index 4bf162c..f0609ed 100644
--- a/docs/_zh_CN/pages/6-argument-parse-picker.md
+++ b/docs/_zh_CN/pages/6-argument-parse-picker.md
@@ -139,6 +139,7 @@ fn handle_test_entry(prev: EntryTest) -> Next {
```rust
// Features: ["parser", "extra_macros"]
+@@@use mingling::macros::buffer;
@@@use mingling::macros::route;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
@@@pack!(ResultName = String);
@@ -155,11 +156,9 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
ResultName::new(name).into()
}
-#[renderer]
-fn render_greet(result: ResultName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultName) {
+ r_println!("Hello, {}!", *result);
}
```
@@ -225,6 +224,7 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
```rust
// Features: ["parser", "extra_macros"]
+@@@use mingling::macros::buffer;
@@@use mingling::macros::route;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
@@@pack!(ResultName = String);
@@ -247,19 +247,15 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
ResultName::new(name).into()
}
-#[renderer]
-fn render_name_too_long(prev: ErrorNameTooLong) -> RenderResult {
- let mut r = RenderResult::new();
+#[renderer(buffer)]
+fn render_name_too_long(prev: ErrorNameTooLong) {
let len = *prev;
- writeln!(r, "Error: name too long (length: {} > 32)", len).ok();
- r
+ r_println!("Error: name too long (length: {} > 32)", len);
}
-#[renderer]
-fn render_name(prev: ResultName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_name(prev: ResultName) {
+ r_println!("Hello, {}!", *prev);
}
```
@@ -314,6 +310,7 @@ fn parse_size() {
```rust
// Features: ["parser"]
+@@@use mingling::macros::buffer;
@@@use mingling::parser::{Pickable, Argument};
@@@use mingling::Flag;
#[derive(Default, Clone)]
@@ -341,11 +338,9 @@ fn handle_connect_entry(prev: EntryConnect) -> Next {
ResultConnected::new(address).into()
}
-#[renderer]
-fn render_connected(addr: ResultConnected) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Connected: IP: {} PORT: {}", addr.ip, addr.port).ok();
- r
+#[renderer(buffer)]
+fn render_connected(addr: ResultConnected) {
+ r_println!("Connected: IP: {} PORT: {}", addr.ip, addr.port);
}
```
@@ -362,6 +357,7 @@ Connected: IP: 127.0.0.1 PORT: 8080
```rust
// Features: ["parser"]
+@@@use mingling::macros::buffer;
@@@use mingling::parser::PickableEnum;
@@@use mingling::EnumTag;
#[derive(Debug, Default, EnumTag)]
@@ -382,11 +378,9 @@ fn handle_eat_entry(prev: EntryEat) -> Next {
ResultFruit::new(fruit).into()
}
-#[renderer]
-fn render_fruit(prev: ResultFruit) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Picked fruit: {:?}", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_fruit(prev: ResultFruit) {
+ r_println!("Picked fruit: {:?}", *prev);
}
```
@@ -395,3 +389,4 @@ fn render_fruit(prev: ResultFruit) -> RenderResult {
Written by @Weicao-CatilGrass
+````
diff --git a/docs/_zh_CN/pages/7-argument-parse-clap.md b/docs/_zh_CN/pages/7-argument-parse-clap.md
index 21f886c..fda93f3 100644
--- a/docs/_zh_CN/pages/7-argument-parse-clap.md
+++ b/docs/_zh_CN/pages/7-argument-parse-clap.md
@@ -25,6 +25,7 @@ features = ["derive", "color"]
// Dependencies:
// clap = "4"
@@@ use mingling::macros::dispatcher_clap;
+@@@ use mingling::macros::buffer;
#[derive(Default, clap::Parser, Grouped)]
#[dispatcher_clap("greet", CMDGreet, help = true, error = ErrorGreetParsed)]
pub struct EntryGreet {
@@ -34,23 +35,19 @@ pub struct EntryGreet {
repeat: i32,
}
-#[renderer]
-fn render_greet(greet: EntryGreet) -> RenderResult {
- let mut r = RenderResult::new();
+#[renderer(buffer)]
+fn render_greet(greet: EntryGreet) {
let count = greet.repeat.max(0) as usize;
- write!(r, "Hello, ").ok();
+ r_print!("Hello, ");
for _ in 0..count {
- write!(r, "{} ", greet.name).ok();
+ r_print!("{} ", greet.name);
}
- writeln!(r, "!").ok();
- r
+ r_println!("!");
}
-#[renderer]
-fn render_greet_parse_failed(err: ErrorGreetParsed) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "{}", *err).ok();
- r
+#[renderer(buffer)]
+fn render_greet_parse_failed(err: ErrorGreetParsed) {
+ r_println!("{}", *err);
}
```
@@ -62,6 +59,7 @@ fn render_greet_parse_failed(err: ErrorGreetParsed) -> RenderResult {
// Features: ["clap"]
// Dependencies:
// clap = "4"
+@@@use mingling::macros::buffer;
@@@use mingling::setup::BasicProgramSetup;
@@@use mingling::macros::dispatcher_clap;
@@@#[derive(Default, clap::Parser, Grouped)]
@@ -69,11 +67,9 @@ fn render_greet_parse_failed(err: ErrorGreetParsed) -> RenderResult {
@@@pub struct EntryGreet {
@@@ name: String,
@@@}
-@@@#[renderer]
-@@@fn render_greet(greet: EntryGreet) -> RenderResult {
-@@@ let mut r = RenderResult::new();
-@@@ write!(r, "Hello, {}!", greet.name).ok();
-@@@ r
+@@@#[renderer(buffer)]
+@@@fn render_greet(greet: EntryGreet) {
+@@@ r_println!("Hello, {}!", greet.name);
@@@}
fn main() {
let mut program = ThisProgram::new();
diff --git a/docs/_zh_CN/pages/9-error-handling.md b/docs/_zh_CN/pages/9-error-handling.md
index 07c82da..4ce61ab 100644
--- a/docs/_zh_CN/pages/9-error-handling.md
+++ b/docs/_zh_CN/pages/9-error-handling.md
@@ -38,23 +38,20 @@ fn handle_greet(args: EntryGreet) -> Next {
然后各自写 Renderer:
```rust
+@@@use mingling::macros::buffer;
@@@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_greet(result: ResultGreeting) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
}
-#[renderer]
-fn render_error_name_empty(err: ErrorNameEmpty) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: {}", *err).ok();
- r
+#[renderer(buffer)]
+fn render_error_name_empty(err: ErrorNameEmpty) {
+ r_println!("Error: {}", *err);
}
```
@@ -63,6 +60,7 @@ fn render_error_name_empty(err: ErrorNameEmpty) -> RenderResult {
## 完整的例子
```rust
+@@@use mingling::macros::buffer;
dispatcher!("greet", CMDGreet => EntryGreet);
pack!(ResultGreeting = String);
@@ -78,18 +76,14 @@ fn handle_greet(args: EntryGreet) -> Next {
}
}
-#[renderer]
-fn render_greet(result: ResultGreeting) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
}
-#[renderer]
-fn render_error_name_empty(err: ErrorNameEmpty) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: {}", *err).ok();
- r
+#[renderer(buffer)]
+fn render_error_name_empty(err: ErrorNameEmpty) {
+ r_println!("Error: {}", *err);
}
fn main() {
diff --git a/docs/_zh_CN/pages/advanced/2-structural-renderer.md b/docs/_zh_CN/pages/advanced/2-structural-renderer.md
index 70bed79..a498dac 100644
--- a/docs/_zh_CN/pages/advanced/2-structural-renderer.md
+++ b/docs/_zh_CN/pages/advanced/2-structural-renderer.md
@@ -27,6 +27,7 @@ features = ["structural_renderer"]
// Features: ["structural_renderer"]
// Dependencies:
// serde = "1"
+@@@use mingling::macros::buffer;
@@@use mingling::setup::StructuralRendererSetup;
@@@dispatcher!("render", CMDRender => EntryRender);
@@ -40,11 +41,9 @@ fn handle_render(args: EntryRender) -> Next {
ResultInfo::new((name, age)).into()
}
-#[renderer]
-fn render_info(r: ResultInfo) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "{:?}", *r).ok();
- result
+#[renderer(buffer)]
+fn render_info(r: ResultInfo) {
+ r_println!("{:?}", *r);
}
```
@@ -68,6 +67,7 @@ fn render_info(r: ResultInfo) -> RenderResult {
// Features: ["structural_renderer"]
// Dependencies:
// serde = "1"
+@@@use mingling::macros::buffer;
@@@use mingling::prelude::*;
@@@use mingling::setup::StructuralRendererSetup;
@@@use mingling::StructuralData;
@@ -87,11 +87,9 @@ fn handle_render(args: EntryRender) -> Next {
Info { name, age }.to_render()
}
-#[renderer]
-fn render_info(info: Info) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "{} is {} years old", info.name, info.age).ok();
- r
+#[renderer(buffer)]
+fn render_info(info: Info) {
+ r_println!("{} is {} years old", info.name, info.age);
}
@@@
@@@fn main() {
diff --git a/docs/_zh_CN/pages/other/naming_rule.md b/docs/_zh_CN/pages/other/naming_rule.md
index c854ba1..6e65ee4 100644
--- a/docs/_zh_CN/pages/other/naming_rule.md
+++ b/docs/_zh_CN/pages/other/naming_rule.md
@@ -166,6 +166,7 @@ fn handle_remote_add(args: EntryRemoteAdd, cwd: &ResCurrentDir, db: &mut ResData
## 完整示例
```rust
+@@@use mingling::macros::buffer;
@@@ #[derive(Default, Clone)]
@@@ struct ResDatabase { }
@@@ impl ResDatabase { fn has_remote(&self, remote: &String) -> bool { true } }
@@ -192,19 +193,15 @@ fn handle_state_operation_remotes(state: StateOperationRemotes, db: &ResDatabase
}
// 结果渲染
-#[renderer]
-fn render_remote_added(result: ResultRemoteAdded) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Remote added: {}", result.inner).ok();
- r
+#[renderer(buffer)]
+fn render_remote_added(result: ResultRemoteAdded) {
+ r_println!("Remote added: {}", result.inner);
}
// 错误渲染
-#[renderer]
-fn render_error_repository_not_found(err: ErrorRepositoryNotFound) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: remote '{}' not found", err.inner).ok();
- r
+#[renderer(buffer)]
+fn render_error_repository_not_found(err: ErrorRepositoryNotFound) {
+ r_println!("Error: remote '{}' not found", err.inner);
}
```
diff --git a/docs/pages/10-help.md b/docs/pages/10-help.md
index c17f410..1e3ea78 100644
--- a/docs/pages/10-help.md
+++ b/docs/pages/10-help.md
@@ -13,18 +13,17 @@ Write a help function directly for an Entry:
```rust
@@@use mingling::macros::help;
+@@@use mingling::macros::buffer;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
-#[help]
-fn help_greet(entry: EntryGreet) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Usage: greet [name]").ok();
- writeln!(r, "Say hello to someone.").ok();
- r
+#[help(buffer)]
+fn help_greet(_entry: EntryGreet) {
+ r_println!("Usage: greet [name]");
+ r_println!("Say hello to someone.");
}
```
> [!NOTE]
-> Help functions also use `writeln!` into a `RenderResult`, because `#[help]` follows the rendering pipeline — it's a short-circuit render triggered early by the `--help` flag, not logic outside the pipeline.
+> Help functions also use `r_println!` into a `RenderResult`, because `#[help]` follows the rendering pipeline — it's a short-circuit render triggered early by the `--help` flag, not logic outside the pipeline.
## Global Help
@@ -32,14 +31,13 @@ You can also write help for `ErrorDispatcherNotFound` as the "root help":
```rust
@@@use mingling::macros::help;
+@@@use mingling::macros::buffer;
// Triggered when user passes --help directly
-#[help]
-fn help_root(entry: ErrorDispatcherNotFound) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Usage: my-cli ").ok();
- writeln!(r, "Commands:").ok();
- writeln!(r, " greet Say hello").ok();
- r
+#[help(buffer)]
+fn help_root(entry: ErrorDispatcherNotFound) {
+ r_println!("Usage: my-cli ");
+ r_println!("Commands:");
+ r_println!(" greet Say hello");
}
```
diff --git a/docs/pages/11-resource-system.md b/docs/pages/11-resource-system.md
index 9491212..0e2bd19 100644
--- a/docs/pages/11-resource-system.md
+++ b/docs/pages/11-resource-system.md
@@ -27,6 +27,7 @@ Since `ResCurrentDir` implements both `Default` and `Clone`, the framework autom
In a Chain or Renderer, simply declare the resource in the parameter list:
```rust
+@@@use mingling::macros::buffer;
@@@#[derive(Default, Clone)]
@@@struct ResCurrentDir(String);
@@@dispatcher!("pwd", CMDPrintWorkingDir => EntryPrintWorkingDir);
@@ -37,11 +38,9 @@ fn handle_pwd(_args: EntryPrintWorkingDir, cwd: &ResCurrentDir) -> Next {
ResultPath::new(cwd.0.clone()).to_render()
}
-#[renderer]
-fn render_path(result: ResultPath) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "{}", *result).ok();
- r
+#[renderer(buffer)]
+fn render_path(result: ResultPath) {
+ r_println!("{}", *result);
}
```
@@ -50,6 +49,7 @@ fn render_path(result: ResultPath) -> RenderResult {
Use `&mut T` to inject a mutable resource:
```rust
+@@@use mingling::macros::buffer;
@@@#[derive(Default, Clone)]
@@@struct ResVisitCount(u32);
@@@dispatcher!("visit", CMDVisit => EntryVisit);
@@ -60,11 +60,9 @@ fn handle_visit(_args: EntryVisit, counter: &mut ResVisitCount) -> Next {
ResultDone::default().into()
}
-#[renderer]
-fn render_done(_done: ResultDone, counter: &ResVisitCount) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "visit count is : {}", counter.0).ok();
- r
+#[renderer(buffer)]
+fn render_done(_done: ResultDone, counter: &ResVisitCount) {
+ r_println!("visit count is : {}", counter.0);
}
```
diff --git a/docs/pages/14-testing.md b/docs/pages/14-testing.md
index fa196b0..65fedc9 100644
--- a/docs/pages/14-testing.md
+++ b/docs/pages/14-testing.md
@@ -16,7 +16,7 @@ Renderer is the easiest to test — call the function, assert the result:
#[renderer]
fn render_greet(result: ResultName) -> RenderResult {
let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
+ r_println!(r, "Hello, {}!", *result);
r
}
diff --git a/docs/pages/4-render-result.md b/docs/pages/4-render-result.md
index ca1e563..9e72d09 100644
--- a/docs/pages/4-render-result.md
+++ b/docs/pages/4-render-result.md
@@ -7,21 +7,34 @@ Now we've created a Dispatcher and a Chain, and produced a Result type via `pack
## The `#[renderer]` Macro
-Similar to `#[chain]`, `#[renderer]` marks an output function:
+Similar to `#[chain]`, `#[renderer]` marks a function that produces output:
```rust
-use std::io::Write;
+@@@use mingling::macros::buffer;
+@@@pack!(ResultName = String);
+#[renderer(buffer)]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
+}
+```
-pack!(ResultName = String);
-#[renderer]
-fn render_name(name: ResultName) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "Hello, {}!", *name).ok();
- result
+A Renderer receives the result produced by a Chain and returns a `RenderResult`. Inside the function, you create a `RenderResult`, write content with `r_print!` / `r_println!`, and finally return it.
+
+## The `buffer` Extension
+
+If you find explicitly creating and returning a `RenderResult` too verbose, you can use `#[renderer(buffer)]` to inject a buffer directly into your function.
+
+```rust
+use mingling::macros::buffer;
+
+@@@pack!(ResultName = String);
+#[renderer(buffer)]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
}
```
-A Renderer takes the result produced by a Chain and returns a `RenderResult`. Inside the function, create a `RenderResult`, write content using `write!` / `writeln!` (from [`std::io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html)), and return it.
+This gives your renderer function a more concise syntax, but also introduces an implicit mechanism: it injects a mutable `RenderResult` variable named `__render_result_buffer` into the function. When the `r_print!` macro is used without an explicit `RenderResult`, it will append output to that buffer by convention.
## The `RenderResult` Type
@@ -36,7 +49,7 @@ A Renderer takes the result produced by a Chain and returns a `RenderResult`. In
Putting all three tutorials together, here's your first complete Mingling program:
```rust
-use std::io::Write;
+use mingling::macros::buffer;
// 1. Declare commands with a Dispatcher
dispatcher!("greet", CMDGreet => EntryGreet);
@@ -55,11 +68,9 @@ fn handle_greet(args: EntryGreet) -> Next {
}
// 4. Output results with a Renderer
-#[renderer]
-fn render_name(name: ResultName) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "Hello, {}!", *name).ok();
- result
+#[renderer(buffer)]
+fn render_name(name: ResultName) {
+ r_println!("Hello, {}!", *name);
}
// 5. Assemble and run the program in main
@@ -108,17 +119,15 @@ cargo run -- great
`gen_program!()` auto-generates an `ErrorDispatcherNotFound` type wrapping `Vec`—it holds the user input that didn't match any command. You just need to write a Renderer for it:
```rust
-use std::io::Write;
+use mingling::macros::buffer;
-#[renderer]
-fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) -> RenderResult {
- let mut result = RenderResult::new();
+#[renderer(buffer)]
+fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) {
if err.inner.is_empty() {
- writeln!(result, "Unknown command").ok();
+ r_println!("Unknown command");
} else {
- writeln!(result, "Command not found: \"{}\"", err.inner.join(" ")).ok();
+ r_println!("Command not found: \"{}\"", err.inner.join(" "));
}
- result
}
```
diff --git a/docs/pages/5-multiple-commands.md b/docs/pages/5-multiple-commands.md
index d9a335a..0b71e49 100644
--- a/docs/pages/5-multiple-commands.md
+++ b/docs/pages/5-multiple-commands.md
@@ -10,6 +10,7 @@ Real-world CLIs rarely have just one command. Let's extend our previous greet pr
Work in the same project:
```rust
+@@@use mingling::macros::buffer;
// Declare two commands
dispatcher!("greet", CMDGreet => EntryGreet);
dispatcher!("add", CMDAdd => EntryAdd);
@@ -29,18 +30,14 @@ fn handle_add(args: EntryAdd) -> Next {
ResultSum::new(sum).into()
}
-#[renderer]
-fn render_greet(result: ResultGreeting) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
}
-#[renderer]
-fn render_sum(result: ResultSum) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Sum: {}", *result).ok();
- r
+#[renderer(buffer)]
+fn render_sum(result: ResultSum) {
+ r_println!("Sum: {}", *result);
}
fn main() {
diff --git a/docs/pages/6-argument-parse-picker.md b/docs/pages/6-argument-parse-picker.md
index 398cd3c..01f1c37 100644
--- a/docs/pages/6-argument-parse-picker.md
+++ b/docs/pages/6-argument-parse-picker.md
@@ -3,7 +3,7 @@
Use Picker to perform basic argument parsing
-In previous tutorials, we extracted args manually from `EntryGreet.inner` (`Vec`).
+In previous tutorials, we manually extracted parameters from `EntryGreet.inner` (`Vec`).
```rust
@@@ fn main() {
@@ -12,7 +12,7 @@ let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
@@@ }
```
-But this approach doesn't scale well for many params. Mingling provides `Picker` — a chaining API to extract and convert args.
+But this approach doesn't scale well when there are many params. Mingling provides `Picker` — a chained API for extracting and transforming params.
To enable `Picker`, update your `Cargo.toml`:
@@ -22,7 +22,7 @@ To enable `Picker`, update your `Cargo.toml`:
features = ["parser"]
```
-Now let's look at `Picker` in action:
+Now let's see how `Picker` is written:
```rust
// Features: ["parser"]
@@ -36,9 +36,9 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
}
```
-`AsPicker` implements `pick`, `pick_or`, and `pick_or_route` for any type that can convert to `Vec`: they semantically **pick** args from a string list and convert them to structured data.
+`AsPicker` implements `pick`, `pick_or`, and `pick_or_route` for all types convertible to `Vec`. These functions semantically **pick** params from the string list and convert them into structured data.
-Breaking down the example above:
+For the code above:
```rust
// Features: ["parser"]
@@ -62,17 +62,17 @@ Its semantics are:
@@@let name: String =
prev.pick_or((), "World").unpack();
// ~~~~ ~~~~~~~ ~~ ~~~~~~~ ~~~~~~~~
-// | | | | |_ unpack to String
+// | | | | |_ unpack as String
// | | | |__________ default value "World"
// | | |______________ pick the first positional arg (no flag)
// | |______________________ pick or use default
-// |___________________________ from previous input
+// |___________________________ from the previous input
@@@}
```
-## Parsing Flag Args
+## Parsing Flag Arguments
-If your program needs to parse flag args (e.g., `greet --name Alice`), do this:
+If your program needs to parse flag arguments (e.g. `greet --name Alice`), do this:
```rust
// Features: ["parser"]
@@ -97,19 +97,19 @@ Its semantics:
@@@let name: String =
prev.pick_or(["--name", "-n"], "World").unpack();
// ~~~~ ~~~~~~~ ~~~~~~~~~~~~~~~~ ~~~~~~~ ~~~~~~~~
-// | | | | |_ unpack to String
+// | | | | |_ unpack as String
// | | | |__________ default value "World"
-// | | |____________________________ pick arg after "--name" or "-n"
+// | | |____________________________ pick the value after "--name" or "-n"
// | |____________________________________ pick or use default
-// |_________________________________________ from previous input
+// |_________________________________________ from the previous input
@@@}
```
## About `.unpack()`
-You may have noticed that `Picker` calls `.unpack()` at the end of parsing. It converts the accumulated parse results into structured info.
+You may have noticed that `Picker` calls `.unpack()` at the end of parsing. It converts the collected results into structured info.
-For a single pick, `.unpack()` returns a single value; for multiple picks, it returns a tuple:
+For a single pick, `.unpack()` returns the value directly; for multiple picks, it returns a tuple:
```rust
// Features: ["parser"]
@@ -129,16 +129,17 @@ fn handle_test_entry(prev: EntryTest) -> Next {
```
> [!IMPORTANT]
-> `Picker` is very sensitive to parse order, esp. for positional args (they're parsed sequentially). If you need to parse positional args, make sure all **flag args** have been picked and consumed first.
+> `Picker` is sensitive to parse order, especially for positional args — it parses sequentially. If you need to parse positional args, make sure all **flag arguments** are picked and consumed first.
## Handling Edge Cases with `pick_or_route`
-As the old saying goes: "Never trust your users." To handle missing required args, type mismatches, etc., `pick_or_route` routes the execution chain to a dedicated error-handling type.
+As the saying goes: "never trust your users." To handle missing required params, type mismatches, etc., `pick_or_route` routes the chain to a dedicated error handler.
-A simple example:
+Here's a simple example:
```rust
// Features: ["parser", "extra_macros"]
+@@@use mingling::macros::buffer;
@@@use mingling::macros::route;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
@@@pack!(ResultName = String);
@@ -150,29 +151,20 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
.pick_or_route(["--name", "-n"], ErrorNoName::default())
.unpack();
- // Use route! macro to unpack pick_result
+ // Use route! macro to expand pick_result
let name = route!(pick_result);
ResultName::new(name).into()
}
-#[renderer]
-fn render_no_name(_prev: ErrorNoName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: No name provided.").ok();
- r
-}
-
-#[renderer]
-fn render_name(prev: ResultName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultName) {
+ r_println!("Hello, {}!", *result);
}
```
-With `pick_or_route`, the code gets a bit more complex: `.unpack()` no longer returns the value directly, but `Result`.
+With `pick_or_route`, the code becomes more involved: `.unpack()` no longer returns the value directly, but `Result`.
-However, Mingling's `extra_macros` feature provides the `route!` macro to simplify unwrapping — it just omits some boilerplate:
+However, **Mingling**'s `extra_macros` feature provides the `route!` macro for simplified expansion. It's not complex — it just reduces boilerplate:
```rust
// Features: ["parser", "extra_macros"]
@@ -204,7 +196,7 @@ let name = match pick_result {
## Post-processing Extracted Values
-After picking user input, you can use `after` to process the value immediately:
+After picking user input with `pick`, you can use `after` to process it immediately:
```rust
// Features: ["parser"]
@@ -215,7 +207,7 @@ After picking user input, you can use `after` to process the value immediately:
fn handle_greet_entry(prev: EntryGreet) -> Next {
let name = prev
.pick_or(["--name", "-n"], "World")
- // Format immediately after extracting --name
+ // Format immediately after picking --name
.after(|name: String| {
name.replace(['-', '_', '.'], " ")
.to_lowercase()
@@ -228,10 +220,11 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
}
```
-Similarly, use `after_or_route` to handle format errors in input args:
+Similarly, you can use `after_or_route` to handle input format errors:
```rust
// Features: ["parser", "extra_macros"]
+@@@use mingling::macros::buffer;
@@@use mingling::macros::route;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
@@@pack!(ResultName = String);
@@ -254,35 +247,31 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
ResultName::new(name).into()
}
-#[renderer]
-fn render_name_too_long(prev: ErrorNameTooLong) -> RenderResult {
- let mut r = RenderResult::new();
+#[renderer(buffer)]
+fn render_name_too_long(prev: ErrorNameTooLong) {
let len = *prev;
- writeln!(r, "Error: name too long (length: {} > 32)", len).ok();
- r
+ r_println!("Error: name too long (length: {} > 32)", len);
}
-#[renderer]
-fn render_name(prev: ResultName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_name(prev: ResultName) {
+ r_println!("Hello, {}!", *prev);
}
```
## Boolean Parsing
-`Picker` can parse bools too, with two modes: implicit and explicit.
+`Picker` can also parse booleans, in two modes:
| Mode | Format |
| -------- | ----------------------------------- |
| Implicit | `--confirmed` |
| Explicit | `--confirm true` or `--confirm yes` |
-- Using `.pick::(flag)` → implicit: flag present means `true`
-- Using `.pick::(flag)` or `.pick::(flag)` → explicit
+- `.pick::(flag)` uses implicit mode: the flag being present means `true`
+- `.pick::(flag)` or `.pick::(flag)` uses explicit mode
-Implicit is fine for most cases, but for important confirmations, explicit logic is more semantic.
+Implicit mode is generally sufficient, but for important confirmations, explicit logic is more idiomatic.
```rust
// Features: ["parser"]
@@ -302,7 +291,7 @@ fn handle_entry(prev: EntryTest) -> Next {
## Special Usage: `usize` Parsing
-Mingling provides a special `usize` feature: parsing strings like `25G`, `32mib`, etc.
+**Mingling** provides a special `usize` feature: parsing strings like `25G`, `32mib`, etc.
```rust
// Features: ["parser"]
@@ -315,12 +304,13 @@ fn parse_size() {
}
```
-## Custom Parseable Types
+## Custom Pickable Types
-Implement the `Pickable` trait to make your type parseable by `Picker` — this is where Picker's extensibility comes from.
+You can make your types pickable by `Picker` using the `Pickable` trait — this is where `Picker`'s extensibility comes from.
```rust
// Features: ["parser"]
+@@@use mingling::macros::buffer;
@@@use mingling::parser::{Pickable, Argument};
@@@use mingling::Flag;
#[derive(Default, Clone)]
@@ -348,12 +338,9 @@ fn handle_connect_entry(prev: EntryConnect) -> Next {
ResultConnected::new(address).into()
}
-#[renderer]
-fn render_connected(prev: ResultConnected) -> RenderResult {
- let mut r = RenderResult::new();
- let addr = prev.inner;
- writeln!(r, "Connected: IP: {} PORT: {}", addr.ip, addr.port).ok();
- r
+#[renderer(buffer)]
+fn render_connected(addr: ResultConnected) {
+ r_println!("Connected: IP: {} PORT: {}", addr.ip, addr.port);
}
```
@@ -366,10 +353,11 @@ Connected: IP: 127.0.0.1 PORT: 8080
## Auto-implementing Pickable for Enums
-To implement `Pickable` for an enum, just make it implement `EnumTag`, then implement `PickableEnum`:
+To make an enum `Pickable`, just implement `EnumTag` on it, then implement `PickableEnum`:
```rust
// Features: ["parser"]
+@@@use mingling::macros::buffer;
@@@use mingling::parser::PickableEnum;
@@@use mingling::EnumTag;
#[derive(Debug, Default, EnumTag)]
@@ -390,15 +378,13 @@ fn handle_eat_entry(prev: EntryEat) -> Next {
ResultFruit::new(fruit).into()
}
-#[renderer]
-fn render_fruit(prev: ResultFruit) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Picked fruit: {:?}", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_fruit(prev: ResultFruit) {
+ r_println!("Picked fruit: {:?}", *prev);
}
```
-That covers all the features of `Picker`.
+That covers all the usages of `Picker`.
Written by @Weicao-CatilGrass
diff --git a/docs/pages/7-argument-parse-clap.md b/docs/pages/7-argument-parse-clap.md
index 86fce35..dcebd65 100644
--- a/docs/pages/7-argument-parse-clap.md
+++ b/docs/pages/7-argument-parse-clap.md
@@ -25,6 +25,7 @@ Add `#[dispatcher_clap]` on a `clap::Parser` struct to auto-generate a Dispatche
// Dependencies:
// clap = "4"
@@@ use mingling::macros::dispatcher_clap;
+@@@ use mingling::macros::buffer;
#[derive(Default, clap::Parser, Grouped)]
#[dispatcher_clap("greet", CMDGreet, help = true, error = ErrorGreetParsed)]
pub struct EntryGreet {
@@ -34,23 +35,19 @@ pub struct EntryGreet {
repeat: i32,
}
-#[renderer]
-fn render_greet(greet: EntryGreet) -> RenderResult {
- let mut r = RenderResult::new();
+#[renderer(buffer)]
+fn render_greet(greet: EntryGreet) {
let count = greet.repeat.max(0) as usize;
- write!(r, "Hello, ").ok();
+ r_print!("Hello, ");
for _ in 0..count {
- write!(r, "{} ", greet.name).ok();
+ r_print!("{} ", greet.name);
}
- writeln!(r, "!").ok();
- r
+ r_println!("!");
}
-#[renderer]
-fn render_greet_parse_failed(err: ErrorGreetParsed) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "{}", *err).ok();
- r
+#[renderer(buffer)]
+fn render_greet_parse_failed(err: ErrorGreetParsed) {
+ r_println!("{}", *err);
}
```
@@ -62,6 +59,7 @@ If you need `--help` support, register `BasicProgramSetup` in main and set the c
// Features: ["clap"]
// Dependencies:
// clap = "4"
+@@@use mingling::macros::buffer;
@@@use mingling::setup::BasicProgramSetup;
@@@use mingling::macros::dispatcher_clap;
@@@#[derive(Default, clap::Parser, Grouped)]
@@ -69,11 +67,9 @@ If you need `--help` support, register `BasicProgramSetup` in main and set the c
@@@pub struct EntryGreet {
@@@ name: String,
@@@}
-@@@#[renderer]
-@@@fn render_greet(greet: EntryGreet) -> RenderResult {
-@@@ let mut r = RenderResult::new();
-@@@ write!(r, "Hello, {}!", greet.name).ok();
-@@@ r
+@@@#[renderer(buffer)]
+@@@fn render_greet(greet: EntryGreet) {
+@@@ r_println!("Hello, {}!", greet.name);
@@@}
fn main() {
let mut program = ThisProgram::new();
diff --git a/docs/pages/9-error-handling.md b/docs/pages/9-error-handling.md
index 3e004f2..f6e05e3 100644
--- a/docs/pages/9-error-handling.md
+++ b/docs/pages/9-error-handling.md
@@ -38,23 +38,20 @@ fn handle_greet(args: EntryGreet) -> Next {
Then write separate Renderers:
```rust
+@@@use mingling::macros::buffer;
@@@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) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
}
-#[renderer]
-fn render_error_name_empty(err: ErrorNameEmpty) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: {}", *err).ok();
- r
+#[renderer(buffer)]
+fn render_error_name_empty(err: ErrorNameEmpty) {
+ r_println!("Error: {}", *err);
}
```
@@ -63,6 +60,7 @@ Each Renderer does its own job; what the user sees depends on what the Chain ret
## Complete Example
```rust
+@@@use mingling::macros::buffer;
dispatcher!("greet", CMDGreet => EntryGreet);
pack!(ResultGreeting = String);
@@ -78,18 +76,14 @@ fn handle_greet(args: EntryGreet) -> Next {
}
}
-#[renderer]
-fn render_greeting(result: ResultGreeting) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *result).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultGreeting) {
+ r_println!("Hello, {}!", *result);
}
-#[renderer]
-fn render_error_name_empty(err: ErrorNameEmpty) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: {}", *err).ok();
- r
+#[renderer(buffer)]
+fn render_error_name_empty(err: ErrorNameEmpty) {
+ r_println!("Error: {}", *err);
}
fn main() {
diff --git a/docs/pages/advanced/2-structural-renderer.md b/docs/pages/advanced/2-structural-renderer.md
index 910b197..b54af22 100644
--- a/docs/pages/advanced/2-structural-renderer.md
+++ b/docs/pages/advanced/2-structural-renderer.md
@@ -27,6 +27,7 @@ After enabling `StructuralRendererSetup`, use `pack_structural!` instead of `pac
// Features: ["structural_renderer"]
// Dependencies:
// serde = "1"
+@@@use mingling::macros::buffer;
@@@use mingling::setup::StructuralRendererSetup;
@@@dispatcher!("render", CMDRender => EntryRender);
@@ -40,11 +41,9 @@ fn handle_render(args: EntryRender) -> Next {
ResultInfo::new((name, age)).into()
}
-#[renderer]
-fn render_info(r: ResultInfo) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "{:?}", *r).ok();
- result
+#[renderer(buffer)]
+fn render_info(r: ResultInfo) {
+ r_println!("{:?}", *r);
}
```
@@ -68,6 +67,7 @@ The default output from `pack_structural!` includes an `inner` field. For full c
// Features: ["structural_renderer"]
// Dependencies:
// serde = "1"
+@@@use mingling::macros::buffer;
@@@use mingling::prelude::*;
@@@use mingling::setup::StructuralRendererSetup;
@@@use mingling::StructuralData;
@@ -87,11 +87,9 @@ fn handle_render(args: EntryRender) -> Next {
Info { name, age }.to_render()
}
-#[renderer]
-fn render_info(info: Info) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "{} is {} years old", info.name, info.age).ok();
- r
+#[renderer(buffer)]
+fn render_info(info: Info) {
+ r_println!("{} is {} years old", info.name, info.age);
}
@@@
@@@fn main() {
diff --git a/docs/pages/other/naming_rule.md b/docs/pages/other/naming_rule.md
index 089a711..1175ae0 100644
--- a/docs/pages/other/naming_rule.md
+++ b/docs/pages/other/naming_rule.md
@@ -166,6 +166,7 @@ fn handle_remote_add(args: EntryRemoteAdd, cwd: &ResCurrentDir, db: &mut ResData
## Complete Example
```rust
+@@@use mingling::macros::buffer;
@@@ #[derive(Default, Clone)]
@@@ struct ResDatabase { }
@@@ impl ResDatabase { fn has_remote(&self, remote: &String) -> bool { true } }
@@ -192,21 +193,17 @@ fn handle_state_operation_remotes(state: StateOperationRemotes, db: &ResDatabase
}
// Result rendering
-#[renderer]
-fn render_remote_added(result: ResultRemoteAdded) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Remote added: {}", result.inner).ok();
- r
+
+#[renderer(buffer)]
+fn render_remote_added(result: ResultRemoteAdded) {
+ r_println!("Remote added: {}", result.inner);
}
// Error rendering
-#[renderer]
-fn render_error_repository_not_found(err: ErrorRepositoryNotFound) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: remote '{}' not found", err.inner).ok();
- r
+#[renderer(buffer)]
+fn render_error_repository_not_found(err: ErrorRepositoryNotFound) {
+ r_println!("Error: remote '{}' not found", err.inner);
}
-
```
diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs
index d1691fb..b6c9a5a 100644
--- a/mingling/src/lib.rs
+++ b/mingling/src/lib.rs
@@ -223,6 +223,12 @@ pub mod prelude {
/// Like `pack!` but also marks the type for structured output
#[cfg(all(feature = "macros", feature = "structural_renderer"))]
pub use mingling_macros::pack_structural;
+ /// `r_print!` - Prints text to a `RenderResult` buffer (without newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_print;
+ /// `r_println!` - Prints text to a `RenderResult` buffer (with newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_println;
/// Re-export of the `completion` macro for generating completion entries.
#[cfg(all(feature = "macros", feature = "comp"))]
@@ -237,8 +243,4 @@ pub mod prelude {
#[cfg(feature = "picker")]
pub use crate::picker::EntryPicker;
-
- /// Used to enable the `writeln!` macro for `RenderResult`
- #[cfg(feature = "core")]
- pub use std::io::Write;
}
--
cgit