aboutsummaryrefslogtreecommitdiff
path: root/docs/pages
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-14 22:47:08 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-14 22:47:08 +0800
commitb9edeb9848e4a423e133fa2a13dede6d128d6f08 (patch)
treef8f9e03bf3e64b98f3e5de57fd5d0686bf4739b2 /docs/pages
parentde54d14f315c96a1003b8956086828fc75ddf49d (diff)
Add documentation for Mingling CLI framework
Diffstat (limited to 'docs/pages')
-rw-r--r--docs/pages/1-get-started.md69
-rw-r--r--docs/pages/2-basic.md16
-rw-r--r--docs/pages/2-basic/1-program.md117
-rw-r--r--docs/pages/2-basic/2-setup.md169
-rw-r--r--docs/pages/2-basic/3-dispatcher.md12
-rw-r--r--docs/pages/2-basic/4-chain.md10
-rw-r--r--docs/pages/2-basic/5-renderer.md6
7 files changed, 399 insertions, 0 deletions
diff --git a/docs/pages/1-get-started.md b/docs/pages/1-get-started.md
new file mode 100644
index 0000000..f4edfc0
--- /dev/null
+++ b/docs/pages/1-get-started.md
@@ -0,0 +1,69 @@
+# Get Started
+This article explains how to quickly create your first **Mingling** command-line program.
+
+## Quick Start
+1. Add `mingling` to your Rust project.
+```bash
+cargo add mingling
+```
+Or add the following to your `Cargo.toml`:
+```toml
+[dependencies]
+mingling = "0.1.5"
+```
+
+> **Mingling** is an **async program**, so please use `async-std`, `tokio`, or another async runtime.
+
+2. This article assumes you are using the `tokio` async runtime. Add the following to your `Cargo.toml`:
+```toml
+tokio = {
+ version = "1",
+ features = [
+ "macros",
+ "rt",
+ "rt-multi-thread"
+ ]
+}
+```
+
+3. Write the basic code in your `main.rs` or other program entry point.
+```rust
+use mingling::macros::{dispatcher, gen_program, r_println, renderer};
+
+#[tokio::main]
+async fn main() {
+ // Create ThisProgram
+ let mut program = ThisProgram::new();
+
+ // Import the dispatcher `HelloCommand`
+ program.with_dispatcher(HelloCommand);
+
+ // Run the program
+ program.exec().await;
+}
+
+// Define the dispatcher `HelloCommand`, which routes the "hello" subcommand to `HelloEntry`
+dispatcher!("hello", HelloCommand => HelloEntry);
+
+// Define the renderer, which receives `HelloEntry` and renders the content
+#[renderer]
+fn render_hello(_prev: HelloEntry) {
+ r_println!("Hello, World!")
+}
+
+// Create ThisProgram at the end of the code
+gen_program!();
+```
+
+4. Install your command-line program and run it.
+```bash
+cargo install --path ./
+your_bin hello
+```
+Result:
+```bash
+Hello, World!
+```
+
+## 💡 Next Steps
+> **Mingling**'s basic components [Go](./pages/2-basic)
diff --git a/docs/pages/2-basic.md b/docs/pages/2-basic.md
new file mode 100644
index 0000000..78d2fda
--- /dev/null
+++ b/docs/pages/2-basic.md
@@ -0,0 +1,16 @@
+<h1 align="center">Mingling's Basic Components</h1>
+<p align="center">
+ Table of Contents
+</p>
+
+---
+
+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 @@
+<h1 align="center">Program</h1>
+<p align="center">
+ Mingling's Basic Components
+</p>
+
+---
+
+## 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 @@
+<h1 align="center">Setup</h1>
+<p align="center">
+ Mingling's Basic Components
+</p>
+
+---
+
+## 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<ThisProgram, ThisProgram>
+ for MySetup
+{
+ fn setup(
+ &mut self,
+ program: &mut Program<ThisProgram, ThisProgram>
+ ) {
+ // 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<PathBuf>
+ = 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<ThisProgram, ThisProgram> for MySetup {
+ fn setup(
+ &mut self, program: &mut Program<ThisProgram, ThisProgram>
+ ) {
+ // 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<ThisProgram, ThisProgram>
+) {
+ // 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<PathBuf>
+ = 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<ThisProgram, ThisProgram>
+) {
+ 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 @@
+<h1 align="center">Dispatcher</h1>
+<p align="center">
+ Mingling's Basic Components
+</p>
+
+---
+
+
+
+
+## 💡 Next Page
+> **Basic Component** - Chain [Go](./pages/2-basic/4-chain)
diff --git a/docs/pages/2-basic/4-chain.md b/docs/pages/2-basic/4-chain.md
new file mode 100644
index 0000000..e9676c2
--- /dev/null
+++ b/docs/pages/2-basic/4-chain.md
@@ -0,0 +1,10 @@
+<h1 align="center">Chain</h1>
+<p align="center">
+ Mingling's Basic Components
+</p>
+
+---
+
+
+## 💡 Next Page
+> **Basic Component** - Renderer [Go](./pages/2-basic/5-renderer)
diff --git a/docs/pages/2-basic/5-renderer.md b/docs/pages/2-basic/5-renderer.md
new file mode 100644
index 0000000..f3e09de
--- /dev/null
+++ b/docs/pages/2-basic/5-renderer.md
@@ -0,0 +1,6 @@
+<h1 align="center">Renderer</h1>
+<p align="center">
+ Mingling's Basic Components
+</p>
+
+---