From b9edeb9848e4a423e133fa2a13dede6d128d6f08 Mon Sep 17 00:00:00 2001
From: 魏曹先生 <1992414357@qq.com>
Date: Tue, 14 Apr 2026 22:47:08 +0800
Subject: Add documentation for Mingling CLI framework
---
docs/.nojekyll | 0
docs/LICENSE | 21 +
docs/README.md | 157 +++++++
docs/_sidebar.md | 9 +
docs/css/vue.css | 885 +++++++++++++++++++++++++++++++++++++
docs/index.html | 55 +++
docs/pages/1-get-started.md | 69 +++
docs/pages/2-basic.md | 16 +
docs/pages/2-basic/1-program.md | 117 +++++
docs/pages/2-basic/2-setup.md | 169 +++++++
docs/pages/2-basic/3-dispatcher.md | 12 +
docs/pages/2-basic/4-chain.md | 10 +
docs/pages/2-basic/5-renderer.md | 6 +
13 files changed, 1526 insertions(+)
create mode 100644 docs/.nojekyll
create mode 100644 docs/LICENSE
create mode 100644 docs/README.md
create mode 100644 docs/_sidebar.md
create mode 100644 docs/css/vue.css
create mode 100644 docs/index.html
create mode 100644 docs/pages/1-get-started.md
create mode 100644 docs/pages/2-basic.md
create mode 100644 docs/pages/2-basic/1-program.md
create mode 100644 docs/pages/2-basic/2-setup.md
create mode 100644 docs/pages/2-basic/3-dispatcher.md
create mode 100644 docs/pages/2-basic/4-chain.md
create mode 100644 docs/pages/2-basic/5-renderer.md
diff --git a/docs/.nojekyll b/docs/.nojekyll
new file mode 100644
index 0000000..e69de29
diff --git a/docs/LICENSE b/docs/LICENSE
new file mode 100644
index 0000000..bec4d76
--- /dev/null
+++ b/docs/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 docsifyjs
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..15e3230
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,157 @@
+
+
+> [!WARNING]
+>
+> **Note**: Mingling is still under active development, and its API may change. Feel free to try it out and give us feedback!
+> **Hint**: This note will be removed in version `0.2.0`
+
+## Contents
+
+- [Intro](#intro)
+- [Quick Start](#quick-start)
+- [Core Concepts](#core-concepts)
+- [Project Structure](#project-structure)
+- [Example Projects](#example-projects)
+- [Next Steps](#next-steps)
+- [Roadmap](#roadmap)
+- [Unplanned Features](#unplanned-features)
+- [License](#license)
+
+## Intro
+
+[`Mingling`](https://github.com/CatilGrass/mingling) is a **proc-macro and type system-based** Rust CLI framework, suitable for developing complex command-line programs with numerous subcommands.
+
+> BTW: Its name comes from the Chinese Pinyin "mìng lìng", meaning "Command". 😄
+
+
+## Quick Start
+
+The example below shows how to use `Mingling` to create a simple command-line program:
+
+```rust
+use mingling::macros::{dispatcher, gen_program, r_println, renderer};
+
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+ program.with_dispatcher(HelloCommand);
+
+ // Execute
+ program.exec().await;
+}
+
+// Define command: " hello"
+dispatcher!("hello", HelloCommand => HelloEntry);
+
+// Render HelloEntry
+#[renderer]
+fn render_hello_world(_prev: HelloEntry) {
+ r_println!("Hello, World!")
+}
+
+// Fallbacks
+#[renderer]
+fn fallback_dispatcher_not_found(prev: DispatcherNotFound) {
+ r_println!("Dispatcher not found for command `{}`", prev.join(", "))
+}
+
+#[renderer]
+fn fallback_renderer_not_found(prev: RendererNotFound) {
+ r_println!("Renderer not found `{}`", *prev)
+}
+
+// Collect renderers and chains to generate ThisProgram
+gen_program!();
+```
+
+Output:
+
+```
+> mycmd hello
+Hello, World!
+> mycmd hallo
+Dispatcher not found for command `hallo`
+```
+
+## Core Concepts
+
+Mingling abstracts command execution into the following parts:
+
+1. **Dispatcher** - Routes user input to a specific renderer or chain based on the command node name.
+2. **Chain** - Transforms the incoming type into another type, passing it to the next chain or renderer.
+3. **Renderer** - Stops the chain and prints the currently processed type to the terminal.
+4. **Program** - Manages the lifecycle and configuration of the entire CLI application.
+
+
+ Architecture Diagram (click to expand)
+
+
+---
+
+Mingling abstracts the lifecycle of a CLI program into the following types:
+
+| Component | Description |
+| :--- | :--- |
+| [Program](./pages/2-basic/1-program) | Records resources for the current context |
+| [Setup](./pages/2-basic/2-setup) | Bundles commonly used functionalities |
+| [Dispatcher](./pages/2-basic/3-dispatcher) | Dispatches user input to specific types |
+| [Chain](./pages/2-basic/4-chain) | Handles type conversion |
+| [Renderer](./pages/2-basic/5-renderer) | Handles type rendering |
diff --git a/docs/pages/2-basic/1-program.md b/docs/pages/2-basic/1-program.md
new file mode 100644
index 0000000..fd8e986
--- /dev/null
+++ b/docs/pages/2-basic/1-program.md
@@ -0,0 +1,117 @@
+
Program
+
+ Mingling's Basic Components
+
+
+---
+
+## Intro
+
+`Program` is the data structure that holds the state for **Mingling** CLI programs. It manages the user's context and enables type-based dispatch.
+
+`Program` needs to implement the `ProgramCollect` trait,
+
+> but, you don't have to do this manually —
+
+The `mingling_macros` crate provides the `gen_program!()` macro, which can auto collect resources defined by the `dispatcher!`, `chain!`, and the `completion!` macro of the `comp` feature.
+
+```rust
+// Define Dispatcher
+dispatcher!("hello", HelloCommand => HelloEntry);
+
+// Define Renderer
+#[renderer]
+fn render_hello(_prev: HelloEntry) {
+ r_println!("Hello, World!")
+}
+
+// Collect all resources here and generate ThisProgram
+gen_program!();
+
+// You can also explicitly declare a Program
+// with a different name like this:
+// gen_program!(MyProgram);
+```
+
+## Adding Setup
+
+You can use the `with_setup` function to add preset [Setup](pages/2-basic/2-setup) to your program, which provide reusable functionality.
+
+For example, you can use the following code to add parsing for global flags like `--confirm` / `--help` / `--quiet` to your program:
+
+```rust
+use mingling::{
+ macros::gen_program,
+ setup::BasicProgramSetup
+};
+
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+ // Add `BasicProgramSetup`
+ program.with_setup(BasicProgramSetup);
+ program.exec().await;
+}
+
+// Generate `ThisProgram`
+gen_program!();
+```
+
+## Adding Dispatcher
+
+You can use `with_dispatcher` or `with_dispatchers` to add [Dispatchers](pages/2-basic/3-dispatcher) to your program to make it work:
+
+```rust
+// Define two Dispatchers using `dispatcher!`
+dispatcher!("member.add",
+ AddMemberCommand => AddMemberEntry);
+dispatcher!("member.rm",
+ RemoveMemberCommand => RemoveMemberEntry);
+
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+
+ // Register Dispatchers
+ program.with_dispatcher(AddMemberCommand);
+ program.with_dispatcher(RemoveMemberCommand);
+
+ // Or use `with_dispatchers`
+ program.with_dispatchers((
+ AddMemberCommand,
+ RemoveMemberCommand
+ ));
+
+ program.exec().await;
+}
+```
+
+## Parsing Global Args
+
+You can extract global arguments before the program runs to control the global state of the `Program`:
+
+```rust
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+
+ let mut output = current_dir().unwrap();
+
+ // Pick the "--quiet" or "-q" flag
+ program.global_flag(["--quiet", "-q"], |p| {
+ // Disable render output
+ p.stdout_setting.render_output = false;
+ });
+
+ // Pick the "--output" or "-O" flag, write to output
+ program.global_argument(
+ ["--output", "-O"],
+ |_, v| output = PathBuf::from(v)
+ );
+
+ program.exec().await;
+}
+```
+
+## 💡 Next Page
+> **Basic Component** - Setup [Go](./pages/2-basic/2-setup)
diff --git a/docs/pages/2-basic/2-setup.md b/docs/pages/2-basic/2-setup.md
new file mode 100644
index 0000000..8dbdd76
--- /dev/null
+++ b/docs/pages/2-basic/2-setup.md
@@ -0,0 +1,169 @@
+
Setup
+
+ Mingling's Basic Components
+
+
+---
+
+## Usage
+
+`Setup` is used to organize and package the initialization process of a `Program`, making the project easier to manage. It is defined as follows:
+
+```rust
+struct MySetup;
+impl ProgramSetup
+ for MySetup
+{
+ fn setup(
+ &mut self,
+ program: &mut Program
+ ) {
+ // Your setup logic
+ }
+}
+```
+
+For example:
+
+```rust
+use std::{env::current_dir, path::PathBuf};
+
+use mingling::{
+ Program,
+ macros::{dispatcher, gen_program, renderer},
+ setup::ProgramSetup,
+};
+
+// Global state
+static OUTPUT_PATH: std::sync::OnceLock
+ = std::sync::OnceLock::new();
+
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+ program.with_setup(MySetup);
+ program.exec().await;
+}
+
+// Define two Dispatchers using `dispatcher!`
+dispatcher!("member.add",
+ AddMemberCommand => AddMemberEntry);
+dispatcher!("member.rm",
+ RemoveMemberCommand => RemoveMemberEntry);
+
+struct MySetup;
+impl ProgramSetup for MySetup {
+ fn setup(
+ &mut self, program: &mut Program
+ ) {
+ // Register Dispatchers
+ program.with_dispatcher(AddMemberCommand);
+ program.with_dispatcher(RemoveMemberCommand);
+
+ // Initialize global output once
+ OUTPUT_PATH.get_or_init(|| current_dir().unwrap());
+
+ // Pick the "--quiet" or "-q" flag
+ program.global_flag(["--quiet", "-q"], |p| {
+ // Disable render output
+ p.stdout_setting.render_output = false;
+ });
+
+ // Pick the "--output" or "-O" flag, write to output
+ program.global_argument(["--output", "-O"], |_, v| {
+ let _ = OUTPUT_PATH.set(PathBuf::from(v));
+ });
+ }
+}
+
+// Define empty renderer types to give the two types type IDs
+
+#[renderer]
+fn phantom_renderer_add_member(
+ _prev: AddMemberEntry
+) {}
+
+#[renderer]
+fn phantom_renderer_remove_member(
+ _prev: RemoveMemberEntry
+) {}
+
+gen_program!();
+```
+
+## Simplified Syntax
+
+If you find the above declaration method too **verbose**, you can use the `program_setup!` macro to simplify it. The format is:
+
+```rust
+#[program_setup]
+fn my_setup(
+ program: &mut Program
+) {
+ // Your setup logic
+}
+```
+
+For example:
+
+```rust
+use std::{env::current_dir, path::PathBuf};
+
+use mingling::{
+ Program,
+ macros::{
+ dispatcher,
+ gen_program,
+ program_setup,
+ renderer
+ },
+};
+
+static OUTPUT_PATH: std::sync::OnceLock
+ = std::sync::OnceLock::new();
+
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+ program.with_setup(MySetup);
+ program.exec().await;
+}
+
+dispatcher!("member.add",
+ AddMemberCommand => AddMemberEntry);
+dispatcher!("member.rm",
+ RemoveMemberCommand => RemoveMemberEntry);
+
+#[program_setup]
+fn my_setup(
+ program: &mut Program
+) {
+ program.with_dispatcher(AddMemberCommand);
+ program.with_dispatcher(RemoveMemberCommand);
+
+ OUTPUT_PATH.get_or_init(|| current_dir().unwrap());
+
+ program.global_flag(["--quiet", "-q"], |p| {
+ p.stdout_setting.render_output = false;
+ });
+
+ program.global_argument(["--output", "-O"], |_, v| {
+ let _ = OUTPUT_PATH.set(PathBuf::from(v));
+ });
+}
+
+#[renderer]
+fn phantom_renderer_add_member(
+ _prev: AddMemberEntry
+) {}
+
+#[renderer]
+fn phantom_renderer_remove_member(
+ _prev: RemoveMemberEntry
+) {}
+
+gen_program!();
+```
+
+## 💡 Next Page
+> **Basic Component** - Dispatcher [Go](./pages/2-basic/3-dispatcher)
diff --git a/docs/pages/2-basic/3-dispatcher.md b/docs/pages/2-basic/3-dispatcher.md
new file mode 100644
index 0000000..643a752
--- /dev/null
+++ b/docs/pages/2-basic/3-dispatcher.md
@@ -0,0 +1,12 @@
+