aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/3-features
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-28 22:39:59 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-28 22:39:59 +0800
commit85ee549f68449bc70a7f1271a93ad26a8207ee40 (patch)
treebfb0b678d0f96c06b196417fd612a9cad2baf7fe /docs/pages/3-features
parent5bf4209bd138faf76e3bd316fdfa128a08f2bb2e (diff)
Rebuild and rewrite the documentation site infrastructure
Diffstat (limited to 'docs/pages/3-features')
-rw-r--r--docs/pages/3-features/1-parser.md376
-rw-r--r--docs/pages/3-features/2-general-renderer.md75
-rw-r--r--docs/pages/3-features/3-comp.md118
-rw-r--r--docs/pages/3-features/4-async.md6
-rw-r--r--docs/pages/3-features/5-clap-parser.md6
5 files changed, 0 insertions, 581 deletions
diff --git a/docs/pages/3-features/1-parser.md b/docs/pages/3-features/1-parser.md
deleted file mode 100644
index 0b5ded5..0000000
--- a/docs/pages/3-features/1-parser.md
+++ /dev/null
@@ -1,376 +0,0 @@
-<h1 align="center">Parser</h1>
-<p align="center">
- Mingling's Features
-</p>
-
----
-
-## Enable Feature
-
-`parser` is a feature provided by **Mingling**. You can enable it in the following way:
-
-```toml
-[dependencies]
-mingling = {
- version = "...",
- features = ["parser"]
-}
-```
-
-## Usage
-
-`parser` provides the ability to transform user input into structured data. Its core concept is **pick**.
-
-The following demonstrates the parsing approach without using a `Picker`:
-
-```rust
-#[chain]
-fn parse_hello(prev: HelloEntry) -> NextProcess {
- let args = &*prev;
- let first = args.first().cloned().unwrap_or_else(|| "World".to_string());
- ParsedHello::new(first).to_render()
-}
-```
-
-This is how it looks when using `Picker`:
-
-```rust
-#[chain]
-fn parse_hello(prev: HelloEntry) -> NextProcess {
- // Create Picker
- let picker = Picker::<ThisProgram>::new(prev.inner);
-
- // Extract the first argument from the Picker,
- // fallback to "World" if it doesn't exist
- let first = picker
- .pick_or((), "World")
- .unpack_directly();
-
- ParsedHello::new(first).to_render()
-}
-```
-
-You might notice that using `Picker` can sometimes make statements more verbose, but this is only when parsing a small number of arguments. What if we complicate the scenario?
-
-Suppose we want to design the following commands:
-
-```bash
-# Eat 1 apple weighing at least 20
-fruit eat Apple --min-weight 20
-
-# Eat 10 apples weighing at least 20
-fruit eat Apple --min-weight 20 --count 10
-
-# Eat 1 apple weighing between 10 and 20
-fruit eat Apple --min-weight 10 --max-weight 20
-
-# Eat 1 apple weighing between 20 and 10 (incorrect logic)
-fruit eat Apple --min-weight 20 --max-weight 10
-
-# When no specific fruit is specified, eat banana
-fruit eat --count 5
-```
-
-For this complex scenario, the `Picker` comes into play!
-
-We first design the type `ParsedEatFruit`
-
-```rust
-#[derive(Debug, Default, Groupped)]
-struct ParsedEatFruit {
- count: i16,
- weight_range: (i16, i16),
- fruit_type: Fruit,
-}
-
-#[derive(Debug, Default, EnumTag)]
-enum Fruit {
- #[default]
- Banana,
- Apple,
- Orange,
-}
-```
-
-Then create the basic binary program `fruit`
-
-```rust
-use mingling::{
- EnumTag, Groupped,
- macros::{chain, dispatcher, gen_program, r_println, renderer},
- parser::PickableEnum,
-};
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(FruitEatCommand);
- program.exec();
-}
-
-dispatcher!("eat",
- FruitEatCommand => FruitEatEntry);
-
-#[derive(Debug, Default, Groupped)]
-struct ParsedEatFruit {
- count: i16,
- weight_range: (i16, i16),
- fruit_type: Fruit,
-}
-
-#[derive(Debug, Default, EnumTag)]
-enum Fruit {
- #[default]
- Banana,
- Apple,
- Orange,
-}
-
-// Implement PickableEnum for Fruit to make it pickable
-impl PickableEnum for Fruit {}
-
-#[chain]
-fn parse_fruit_eat(prev: FruitEatEntry) -> NextProcess {
- // ...
-}
-
-#[renderer]
-fn render_fruit_eat(prev: ParsedEatFruit) {
- let weight_str = match prev.weight_range {
- (min, max) if min == 0 && max > 0 => {
- format!("up to {}.", max)
- }
- (min, max) if min > 0 && max == 0 => {
- format!("at least {}.", min)
- }
- (min, max) if min > 0 && max > 0 && min != max => {
- format!("between {} and {}.", min, max)
- }
- (min, max) if min > 0 && max > 0 && min == max => {
- format!("exactly {}.", min)
- }
- _ => "unknown.".to_string(),
- };
-
- let fruit_type = if prev.count > 1 {
- format!("{}s", prev.fruit_type.enum_info().0)
- } else {
- prev.fruit_type.enum_info().0.to_string()
- };
-
- r_println!(
- "I ate {} {}, each weighing {}",
- prev.count,
- fruit_type,
- weight_str
- );
-}
-
-gen_program!();
-```
-
-Now focus on writing the logic for `parse_fruit_eat`:
-
-> Review the business logic:
->
-> 1 - The default fruit is Banana
->
-> 2 - The default quantity is 1
->
-> 3 - The default weight is (0, 0)
->
-> 4 - When `max-weight` is less than `min-weight`, the business logic is in error
-
-Before writing the code, define the error type `MinGreaterThanMax` and the related `Renderer`
-
-```rust
-pack!(MinGreaterThanMax = ());
-
-#[renderer]
-fn render_min_greater_than_max(_prev: MinGreaterThanMax) {
- r_println!("Error: min weight cannot be greater than max weight.");
-}
-```
-
-Now start writing the logic:
-
-```rust
-#[chain]
-fn parse_fruit_eat(prev: FruitEatEntry) -> NextProcess {
- let picker = Picker::new(prev.inner);
- let mut min_weight: i16 = 0;
- let parsed = picker
- .pick_or(["--count", "-n"], 1)
- .pick::<i16>("--min-weight") // default: 0
- .after(|min| {
- // Copy `min` to external variable
- min_weight = min;
- min
- })
- .pick_or::<i16>("--max-weight", min_weight) // default: min_weight
- .after_or_route(|max| {
- // Check if `max` is valid
- if max < &min_weight {
- Err(MinGreaterThanMax::default())
- } else {
- Ok(max.clone())
- }
- })
- .pick(())
- // Since there's a possibility of being routed,
- // don't use `unpack_directly`
- .unpack();
-
- match parsed {
- Ok((count, min_weight, max_weight, fruit_type)) => {
- let parsed = ParsedEatFruit {
- count,
- weight_range: (min_weight, max_weight),
- fruit_type,
- };
-
- AnyOutput::new(parsed).route_renderer()
- }
- Err(route) => route.to_render(),
- }
-}
-```
-
-Complete code:
-
-```rust
-use mingling::{
- AnyOutput, EnumTag, Groupped,
- macros::{chain, dispatcher, gen_program, pack, r_println, renderer},
- parser::{PickableEnum, Picker},
-};
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(FruitEatCommand);
- program.exec();
-}
-
-dispatcher!("eat",
- FruitEatCommand => FruitEatEntry);
-
-#[derive(Debug, Default, Groupped)]
-struct ParsedEatFruit {
- count: i16,
- weight_range: (i16, i16),
- fruit_type: Fruit,
-}
-
-#[derive(Debug, Default, EnumTag)]
-enum Fruit {
- #[default]
- Banana,
- Apple,
- Orange,
-}
-
-impl PickableEnum for Fruit {}
-
-pack!(MinGreaterThanMax = ());
-
-#[chain]
-fn parse_fruit_eat(prev: FruitEatEntry) -> NextProcess {
- let picker = Picker::new(prev.inner);
- let mut min_weight: i16 = 0;
- let (count, min_weight, max_weight, fruit_type) = route! {
- picker
- // Pick count
- .pick_or::<i16>(["--count", "-n"], 1 as i16)
-
- // Pick min/max weight
- .pick::<i16>("--min-weight")
- .after(|min| {
- min_weight = min;
- min
- })
-
- .pick_or::<i16>("--max-weight", min_weight)
- .after_or_route(|max| {
- if max < &min_weight {
- Err(MinGreaterThanMax::default().to_render())
- } else {
- Ok(max.clone())
- }
- })
-
- // Pick Type
- .pick(())
- .unpack()
- };
-
- ParsedEatFruit {
- count,
- weight_range: (min_weight, max_weight),
- fruit_type,
- }
- .to_render()
-}
-
-#[renderer]
-fn render_min_greater_than_max(_prev: MinGreaterThanMax) {
- r_println!("Error: min weight cannot be greater than max weight.");
-}
-
-#[renderer]
-fn render_fruit_eat(prev: ParsedEatFruit) {
- let weight_str = match prev.weight_range {
- (min, max) if min == 0 && max > 0 => {
- format!("up to {}.", max)
- }
- (min, max) if min > 0 && max == 0 => {
- format!("at least {}.", min)
- }
- (min, max) if min > 0 && max > 0 && min != max => {
- format!("between {} and {}.", min, max)
- }
- (min, max) if min > 0 && max > 0 && min == max => {
- format!("exactly {}.", min)
- }
- _ => "unknown.".to_string(),
- };
-
- let fruit_type = if prev.count > 1 {
- format!("{}s", prev.fruit_type.enum_info().0)
- } else {
- prev.fruit_type.enum_info().0.to_string()
- };
-
- r_println!(
- "I ate {} {}, each weighing {}",
- prev.count,
- fruit_type,
- weight_str
- );
-}
-
-gen_program!();
-```
-
-Now compile the program and run it:
-
-```bash
-cargo install --path ./
-```
-
-Running results:
-
-```bash
-~> fruit eat Apple --min-weight 20
-I ate 1 Apple, each weighing exactly 20.
-
-~> fruit eat Apple --min-weight 20 --count 10
-I ate 10 Apples, each weighing exactly 20.
-
-~> fruit eat Apple --min-weight 10 --max-weight 20
-I ate 1 Apple, each weighing between 10 and 20.
-
-~> fruit eat Apple --min-weight 20 --max-weight 10
-Error: min weight cannot be greater than max weight.
-
-~> fruit eat --count 5
-I ate 5 Bananas, each weighing unknown.
-```
diff --git a/docs/pages/3-features/2-general-renderer.md b/docs/pages/3-features/2-general-renderer.md
deleted file mode 100644
index c3b81a2..0000000
--- a/docs/pages/3-features/2-general-renderer.md
+++ /dev/null
@@ -1,75 +0,0 @@
-<h1 align="center">General Renderer</h1>
-<p align="center">
- Mingling's Features
-</p>
-
----
-
-## Enable Feature
-
-`general_renderer` is a feature provided by **Mingling**. You can enable it in the following way:
-
-```toml
-[dependencies]
-mingling = {
- version = "...",
- features = ["general_renderer"]
-}
-```
-
-## Setup
-
-`general_renderer` requires you to implement the `serde::Serialize` trait for **all** structs, so your project needs to include `serde`
-
-```toml
-[dependencies]
-serde = {
- version = "1",
- features = ["derive"]
-}
-```
-
-For types wrapped with the `pack!` macro, `serde::Serialize` will be automatically implemented
-
-```rust
-pack!(YourInfo = ()); // Auto derive `serde::Serialize`
-```
-
-For types using the derive macro `Groupped`, you need to manually implement `serde::Serialize`
-
-```rust
-#[derive(Default, Groupped, Serialize)]
-struct YourInfo {
- name: String,
- age: i32,
-}
-```
-
-> [!Tip]
-> If there are types that do not implement `serde::Serialize`, compilation will fail.
-
-## Import GeneralRendererSetup
-
-`general_renderer` provides a Setup type called `GeneralRendererSetup`.
-
-After importing it into your program,
-user inputs like `--json`, `--yaml`, `--toml`, `--ron`, `--json-pretty`, and `--ron-pretty` will be automatically recognized.
-
-During the **rendering phase**, instead of the **default renderer**, the serialized content will be displayed to the terminal.
-
-```rust
-fn main() {
- let mut program = ThisProgram::new();
-
- // Add General Renderer
- program.with_setup(GeneralRendererSetup);
-
- // Add Dispatchers
- program.with_dispatchers((
- // Your dispatchers
- ));
-
- // Execute
- program.exec();
-}
-```
diff --git a/docs/pages/3-features/3-comp.md b/docs/pages/3-features/3-comp.md
deleted file mode 100644
index 259e174..0000000
--- a/docs/pages/3-features/3-comp.md
+++ /dev/null
@@ -1,118 +0,0 @@
-<h1 align="center">Completion</h1>
-<p align="center">
- Mingling's Features
-</p>
-
----
-
-## Enable Feature
-
-`comp` is the command-line completion feature provided by **Mingling**. Its approach is not static completion but rather dynamic completion by invoking your program itself.
-
-Enable this feature as follows:
-
-```toml
-[dependencies]
-mingling = {
- version = "...",
- features = ["comp"]
-}
-```
-
-## Setup
-
-Once `comp` is enabled, `gen_program!` will automatically generate a `CompletionDispatcher`, which is a command with the node `__comp`: the completion script will call this subcommand.
-
-Add this [Dispatcher](pages/2-basic/3-dispatcher) to your [Program](pages/2-basic/1-program):
-
-```rust
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CompletionDispatcher);
- program.exec();
-}
-```
-
-## Usage
-
-You can use the `completion!` macro to bind completion logic to your command entry point. The syntax is as follows:
-
-```rust
-// Define Dispatcher
-dispatcher!("test-comp",
- TestCompletionCommand => TestCompletionEntry
-);
-
-// Establish completion logic, bound to `TestCompletionEntry`
-#[completion(TestCompletionEntry)]
-fn comp_test_comp_cmd(_ctx: &ShellContext) -> Suggest {
- suggest!()
-}
-```
-
-You can obtain the context passed by the shell via `ShellContext` and return the generated suggestions:
-
-```rust
-#[completion(TestCompletionEntry)]
-fn comp_test_comp_cmd(ctx: &ShellContext) -> Suggest {
- if ctx.current_word.starts_with("-") {
- // Comp flags
- return suggest!(
- "--name": "Names",
- "--age": "Age"
- );
- }
-
- if ctx.previous_word == "--name" {
- return suggest!("Bob", "Alice"); // Comp names
- }
-
- if ctx.previous_word == "--age" {
- return suggest!(); // If typing age, suggest nothing
- }
-
- suggest!() // Comp nothing
-}
-```
-
-> 🎬 Logic
->
-> When the user inputs `bin test-<TAB>`, it completes to `bin test-comp`.
->
-> When the user inputs `bin test-comp -<TAB>`, it suggests `--age` / `--name`.
->
-> When the user inputs `bin test-comp --name <TAB>`, it suggests `Bob` / `Alice`.
->
-> In other cases, no suggestions are generated.
-
-## Generate Completion Script
-
-Any shell requires registering a relevant completion script to enable your command's completion capability. However, **Mingling** provides a related build script:
-
-Please add the following to `build-dependencies` in your `Cargo.toml`:
-
-```toml
-[build-dependencies]
-mingling = { version = "...", features = ["comp"] }
-```
-
-Next, call the following logic in your project's `build.rs`:
-
-```rust
-use mingling::build::build_comp_scripts;
-
-fn main() {
- // Generate completion scripts for the current program
- // build_comp_scripts().unwrap();
-
- // Or specify a specific name
- build_comp_scripts("your_cmd").unwrap();
-}
-```
-
-`build_comp_scripts` will generate the corresponding completion scripts based on your platform and output them to the `target` directory.
-
-> [!Note]
-> The completion script does not contain the actual completion logic;
->
-> it is just a thin invocation layer.
diff --git a/docs/pages/3-features/4-async.md b/docs/pages/3-features/4-async.md
deleted file mode 100644
index 08cbb9a..0000000
--- a/docs/pages/3-features/4-async.md
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1 align="center">Async</h1>
-<p align="center">
- Mingling's Features
-</p>
-
----
diff --git a/docs/pages/3-features/5-clap-parser.md b/docs/pages/3-features/5-clap-parser.md
deleted file mode 100644
index 5cb68e6..0000000
--- a/docs/pages/3-features/5-clap-parser.md
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1 align="center">Clap Parser</h1>
-<p align="center">
- Mingling's Features
-</p>
-
----