aboutsummaryrefslogtreecommitdiff
path: root/docs/pages
diff options
context:
space:
mode:
Diffstat (limited to 'docs/pages')
-rw-r--r--docs/pages/1-creating-your-first-program.md258
-rw-r--r--docs/pages/2-implementing-fallbacks.md141
-rw-r--r--docs/pages/3-parsing-complex-arguments.md364
-rw-r--r--docs/pages/4-implementing-help-display.md4
-rw-r--r--docs/pages/5-implementing-completion.md4
5 files changed, 0 insertions, 771 deletions
diff --git a/docs/pages/1-creating-your-first-program.md b/docs/pages/1-creating-your-first-program.md
deleted file mode 100644
index 7348805..0000000
--- a/docs/pages/1-creating-your-first-program.md
+++ /dev/null
@@ -1,258 +0,0 @@
-<h1 align="center">Creating your first Program</h1>
-<p align="center">
- Learn <b>Mingling</b> and use it to create your first command-line program
-</p>
-
-## Intro
-
- This chapter will guide you through **Mingling** step by step.
-
- Before we start, let me explain what **Mingling** can do:
-
- Without extra features, it is a sub-command dispatch system based on `proc-macro`: it matches user input, finds & creates the corresponding data, then pushes that data into a dispatcher that continually transforms its type. When the data can no longer be transformed, the program renders the final result to the terminal.
-
- In other words, you need to understand a new dev paradigm: **a fully type-based dispatch system**. This may feel **frustrating** at first, but once you get the hang of it, you'll be able to write CLI apps that are super easy to modify and extend.
-
-
-
-## Creating a Basic Program
-
- Next I'll walk you through creating a basic program—I assume you already have an empty Rust project ready!
-
-#### 1. Add Dependencies
-
- Add the following deps to `Cargo.toml` ✏️
-
-```toml
-[dependencies]
-mingling = "0.1.9"
-
-# If you want the latest, try the version hosted on Github
-mingling = { git = "https://github.com/catilgrass/mingling", branch = "main" }
-```
-
-> [!NOTE]
->
-> This version matches the **Mingling** version used when writing this doc. Check [crates.io](https://crates.io/crates/mingling) for the latest release! 😄
->
-> **Mingling** docs are actively updated to keep pace with the latest version.
-
-
-
-#### 2. Create the Program
-
- Now, create the program in `src/main.rs` ✏️
-
-```rust
-fn main() {
- // Create ThisProgram and run it
- ThisProgram::new().exec();
-}
-
-// The gen_program! macro collects *all preceding* components & types
-// then generates the `ThisProgram` struct
-mingling::macros::gen_program!();
-```
-
-> [!TIP]
->
-> When `gen_program!()` expands, it gathers info from other components & types that were expanded before it. This means you must place `gen_program!()` at the very last expansion point in the crate.
->
-> I recommend putting it at the end of `main.rs` or `lib.rs`.
-
-
-
-#### 3. Create a Command
-
- Of course, the program currently does nothing—it won't output anything at runtime. So let's create our first command `greet` and say hi to someone ✏️
-
-```rust
-fn main() {
- // ...
-}
-
-// Create a dispatcher, binding GreetCommand to the "greet" sub-command
-// When the user specifies this command, send GreetEntry to the dispatcher
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-// ...
-gen_program!();
-```
-
- Don't be scared by the sudden macro and two new types! Let me explain what this macro does:
-
-##### About the `dispatcher!` macro 💡
-
-1. It creates a `GreetCommand` struct and implements the `Dispatcher` trait
-
-​ *This tells the framework: there's a new dispatcher that will handle a sub-command's behavior.*
-
-2. It implements the `Dispatcher` trait's `node(&self) -> Node` function, setting the node to `"greet"`
-
-​ *This tells the framework: this dispatcher handles the `"greet"` sub-command.*
-
-3. It implements the `Dispatcher` trait's `begin` function, converting the user's full input into the first type `GreetEntry`
-
-​ *This tells the framework: when this dispatcher is matched, it sends a `GreetEntry` type to the dispatcher for further processing.*
-
- In short: **"When user types `greet`, I create a `GreetEntry` and throw it into the dispatcher for conversion."**
-
-
-
-#### 4. Register the Command
-
- After creating the `Dispatcher`, we have two types: `GreetCommand` and `GreetEntry`. First, register `GreetCommand` with `ThisProgram` ✏️
-
-```rust
-fn main() {
- let mut program = ThisProgram::new();
-
- // Register the dispatcher
- program.with_dispatcher(GreetCommand);
- program.exec();
-}
-```
-
- Now `ThisProgram` recognizes the `"greet"` sub-command, but the framework still doesn't know what `"greet"` should do. That's where we implement the actual logic:
-
-
-
-#### 5. Implement Rendering Behavior
-
- We want `"greet"` to output `"Hello, World"`: since we're outputting to the screen, we can use another **Mingling** component, `Renderer`, which handles rendering data to the terminal ✏️
-
-```rust
-// ...
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-// Declare a renderer `render_greet`, specifying the previous type as `GreetEntry`
-#[renderer]
-fn render_greet(_prev: GreetEntry) {
- r_println!("Hello, World!");
-}
-
-// ...
-gen_program!(); // The renderer will be registered with the program
-```
-
- For functions marked with `#[renderer]`, **Mingling** strictly enforces only one function signature:
-
-```rust
-#[renderer]
-fn renderer_name (_prev: PreviousType) { }
-```
-
- The macro reads the type of the first param and tells `gen_program!` that this function renders that type.
-
-##### About `r_println!()` 💡
-
- You might notice that the print macro used inside `#[renderer]` is `r_println!` instead of `println!`. This is because the framework's rendering logic doesn't happen inside that function: after `#[renderer]` expands, it injects a `__renderer_inner_result: &mut RenderResult` into the function; `r_println!` appends the message to the `RenderResult`, and after the dispatcher closes, the final rendered data is handed to `Program::exec` for output.
-
-
-
-#### 6. Add Execution Logic
-
- I bet you're already itching to implement something like `greet Alice` to output `"Hello, Alice!"`—and this section is about to do just that!
-
- **Mingling**'s core execution flow is `Dispatcher -> Chain -> Renderer`, and the key part is `Chain`: it converts the input data type into another type, then lets the dispatcher find the next `Chain` or `Renderer` based on the result type ✏️
-
-```rust
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-// Wrap the intermediate type `ResultGreetSomeone`
-pack!(ResultGreetSomeone = String);
-
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- let args = prev.inner;
- let name = args
- .first()
- .cloned()
- .unwrap_or_else(|| "World".to_string());
-
- // Wrap into intermediate type
- ResultGreetSomeone::new(name)
-}
-
-#[renderer]
-fn render_greet_someone(prev: ResultGreetSomeone) {
- // Deref prev to get the raw type
- r_println!("Hello, {}!", *prev);
-}
-```
-
- Just like `#[renderer]`, we created a `#[chain]` that processes type `GreetEntry` and outputs `ResultGreetSomeone`.
-
- This inserts a `Chain` between the original `Dispatcher` and `Renderer`: it extracts the user's input params (or falls back to "World"), then passes them to the renderer to print to the terminal.
-
-##### About `Next` 💡
-
- `Next` is a placeholder generated by `gen_program!()`. After `#[chain]` expands, it's replaced by a type-erased type `ChainProcess<ThisProgram>` that the dispatcher can recognize, helping reduce boilerplate code.
-
-> [!NOTE]
->
-> `Next` is a temporary solution; the next update will wait until Rust's `Impl In Type Aliases` feature is stable.
->
-> **But don't worry**: the next `Next` update won't introduce **breaking changes!**
-
-##### About `pack!` 💡
-
- `pack!` is an **extremely** frequently used macro in **Mingling** development: it wraps any type into another type and auto-derives the traits the framework needs.
-
- Its syntax is as simple as you see:
-
-```rust
-pack!(PackedType = RawType);
-```
-
- Note: `pack!` doesn't support types with lifetimes, because types are always moved (not borrowed) between dispatchers.
-
-
-
-#### 7. Compile & Run
-
- Alright, we've completed a basic CLI app. Here's the full code—you can paste it and run it directly:
-
-```rust
-use mingling::macros::{chain, dispatcher, gen_program, pack, r_println, renderer};
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(GreetCommand);
- program.exec();
-}
-
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-pack!(ResultGreetSomeone = String);
-
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- let args = prev.inner;
- let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
-
- ResultGreetSomeone::new(name)
-}
-
-#[renderer]
-fn render_greet_someone(prev: ResultGreetSomeone) {
- r_println!("Hello, {}!", *prev);
-}
-
-gen_program!();
-```
-
- Output:
-
-```bash
-~> your-bin greet
-Hello, World!
-~> your-bin greet Alice
-Hello, Alice!
-```
-
- At this point, you have successfully created a basic **Mingling** command-line program. The next chapter will explain how to implement a fallback mechanism for your command-line program to handle cases where a command or renderer does not exist.
-
-<p align="center" style="font-size: 0.85em; color: gray;">
- Written by @Weicao-CatilGrass
-</p>
diff --git a/docs/pages/2-implementing-fallbacks.md b/docs/pages/2-implementing-fallbacks.md
deleted file mode 100644
index 3f3cb93..0000000
--- a/docs/pages/2-implementing-fallbacks.md
+++ /dev/null
@@ -1,141 +0,0 @@
-<h1 align="center">Implementing Fallbacks</h1>
-<p align="center">
- Handling error cases in your program using a fallback mechanism
-</p>
-
-## Recap
-
- In the last post, we introduced how to develop a basic CLI program using **Mingling**: you can use the `"greet"` subcommand to output `"Hello, World!"`, or use `"greet Alice"` to output `"Hello, Alice!"`
-
- But what happens when the user does not enter `"greet"`? Let's type a command and find out ⌨️
-
-```bash
-~> your-bin hello
-~> your-bin hello Alice
-```
-
- **It does nothing!** 👆
-
- Let me explain why: **Mingling** doesn't presume to act; it will not output anything to the terminal no matter what happens (except for `panic!` under `unwind`)
-
- This means that if you need to actively do something when your CLI program encounters an error, you have to state it explicitly.
-
- Fortunately, **Mingling** provides a convenient interface for this functionality: inside the `gen_program!` macro, two `FallBack` types are generated
-
-|Type|When it occurs|How it occurs|
-|-|-|-|
-|RendererNotFound|When a renderer cannot be found for scheduling|Scheduled as a `Chain`|
-|DispatcherNotFound|When a command is entered but no dispatcher matches|Scheduled as a `Chain`|
-
-### The `DispatcherNotFound` Type
-
- Let's first focus on the `DispatcherNotFound` type. It is produced as follows:
-
-```rust
-// 1. Define the `greet` command
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-fn main() {
- // ->> User enters "hello Alice"
- let mut program = ThisProgram::new();
-
- // 2. Import the `greet` command
- program.with_dispatcher(GreetCommand);
-
- // 3. Execute the program
- program.exec();
-}
-
-// ...
-
-// 5. Receive the DispatcherNotFound dispatch
-#[renderer]
-fn dispatcher_not_found(prev: DispatcherNotFound) {
- // 6. Output
- r_println!(
- "Cannot match any command! Current input: \"{}\"",
- prev.join(" ")
- );
-}
-
-// 4. Cannot match any dispatcher named `hello`
-// Forward the user's arguments as-is to DispatcherNotFound
-gen_program!();
-```
-
- The output of the above program is:
-
-```bash
-~> omg hello
-Cannot match any command! Current input: "hello"
-
-~> omg hello Alice
-Cannot match any command! Current input: "hello Alice"
-```
-
- Now, if the user enters a command that doesn't match, **Mingling** will output the appropriate message!
-
-## The `RendererNotFound` Type
-
- `RendererNotFound` can be produced in two ways:
-
- 1. The type was explicitly dispatched to a `Renderer` (using the `.to_render()` function), but the type does not have a renderer implementation
- 2. The type was dispatched to a `Chain`, but the type has neither a chain nor a renderer implementation
-
- Generally, `RendererNotFound` **should not occur in business logic**: its dispatch means your type needs to be rendered but can't be. You can use this type to pinpoint which type is missing a renderer implementation ✏️
-
-```rust
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-fn main() {
- let mut program = ThisProgram::new();
-
- program.with_dispatcher(GreetCommand);
- program.exec();
-}
-
-pack!(ResultGreetSomeone = String);
-
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- let args = prev.inner;
- let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
-
- ResultGreetSomeone::new(name)
-}
-
-// Let's intentionally remove the renderer implementation for `ResultGreetSomeone`
-// #[renderer]
-// fn render_greet_someone(prev: ResultGreetSomeone) {
-// r_println!("Hello, {}!", *prev);
-// }
-
-#[renderer]
-fn renderer_not_found(prev: RendererNotFound) {
- if *prev == "DispatcherNotFound" {
- return; // Exclude the "DispatcherNotFound" type
- }
-
- // Trigger `panic!` when a renderer is not found
- panic!("Renderer \"{}\" not found!", *prev);
-}
-
-gen_program!();
-
-```
-
- The output of the above program is:
-
-```bash
-~> your-bin greet Alice
-
-thread 'main' (90772) panicked at src/bin/your-bin.rs:30:5:
-Renderer "ResultGreetSomeone" not found!
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-```
-
- The above is the fallback mechanism of **Mingling**. In the next chapter, you will learn how to use `Picker` to parse complex user inputs.
-
-<p align="center" style="font-size: 0.85em; color: gray;">
- Written by @Weicao-CatilGrass
-</p>
diff --git a/docs/pages/3-parsing-complex-arguments.md b/docs/pages/3-parsing-complex-arguments.md
deleted file mode 100644
index 141c571..0000000
--- a/docs/pages/3-parsing-complex-arguments.md
+++ /dev/null
@@ -1,364 +0,0 @@
-<h1 align="center">Parsing Complex Args</h1>
-<p align="center">
- Use Mingling Picker to parse complex user input
-</p>
-
-## Intro
-
- In the prev. example, we built a CLI app with a `"greet"` subcommand that outputs the user's first arg.
-
- You may have noticed the approach used was almost direct string manipulation—not very semantic, and hard to maintain long-term.
-
-```rust
-let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
-```
-
- This chapter introduces a new **Mingling** feature: `Picker`. It provides a lightweight parsing solution that meshes well with **Mingling**'s typed routing.
-
- To enable `Picker`, edit `Cargo.toml` ✏️
-
-```toml
-[dependencies]
-mingling = {
- version = "...",
- features = ["parser"]
-}
-```
-
- Enough talk, let's get coding and rewrite the parsing logic from the prev. section ✏️
-
-```rust
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- // Prev. approach:
- // let args = prev.inner;
- // let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
-
- // New approach with Picker
- let name = prev.pick_or((), "World").unpack();
-
- ResultGreetSomeone::new(name)
-}
-```
-
- `Picker` implements `pick`, `pick_or`, and `pick_or_route` for anything `Into<Vec<String>>`. These functions let you semantically **pick** args from a string list and convert them into structured data.
-
- In the code above:
-
-```rust
-prev.pick_or((), "World").unpack();
-```
-
- Its meaning:
-
-```rust
- prev.pick_or((), "World").unpack();
-// ~~~~ ~~~~~~~ ~~ ~~~~~~~ ~~~~~~~~
-// | | | | |_ unpack to String
-// | | | |__________ default value is "World"
-// | | |______________ pick the first positional arg (no flag)
-// | |______________________ pick or use default
-// |___________________________ from the prev. input
-```
-
-## Parsing Flag Args
-
- If your app needs to parse flag args (e.g., `greet --name Alice`), do:
-
-```rust
-prev.pick_or(["--name", "-n"], "World").unpack();
-```
-
- Its meaning:
-
-```rust
- prev.pick_or(["--name", "-n"], "World").unpack();
-// ~~~~ ~~~~~~~ ~~~~~~~~~~~~~~~~ ~~~~~~~ ~~~~~~~~
-// | | | | |_ unpack to String
-// | | | |__________ default value is "World"
-// | | |____________________________ pick the value after "--name" or "-n"
-// | |____________________________________ pick or use default
-// |_________________________________________ from the prev. input
-```
-
-## About `.unpack()` 💡
-
- You may have noticed `Picker` calls `.unpack()` at the end of parsing. It converts the parsed result into structured info.
-
- For a single pick, `.unpack()` returns a single value. For multiple picks, `Picker` returns a tuple:
-
-```rust
-let name_single: String = prev.clone().pick_or((), "World").unpack();
-let (name, age, id) = prev
- .pick::<String>(["--name", "-n"])
- .pick::<u8>(["--age", "-a"])
- .pick::<u32>(["--id", "-I"])
- .unpack();
-
-// Parses: --name Alice --age 21 --id 0711251
-```
-
-> [!IMPORTANT]
-> `Picker` is very order-sensitive, esp. with positional args: it parses sequentially.
->
-> If you need to parse positional args, make sure to pick & consume all **flag args** first.
-
-## Using `pick_or_route` for Edge Cases
-
- Ha, as the old saying goes: "Never trust your users." Missing required args, type mismatches, enabling mutually exclusive options—these are all headache-inducing edge cases.
-
- `pick_or_route` handles these by routing the chain to a dedicated error-handling type, giving you fine-grained error control.
-
- Let's write a simple example showing basic usage:
-
-```rust
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-pack!(ResultGreetSomeone = String);
-pack!(ErrorGreetNoNameProvided = ());
-
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- // Use `pick_or_route` to extract the `--name` arg
- // If missing or parse fails, route to ErrorGreetNoNameProvided
- let pick_result = prev
- .pick_or_route(
- ["--name", "-n"],
- ErrorGreetNoNameProvided::default().to_render(),
- )
- // After using any routable method, `unpack` returns `Result<Value, Route>`
- .unpack();
-
- // Use the `route!` macro to expand `pick_result`,
- // If it's `Err`, the chain returns here, routing to the specified type
- let name = route!(pick_result);
- ResultGreetSomeone::new(name).to_chain()
-}
-
-// Handles rendering for `ErrorGreetNoNameProvided`
-#[renderer]
-fn render_err_greet_no_name_provided(_prev: ErrorGreetNoNameProvided) {
- r_println!("Error: No name provided.")
-}
-
-#[renderer]
-fn render_greet_someone(prev: ResultGreetSomeone) {
- r_println!("Hello, {}!", *prev);
-}
-```
-
- Using `pick_or_route` makes the code a bit more complex: `.unpack()` no longer returns the value directly, but `Result<Value, Route>`.
-
- However, **Mingling** provides the `route!` macro to simplify expansion. It's not complex—just cuts some boilerplate:
-
-```rust
-let name = route!(pick_result);
-
-// Expands to
-let name = match pick_result {
- Ok(r) => r,
- Err(e) => return e,
-};
-```
-
-## Post-Processing Extracted Values
-
- After using `pick` to extract user input, you can use `after` or `after_or_route` to process the arg immediately ✏️
-
-```rust
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- let name = prev
- .pick_or(["--name", "-n"], "World")
- // After extracting `--name`, format it immediately
- .after(|name: String| {
- name.replace(['-', '_', '.'], " ")
- .to_lowercase()
- .trim()
- .to_string()
- })
- .unpack();
-
- ResultGreetSomeone::new(name) // name is now formatted
-}
-```
-
- Similarly, use `after_or_route` to handle format errors in input args ✏️
-
-```rust
-dispatcher!("greet", GreetCommand => GreetEntry);
-
-pack!(ResultGreetSomeone = String);
-pack!(ErrorGreetNameTooLong = usize);
-
-#[chain]
-fn handle_greet_entry(prev: GreetEntry) -> Next {
- let pick_result = prev
- .pick_or(["--name", "-n"], "World")
- // Unlike `after`, this borrows &String
- .after_or_route(|name: &String| {
- name.replace(['-', '_', '.'], " ")
- .to_lowercase()
- .trim()
- .to_string();
-
- // Check name length, route to error type if too long
- let len = name.len();
- if len < 32 {
- Ok(name.clone())
- } else {
- Err(ErrorGreetNameTooLong::new(len).to_render())
- }
- })
- .unpack();
- let name = route!(pick_result);
-
- ResultGreetSomeone::new(name).to_chain()
-}
-
-#[renderer]
-fn render_error_greet_name_too_long(prev: ErrorGreetNameTooLong) {
- let len = *prev;
- r_println!("Error: name too long (length: {} > 32)", len);
-}
-
-#[renderer]
-fn render_greet_someone(prev: ResultGreetSomeone) {
- r_println!("Hello, {}!", *prev);
-}
-```
-
-## Parsing Booleans
-
- `Picker` can parse **bool** types too, but with both explicit and implicit modes:
-
- |Mode|Format|
- |-|-|
- |Explicit|`--confirm true` or `--confirm yes`|
- |Implicit|`--confirmed`|
-
- - Using `.pick` on `bool` uses implicit parsing: flag present → `true`
- - Using `.pick` on `mingling::parser::Yes` or `mingling::parser::True` uses explicit parsing; the value must be `true` / `yes` to be recognized as `true`
-
- Generally, implicit parsing is enough, but for positional args or important confirmations, explicit logic might be more semantic.
-
-```rust
-#[chain]
-fn handle_some_entry(prev: SomeEntry) -> Next {
- let confirmed: bool = prev.pick::<Yes>(()).unpack().is_yes();
- let confirm: bool = prev.pick::<bool>(["--confirm", "-C"]).unpack();
-
- // other logic
-}
-```
-
-## Special Use: `usize` Parsing
-
- **Mingling** has a special use for `usize`: parsing strings like `25G`, `32mb`, etc. ✏️
-
-```rust
-#[test]
-fn parse_size() {
- let vec = vec!["--size".to_string(), "25mib".to_string()];
- let size: usize = vec.pick(["--size", "-S"]).unpack();
- assert_eq!(size, 25 * 1024 * 1024);
-}
-```
-
-## Custom Parsable Types
-
- Use the `Pickable` trait to make your types parsable by `Picker`. This is where `Picker`'s extensibility comes from ✏️
-
-```rust
-// Must implement Default: parse failures record the default directly
-#[derive(Default)]
-pub struct Address {
- ip: String,
- port: u16,
-}
-
-impl Pickable for Address {
- type Output = Self;
- fn pick(args: &mut Argument, flag: Flag) -> Option<Self::Output> {
- // Extract raw string from Argument using Flag
- let raw = args.pick_argument(flag)?;
-
- // Parse raw string into structured data
- let parts: Vec<&str> = raw.split(':').collect();
- let ip = parts.first()?.to_string();
- let port: u16 = parts.get(1)?.parse().ok()?;
-
- Some(Address { ip, port })
- }
-}
-```
-
- With `Pickable` implemented for `Address`, we can now use `ip:port` format for input ✏️
-
-```rust
-dispatcher!("connect", ConnectCommand => ConnectEntry);
-
-pack!(ResultConnected = Address);
-
-#[chain]
-fn handle_connect_entry(prev: ConnectEntry) -> Next {
- let address: Address = prev.pick("--addr").unpack();
- ResultConnected::new(address)
-}
-
-#[renderer]
-fn render_connected(prev: ResultConnected) {
- let addr = prev.inner;
- r_println!("Connected: IP: {} PORT: {}", addr.ip, addr.port);
-}
-```
-
- Running it:
-
-```bash
-~> your-bin connect --addr 127.0.0.1:8080
-Connected: IP: 127.0.0.1 PORT: 8080
-```
-
-## Auto-Implementing Pickable for Enums
-
- No need to manually implement `Pickable` for enums: `Picker` auto-implements it for any type that implements `PickableEnum`, as long as it also implements `EnumTag` ✏️
-
-```rust
-// Debug : for rendering
-// Default: for Picker parsing
-// EnumTag: for implementing PickableEnum
-#[derive(Debug, Default, EnumTag)]
-pub enum Fruits {
- #[default]
- Apple,
- Banana,
- Orange,
-}
-
-// Implement PickableEnum for Fruits
-impl PickableEnum for Fruits {}
-```
-
- Now you can directly use `Picker` to parse this type ✏️
-
-```rust
-pack!(ResultFruit = Fruits);
-
-#[chain]
-fn handle_eat_fruit_entry(prev: EatFruitEntry) -> Next {
- let fruit: Fruits = prev.pick("--fruit").unpack();
- ResultFruit::new(fruit)
-}
-
-#[renderer]
-fn render_ate_fruit(prev: ResultFruit) {
- r_println!("Picked fruit: {:?}", *prev);
-}
-```
-
- That's all for `Picker`'s usage. In the next chapter, I'll introduce how to implement help docs for commands in **Mingling**.
-
-<p align="center" style="font-size: 0.85em; color: gray;">
- Written by @Weicao-CatilGrass
-</p>
diff --git a/docs/pages/4-implementing-help-display.md b/docs/pages/4-implementing-help-display.md
deleted file mode 100644
index 625863e..0000000
--- a/docs/pages/4-implementing-help-display.md
+++ /dev/null
@@ -1,4 +0,0 @@
-<h1 align="center">Impl Help Display</h1>
-<p align="center">
- Implement help documentation for commands using the help macro
-</p>
diff --git a/docs/pages/5-implementing-completion.md b/docs/pages/5-implementing-completion.md
deleted file mode 100644
index 7622775..0000000
--- a/docs/pages/5-implementing-completion.md
+++ /dev/null
@@ -1,4 +0,0 @@
-<h1 align="center">Impl Shell Completion</h1>
-<p align="center">
- Implementing a fully dynamic completion system using Mingling Completion
-</p>