aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/_zh_CN/pages/10-help.md26
-rw-r--r--docs/_zh_CN/pages/11-resource-system.md18
-rw-r--r--docs/_zh_CN/pages/14-testing.md2
-rw-r--r--docs/_zh_CN/pages/4-render-result.md49
-rw-r--r--docs/_zh_CN/pages/5-multiple-commands.md17
-rw-r--r--docs/_zh_CN/pages/6-argument-parse-picker.md45
-rw-r--r--docs/_zh_CN/pages/7-argument-parse-clap.md30
-rw-r--r--docs/_zh_CN/pages/9-error-handling.md34
-rw-r--r--docs/_zh_CN/pages/advanced/2-structural-renderer.md18
-rw-r--r--docs/_zh_CN/pages/other/naming_rule.md17
-rw-r--r--docs/dev/pages/issues/add-picker2.md14
-rw-r--r--docs/dev/pages/issues/remove-r-print-macro.md12
-rw-r--r--docs/example-pages/examples.json15
-rw-r--r--docs/pages/10-help.md26
-rw-r--r--docs/pages/11-resource-system.md18
-rw-r--r--docs/pages/14-testing.md2
-rw-r--r--docs/pages/4-render-result.md53
-rw-r--r--docs/pages/5-multiple-commands.md17
-rw-r--r--docs/pages/6-argument-parse-picker.md116
-rw-r--r--docs/pages/7-argument-parse-clap.md30
-rw-r--r--docs/pages/9-error-handling.md34
-rw-r--r--docs/pages/advanced/2-structural-renderer.md18
-rw-r--r--docs/pages/other/naming_rule.md19
-rw-r--r--docs/res/icon3.pngbin0 -> 752608 bytes
-rw-r--r--docs/res/icon3_1024.pngbin0 -> 262830 bytes
25 files changed, 300 insertions, 330 deletions
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 <command>").ok();
- writeln!(r, "Commands:").ok();
- writeln!(r, " greet Say hello").ok();
- r
+#[help(buffer)]
+fn help_root(entry: ErrorDispatcherNotFound) {
+ r_println!("Usage: my-cli <command>");
+ 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<String>`——它存的是用户输入的那些没匹配到的命令。你只需要给它写一个 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 {
<p align="center" style="font-size: 0.85em; color: gray;">
Written by @Weicao-CatilGrass
</p>
+````
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/dev/pages/issues/add-picker2.md b/docs/dev/pages/issues/add-picker2.md
index 6fe4418..a2b5a10 100644
--- a/docs/dev/pages/issues/add-picker2.md
+++ b/docs/dev/pages/issues/add-picker2.md
@@ -90,11 +90,11 @@ pub struct PickerResult<Tuple> {
## 🕘 Progress
- [x] In Progress
- - [x] Added `Picker` struct and related call chain
- - [x] Added `parselib` providing parsing logic
- - [x] Added `Pickable` for extensibility
- - [ ] Comprehensive testing!
- - [ ] Improve documentation
- - [ ] Add examples
- - [ ] Update README
+ - [x] Added `Picker` struct and related call chain
+ - [x] Added `parselib` providing parsing logic
+ - [x] Added `Pickable` for extensibility
+ - [x] Comprehensive testing!
+ - [ ] Improve documentation
+ - [x] Add examples
+ - [ ] Update README
- [ ] Complete
diff --git a/docs/dev/pages/issues/remove-r-print-macro.md b/docs/dev/pages/issues/remove-r-print-macro.md
index d6f6bff..43d2740 100644
--- a/docs/dev/pages/issues/remove-r-print-macro.md
+++ b/docs/dev/pages/issues/remove-r-print-macro.md
@@ -89,9 +89,9 @@ As for rendering in logic functions like `#[chain]`, that should be handled by a
## 🕘 Progress
- [x] In Progress
- - [x] Remove `r_println!` and `r_print!` macros
- - [x] Modify `#[renderer]` and `#[help]` macros, remove implicit injection
- - [x] Provide **no-return-value mode** and **RenderResult return value mode** for `#[renderer]` and `#[help]` macros
- - [ ] Add new simplified syntax
- - [x] Update documentation and test cases, ensure **all pass**
-- [ ] Complete
+ - [x] Remove `r_println!` and `r_print!` macros
+ - [x] Modify `#[renderer]` and `#[help]` macros, remove implicit injection
+ - [x] Provide **no-return-value mode** and **RenderResult return value mode** for `#[renderer]` and `#[help]` macros
+ - [x] Add new simplified syntax
+ - [x] Update documentation and test cases, ensure **all pass**
+- [x] Complete
diff --git a/docs/example-pages/examples.json b/docs/example-pages/examples.json
index a539011..2a07365 100644
--- a/docs/example-pages/examples.json
+++ b/docs/example-pages/examples.json
@@ -31,6 +31,21 @@
]
},
{
+ "id": "example-argument-picker",
+ "name": "Argument Picker",
+ "icon": "📋",
+ "category": "parsing",
+ "desc": "Demonstrates how to use Mingling's `picker` feature and `Picker` to extract typed arguments from the command line.\n",
+ "tags": [
+ "arg-picker",
+ "SinglePickable"
+ ],
+ "files": [
+ "src/main.rs",
+ "Cargo.toml"
+ ]
+ },
+ {
"id": "example-async-support",
"name": "Async Support",
"icon": "⚡",
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 <command>").ok();
- writeln!(r, "Commands:").ok();
- writeln!(r, " greet Say hello").ok();
- r
+#[help(buffer)]
+fn help_root(entry: ErrorDispatcherNotFound) {
+ r_println!("Usage: my-cli <command>");
+ 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<String>`—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
</p>
-In previous tutorials, we extracted args manually from `EntryGreet.inner` (`Vec<String>`).
+In previous tutorials, we manually extracted parameters from `EntryGreet.inner` (`Vec<String>`).
```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<String>`: 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<String>`. 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<Value, Route>`.
+With `pick_or_route`, the code becomes more involved: `.unpack()` no longer returns the value directly, but `Result<Value, Route>`.
-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::<bool>(flag)` → implicit: flag present means `true`
-- Using `.pick::<Yes>(flag)` or `.pick::<True>(flag)` → explicit
+- `.pick::<bool>(flag)` uses implicit mode: the flag being present means `true`
+- `.pick::<Yes>(flag)` or `.pick::<True>(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`.
<p align="center" style="font-size: 0.85em; color: gray;">
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);
}
-
```
<p align="center" style="font-size: 0.85em; color: gray;">
diff --git a/docs/res/icon3.png b/docs/res/icon3.png
new file mode 100644
index 0000000..04ea5e9
--- /dev/null
+++ b/docs/res/icon3.png
Binary files differ
diff --git a/docs/res/icon3_1024.png b/docs/res/icon3_1024.png
new file mode 100644
index 0000000..868f8ad
--- /dev/null
+++ b/docs/res/icon3_1024.png
Binary files differ