diff options
| -rw-r--r-- | examples/example-async/Cargo.lock | 4 | ||||
| -rw-r--r-- | examples/example-basic/Cargo.lock | 4 | ||||
| -rw-r--r-- | examples/example-completion/Cargo.lock | 4 | ||||
| -rw-r--r-- | examples/example-general-renderer/Cargo.lock | 4 | ||||
| -rw-r--r-- | examples/example-picker/Cargo.lock | 4 | ||||
| -rw-r--r-- | mingling/Cargo.lock | 4 | ||||
| -rw-r--r-- | mingling/Cargo.toml | 4 | ||||
| -rw-r--r-- | mingling/README.md | 209 | ||||
| -rw-r--r-- | mling/Cargo.lock | 6 | ||||
| -rw-r--r-- | mling/Cargo.toml | 2 |
10 files changed, 235 insertions, 10 deletions
diff --git a/examples/example-async/Cargo.lock b/examples/example-async/Cargo.lock index 5d1243e..d9549aa 100644 --- a/examples/example-async/Cargo.lock +++ b/examples/example-async/Cargo.lock @@ -70,6 +70,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "just_fmt", "once_cell", @@ -79,6 +81,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/examples/example-basic/Cargo.lock b/examples/example-basic/Cargo.lock index ae57530..3ed4017 100644 --- a/examples/example-basic/Cargo.lock +++ b/examples/example-basic/Cargo.lock @@ -26,6 +26,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "just_fmt", "once_cell", @@ -35,6 +37,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/examples/example-completion/Cargo.lock b/examples/example-completion/Cargo.lock index 7a54cc1..004c859 100644 --- a/examples/example-completion/Cargo.lock +++ b/examples/example-completion/Cargo.lock @@ -36,6 +36,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "just_fmt", "just_template", @@ -46,6 +48,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/examples/example-general-renderer/Cargo.lock b/examples/example-general-renderer/Cargo.lock index 84e1c28..3051a7c 100644 --- a/examples/example-general-renderer/Cargo.lock +++ b/examples/example-general-renderer/Cargo.lock @@ -72,6 +72,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "just_fmt", "once_cell", @@ -86,6 +88,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/examples/example-picker/Cargo.lock b/examples/example-picker/Cargo.lock index f4dc769..b722ed4 100644 --- a/examples/example-picker/Cargo.lock +++ b/examples/example-picker/Cargo.lock @@ -28,6 +28,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "just_fmt", "once_cell", @@ -37,6 +39,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/mingling/Cargo.lock b/mingling/Cargo.lock index 030b206..08911df 100644 --- a/mingling/Cargo.lock +++ b/mingling/Cargo.lock @@ -236,6 +236,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "env_logger", "just_fmt", @@ -253,6 +255,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml index 61a6c2b..61fca91 100644 --- a/mingling/Cargo.toml +++ b/mingling/Cargo.toml @@ -36,7 +36,7 @@ comp = ["mingling_core/comp", "mingling_macros/comp"] parser = ["dep:size"] [dependencies] -mingling_core = { path = "../mingling_core", default-features = false } -mingling_macros = { path = "../mingling_macros", default-features = false } +mingling_core = { version = "0.1.7", default-features = false } +mingling_macros = { version = "0.1.7", default-features = false } serde = { version = "1.0", features = ["derive"], optional = true } size = { version = "0.5", optional = true } diff --git a/mingling/README.md b/mingling/README.md index f246aa5..7040177 100644 --- a/mingling/README.md +++ b/mingling/README.md @@ -1,14 +1,66 @@ -# Mìng Lìng - 命令 +<p align="center"> + <a href="https://github.com/CatilGrass/mingling"> + <img alt="Mingling" src="https://github.com/CatilGrass/mingling/raw/main/docs/res/icon_shadow.png" width="30%"> + </a> +</p> +<h1 align="center">Mìng Lìng - 命令</h1> + +<p align="center"> + A Rust CLI framework for many subcmds & complex workflows, reduces boilerplate via proc macros, focus on biz logic +</p> +<p align="center"> + <img src="https://img.shields.io/github/stars/CatilGrass/mingling?style=for-the-badge"> + <a href="https://crates.io/crates/mingling"> + <img src="https://img.shields.io/crates/v/mingling?style=for-the-badge"> + </a> + <a href="https://docs.rs/mingling/latest/mingling/"> + <img src="https://img.shields.io/docsrs/mingling?style=for-the-badge"> + </a> + <a href="https://catilgrass.github.io/mingling/"> + <img src="https://img.shields.io/badge/helpdoc-latest-yellow?style=for-the-badge"> + </a> +</p> + > [!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.5.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) -`Mingling` is a Rust command-line framework. Its name comes from the Chinese Pinyin for "命令", which means "Command". +## 🚀 Intro -## Quick Start +[`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. -The example below shows how to use `Mingling` to create a simple command-line program: +> BTW: Its name comes from the Chinese Pinyin "mìng lìng", meaning "Command". 😄 + + +## ⚡ Quick Start + +> To use a release version of `Mingling`, get the latest version from [`crates.io`](https://crates.io/crates/mingling) +> +> To use the latest version, pull the project from the `main` branch on `github` + +```toml +# From crates.io +mingling = "0.1.7" + +# From GitHub +mingling = { git = "https://github.com/catilgrass/mingling", branch = "main" } +``` + +The example below shows how to use `Mingling` to create a simple CLI program: ```rust use mingling::macros::{dispatcher, gen_program, r_println, renderer}; @@ -54,7 +106,96 @@ Hello, World! Dispatcher not found for command `hallo` ``` -## Core Concepts +Now, let's see the full usage of **Mingling**: The following example shows how to use `Mingling` to create a complete CLI program with `help`, `completion`, `fallback`, and `parser` features: + +```rust +use mingling::{ + ShellContext, Suggest, + macros::{ + chain, completion, dispatcher, gen_program, help, pack, r_println, renderer, suggest, + }, + parser::AsPicker, + setup::BasicProgramSetup, +}; + +fn main() { + // Initialize program + let mut program = ThisProgram::new(); + + // Load plugins + program.with_setup(BasicProgramSetup); + program.with_dispatcher(CompletionDispatcher); + + // Load commands + program.with_dispatcher(GreetCommand); + + // Run program + program.exec(); +} + +// Define dispatcher `greet` +dispatcher!("greet", GreetCommand => GreetEntry); + +// Define intermediate type `StateGreeting` +pack!(StateGreeting = String); + +// Define `greet` command help +#[help] +fn help_greet_command(_prev: GreetEntry) { + r_println!("Usage: greet <NAME>"); +} + +// Define `greet` command completion +#[completion(GreetEntry)] +fn comp_greet_command(ctx: &ShellContext) -> Suggest { + if ctx.previous_word == "greet" { + return suggest! { + "Alice", + "Bob", + "Peter" + }; + } + return suggest!(); +} + +// Define chain, parsing `GreetEntry` into `StateGreeting` +#[chain] +fn parse_name_to_greet(prev: GreetEntry) -> NextProcess { + let state_greeting: StateGreeting = + prev.pick_or::<String>((), "World").unpack().into(); + state_greeting +} + +// Render `StateGreeting` +#[renderer] +fn render_state_greeting(prev: StateGreeting) { + r_println!("Hello, {}!", *prev); +} + +// Define fallback logic when no matching dispatcher is found +#[renderer] +fn fallback_no_dispatcher_found(prev: DispatcherNotFound) { + r_println!("Command \"{}\" not found.", prev.join(" ")); +} + +// Generate program +gen_program!(); +``` + +Output: + +``` +~> mycmd greet + Hello, World! +~> mycmd greet Alice + Hello, Alice! +~> mycmd greet --help + Usage: greet <NAME> +~> mycmd great + Command "great" not found. +``` + +## 🧠 Core Concepts Mingling abstracts command execution into the following parts: @@ -63,7 +204,63 @@ Mingling abstracts command execution into the following parts: 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. -## License +<details> + <summary>Architecture Diagram (click to expand)</summary> + <p align="center"> + <a href="https://github.com/CatilGrass/mingling"> + <img alt="Mingling" src="docs/res/graph.png" width="75%"> + </a> + </p> +</details> + +## 🏗️ Project Structure + +The Mingling project consists of two main parts: + +- **[mingling/](mingling/)** - The core runtime library, containing type definitions, error handling, and basic functionality. +- **[mingling_macros/](mingling_macros/)** - The procedural macro library, providing declarative macros to simplify development. + +## 💡 Example Projects + +- **[`examples/example-basic/`](https://docs.rs/mingling/latest/mingling/_mingling_examples/example_basic/index.html)** - A simple "Hello, World!" example demonstrating the most basic usage of a Dispatcher and Renderer. +- **[`examples/example-async/`](https://docs.rs/mingling/latest/mingling/_mingling_examples/example_async/index.html)** - Based on `example-basic`, demonstrates how to integrate an async runtime +- **[`examples/example-picker/`](https://docs.rs/mingling/latest/mingling/_mingling_examples/example_picker/index.html)** - Demonstrates how to use a Chain to process and transform command arguments. +- **[`examples/example-general-renderer/`](https://docs.rs/mingling/latest/mingling/_mingling_examples/example_general_renderer/index.html)** - Shows how to use a general renderer for different data types (e.g., JSON, YAML, TOML, RON). +- **[`examples/example-completion/`](https://docs.rs/mingling/latest/mingling/_mingling_examples/example_completion/index.html)** - An example implementing auto-completion for the shell. + +## 👣 Next Steps + +You can read the following docs to learn more about the `Mingling` framework: + +- Check out **[Mingling Helpdoc](https://catilgrass.github.io/mingling/)** to learn the basics. +- Check out **[Mingling Examples](https://docs.rs/mingling/latest/mingling/_mingling_examples/index.html)** to learn about the core library. +- Check out **[Mingling Docs](https://docs.rs/mingling/latest/mingling/)** to learn how to use the macro system and explore the full API. + +## 🗺️ Roadmap + +- [x] core: \[[0.1.4](https://docs.rs/mingling/0.1.4/mingling/)\] General Renderers *( Json, Yaml, Toml, Ron )* +- [x] core: \[[0.1.5](https://docs.rs/mingling/0.1.5/mingling/)\] Completion *( Bash Zsh Fish Pwsh )* +- [x] core: \[[0.1.6](https://docs.rs/mingling/0.1.6/mingling/)\] Smarter Completion Suggest Generation +- [x] \[[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)\] Clap Parser Support +- [x] core: \[[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)\] Help System +- [x] mling: \[[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)\] Mingling-CLI Tool ( `mling` ) +- [ ] core: \[**0.1.8**\] Compile-Time Dispatcher Tree +- [ ] \[**0.1.9**\] Helpdoc Generation +- [ ] core: \[**0.1.9**\] Debug Toolkits ( `InvokeStackDisplay` ) +- [ ] core: \[**0.2.0**\] REPL Mode ( `program.exec_repl();` ) +- [ ] ... + +## 🚫 Unplanned Features + +While Mingling has several common CLI features that are **NOT PLANNED** to be directly included in the framework. +This is because the Rust ecosystem already has excellent and mature crates to handle these issues, and Mingling's design is intended to be used in combination with them. + +- **Colored Output**: To add color and styles (bold, italic, etc.) to terminal output, consider using crates like [`colored`](https://crates.io/crates/colored) or [`owo-colors`](https://crates.io/crates/owo-colors). You can integrate their types directly into your renderers. +- **I18n**: To translate your CLI application, the [`rust-i18n`](https://crates.io/crates/rust-i18n) crate provides a powerful internationalization solution that you can use in your command logic and renderers. +- **Progress Bars**: To display progress indicators, the [`indicatif`](https://crates.io/crates/indicatif) crate is the standard choice. +- **TUI**: To build full-screen interactive terminal applications, it is recommended to use a framework like [`ratatui`](https://crates.io/crates/ratatui) (formerly `tui-rs`). + +## 📄 License This project is licensed under the MIT License. diff --git a/mling/Cargo.lock b/mling/Cargo.lock index 7167d1d..b98df56 100644 --- a/mling/Cargo.lock +++ b/mling/Cargo.lock @@ -134,7 +134,7 @@ dependencies = [ [[package]] name = "mingling-cli" -version = "0.1.0" +version = "0.1.7" dependencies = [ "colored", "dirs", @@ -148,6 +148,8 @@ dependencies = [ [[package]] name = "mingling_core" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12e0ee263a48336b5a16598a89c2220524af7a0267227160ebed1364ff0a741" dependencies = [ "just_fmt", "just_template", @@ -163,6 +165,8 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7af9a980ada645d77113c0d39877d6a3d3861b271ceb8a1b6bb804177697ad8" dependencies = [ "just_fmt", "once_cell", diff --git a/mling/Cargo.toml b/mling/Cargo.toml index b722420..ebaedb8 100644 --- a/mling/Cargo.toml +++ b/mling/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingling-cli" -version = "0.1.0" +version = "0.1.7" edition = "2024" [[bin]] |
