aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/example-argument-parse/Cargo.lock223
-rw-r--r--examples/example-argument-parse/Cargo.toml12
-rw-r--r--examples/example-argument-parse/page.toml10
-rw-r--r--examples/example-argument-parse/src/main.rs104
-rw-r--r--examples/example-argument-parse/test.toml29
-rw-r--r--examples/example-argument-picker/Cargo.lock6
-rw-r--r--examples/example-argument-picker/src/main.rs72
-rw-r--r--examples/example-async-support/Cargo.lock31
-rw-r--r--examples/example-async-support/Cargo.toml4
-rw-r--r--examples/example-async-support/src/main.rs11
-rw-r--r--examples/example-basic/Cargo.lock6
-rw-r--r--examples/example-basic/src/main.rs32
-rw-r--r--examples/example-clap-binding/Cargo.lock6
-rw-r--r--examples/example-clap-binding/src/main.rs3
-rw-r--r--examples/example-combine-pathf-dispatch-tree/Cargo.lock8
-rw-r--r--examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs5
-rw-r--r--examples/example-combine-pathf-metadata/Cargo.lock8
-rw-r--r--examples/example-combine-pathf-metadata/src/main.rs5
-rw-r--r--examples/example-combine-pathf-metadata/src/sub/mod.rs14
-rw-r--r--examples/example-command-macro/Cargo.lock6
-rw-r--r--examples/example-command-macro/src/main.rs30
-rw-r--r--examples/example-completion/Cargo.lock31
-rw-r--r--examples/example-completion/Cargo.toml2
-rw-r--r--examples/example-completion/src/main.rs51
-rw-r--r--examples/example-custom-pickable/Cargo.lock223
-rw-r--r--examples/example-custom-pickable/Cargo.toml11
-rw-r--r--examples/example-custom-pickable/page.toml10
-rw-r--r--examples/example-custom-pickable/src/main.rs132
-rw-r--r--examples/example-custom-pickable/test.toml17
-rw-r--r--examples/example-dispatch-tree/Cargo.lock6
-rw-r--r--examples/example-dispatch-tree/src/main.rs42
-rw-r--r--examples/example-enum-tag/Cargo.lock31
-rw-r--r--examples/example-enum-tag/Cargo.toml2
-rw-r--r--examples/example-enum-tag/src/main.rs49
-rw-r--r--examples/example-error-handling/Cargo.lock6
-rw-r--r--examples/example-error-handling/src/main.rs37
-rw-r--r--examples/example-exitcode/Cargo.lock6
-rw-r--r--examples/example-exitcode/src/main.rs16
-rw-r--r--examples/example-help/Cargo.lock6
-rw-r--r--examples/example-help/src/main.rs4
-rw-r--r--examples/example-hook/Cargo.lock6
-rw-r--r--examples/example-hook/src/main.rs8
-rw-r--r--examples/example-implicit-dispatcher/Cargo.lock6
-rw-r--r--examples/example-implicit-dispatcher/src/main.rs17
-rw-r--r--examples/example-lazy-resources/Cargo.lock6
-rw-r--r--examples/example-lazy-resources/src/main.rs8
-rw-r--r--examples/example-metadata/Cargo.lock6
-rw-r--r--examples/example-metadata/src/main.rs25
-rw-r--r--examples/example-outside-type/Cargo.lock6
-rw-r--r--examples/example-outside-type/src/main.rs12
-rw-r--r--examples/example-pack-err/Cargo.lock235
-rw-r--r--examples/example-pack-err/Cargo.toml16
-rw-r--r--examples/example-pack-err/page.toml10
-rw-r--r--examples/example-pack-err/src/main.rs151
-rw-r--r--examples/example-pack-err/test.toml35
-rw-r--r--examples/example-panic-unwind/Cargo.lock31
-rw-r--r--examples/example-panic-unwind/Cargo.toml2
-rw-r--r--examples/example-panic-unwind/src/main.rs11
-rw-r--r--examples/example-pathfinder/Cargo.lock8
-rw-r--r--examples/example-pathfinder/src/main.rs5
-rw-r--r--examples/example-pathfinder/src/sub/mod.rs8
-rw-r--r--examples/example-repl-basic/Cargo.lock31
-rw-r--r--examples/example-repl-basic/Cargo.toml2
-rw-r--r--examples/example-repl-basic/src/main.rs42
-rw-r--r--examples/example-resources/Cargo.lock31
-rw-r--r--examples/example-resources/Cargo.toml2
-rw-r--r--examples/example-resources/src/main.rs9
-rw-r--r--examples/example-setup/Cargo.lock6
-rw-r--r--examples/example-setup/src/main.rs68
-rw-r--r--examples/example-setup/test.toml26
-rw-r--r--examples/example-structural-renderer/Cargo.lock31
-rw-r--r--examples/example-structural-renderer/Cargo.toml2
-rw-r--r--examples/example-structural-renderer/src/main.rs20
-rw-r--r--examples/example-unit-test/Cargo.lock6
-rw-r--r--examples/example-unit-test/src/main.rs47
-rw-r--r--examples/full-todolist/Cargo.lock31
-rw-r--r--examples/full-todolist/Cargo.toml2
-rw-r--r--examples/full-todolist/src/main.rs54
78 files changed, 613 insertions, 1716 deletions
diff --git a/examples/example-argument-parse/Cargo.lock b/examples/example-argument-parse/Cargo.lock
deleted file mode 100644
index 8debd86..0000000
--- a/examples/example-argument-parse/Cargo.lock
+++ /dev/null
@@ -1,223 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "equivalent"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
-
-[[package]]
-name = "example-argument-parse"
-version = "0.1.0"
-dependencies = [
- "mingling",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
-
-[[package]]
-name = "indexmap"
-version = "2.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "just_fmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6170dccbc3ea15dfb7f2da964097f814aba1dd8f746d4ffc56f33245c38e6d96"
-
-[[package]]
-name = "memchr"
-version = "2.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
-
-[[package]]
-name = "might_be_async"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eca871cea620b07bd2e6da0c883891a25bead698c43a9ab64b0fd663a7a78d5f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.118",
- "toml",
-]
-
-[[package]]
-name = "mingling"
-version = "0.4.0"
-dependencies = [
- "mingling_core",
- "mingling_macros",
- "size",
-]
-
-[[package]]
-name = "mingling_core"
-version = "0.4.0"
-dependencies = [
- "just_fmt",
- "might_be_async",
-]
-
-[[package]]
-name = "mingling_macros"
-version = "0.4.0"
-dependencies = [
- "just_fmt",
- "proc-macro2",
- "quote",
- "syn 2.0.118",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.229"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
-dependencies = [
- "serde_core",
-]
-
-[[package]]
-name = "serde_core"
-version = "1.0.229"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.229"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 3.0.3",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
-name = "syn"
-version = "2.0.118"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "3.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_write",
- "winnow",
-]
-
-[[package]]
-name = "toml_write"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
-
-[[package]]
-name = "winnow"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
-dependencies = [
- "memchr",
-]
diff --git a/examples/example-argument-parse/Cargo.toml b/examples/example-argument-parse/Cargo.toml
deleted file mode 100644
index e08adcd..0000000
--- a/examples/example-argument-parse/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "example-argument-parse"
-version = "0.1.0"
-edition = "2024"
-
-[dependencies.mingling]
-path = "../../mingling"
-
-# Enable `parser` features
-features = ["parser", "extras"]
-
-[workspace]
diff --git a/examples/example-argument-parse/page.toml b/examples/example-argument-parse/page.toml
deleted file mode 100644
index fc4d646..0000000
--- a/examples/example-argument-parse/page.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[example]
-id = "example-argument-parse"
-name = "Argument Parse"
-icon = "📋"
-category = "parsing"
-desc = """
-Shows how to use Mingling's `parser` feature with a `Picker` to extract and validate typed arguments from the command line.
-"""
-tags = ["pick", "Pickable"]
-files = ["src/main.rs", "Cargo.toml"]
diff --git a/examples/example-argument-parse/src/main.rs b/examples/example-argument-parse/src/main.rs
deleted file mode 100644
index eb07672..0000000
--- a/examples/example-argument-parse/src/main.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-//! Example Argument Parse
-//!
-//! > This example demonstrates how to use the `parser` feature to parse user input
-//!
-//! Run:
-//! ```bash
-//! cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- transfer README.md --size 32kib
-//! cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- transfer src/ --dir
-//! cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- strict-transfer README.md
-//! cargo run --manifest-path examples/example-argument-parse/Cargo.toml --quiet -- strict-transfer --dir
-//! ```
-//!
-//! Output:
-//! ```plaintext
-//! file: README.md (32768)
-//! dir: src/ (1048576)
-//! file: README.md (1048576)
-//! Error: name is not provided
-//! ```
-
-use mingling::{macros::route, prelude::*};
-use std::io::Write;
-
-dispatcher!("transfer", CMDTransfer => EntryTransfer);
-dispatcher!("strict-transfer", CMDStrictTransfer => EntryStrictTransfer);
-
-pack!(ResultFile = (bool, usize, String)); // (IsDir, Size, Name)
-
-#[chain]
-fn handle_transfer_parse(args: EntryTransfer) -> Next {
- // --------- IMPORTANT ---------
- // First parse flag arguments (like --dir/-D), then positional arguments
- let result: ResultFile = args
- // Name --dir --size 20mib
- // ^^^^^^^^^^^^_ first
- .pick::<bool>(["--dir", "-D"])
- // Name --dir
- // ^^^^^_ second (or `-D`)
- .pick_or::<usize>("--size", 1024 * 1024_usize)
- // Name
- // ^^^^_ finally, pick positional arg
- .pick::<String>(())
- .after(|str| str.trim().replace(' ', ""))
- // Unpack to tuple (is_dir, size, name)
- .unpack()
- // Convert into ResultFile
- .into();
- // --------- IMPORTANT ---------
- result.into()
-}
-
-pack!(ErrorNoNameProvided = ());
-
-#[chain]
-fn handle_strict_transfer_parse(args: EntryStrictTransfer) -> Next {
- // --------- IMPORTANT ---------
- // Strict parsing: error immediately if the name is not provided
- let result: ResultFile = route! { // Use `route!` to wrap a Picker that contains `or_route`
- args
- .pick::<bool>(["--dir", "-D"])
- .pick_or::<usize>("--size", 1024 * 1024_usize)
- // Finally parse the positional argument; if not found, route to `ErrorNoNameProvided`
- .pick_or_route::<String, _>((), ErrorNoNameProvided::default())
- .after(|str| str.trim().replace(' ', ""))
- .unpack()
- }
- // Convert into ResultFile
- .into();
- // --------- IMPORTANT ---------
- result.to_chain()
-}
-
-/// Renders the parsed transfer result (file/dir, size, name).
-#[renderer]
-fn render_result_file(result: ResultFile) -> RenderResult {
- let (is_dir, size, name) = result.into();
- let mut result = RenderResult::new();
- writeln!(
- result,
- "{}: {} ({})",
- if is_dir { "dir" } else { "file" },
- name,
- size
- )
- .ok();
- result
-}
-
-/// Renders the error when no name is provided.
-#[renderer]
-fn render_error_no_name_provided(_: ErrorNoNameProvided) -> RenderResult {
- let mut result = RenderResult::new();
- writeln!(result, "Error: name is not provided").ok();
- result
-}
-
-gen_program!();
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDTransfer);
- program.with_dispatcher(CMDStrictTransfer);
- program.exec_and_exit();
-}
diff --git a/examples/example-argument-parse/test.toml b/examples/example-argument-parse/test.toml
deleted file mode 100644
index a405bd9..0000000
--- a/examples/example-argument-parse/test.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[[runs]]
-input = [ "transfer" ]
-
-expect.exit-code = 0
-expect.result = "file: (1048576)"
-
-[[runs]]
-input = [ "transfer", "--dir", "src" ]
-
-expect.exit-code = 0
-expect.result = "dir: src (1048576)"
-
-[[runs]]
-input = [ "transfer", "--size", "500", "myfile.txt" ]
-
-expect.exit-code = 0
-expect.result = "file: myfile.txt (500)"
-
-[[runs]]
-input = [ "strict-transfer", "README.md" ]
-
-expect.exit-code = 0
-expect.result = "file: README.md (1048576)"
-
-[[runs]]
-input = [ "strict-transfer" ]
-
-expect.exit-code = 0
-expect.result = "Error: name is not provided"
diff --git a/examples/example-argument-picker/Cargo.lock b/examples/example-argument-picker/Cargo.lock
index 9977771..f7969b6 100644
--- a/examples/example-argument-picker/Cargo.lock
+++ b/examples/example-argument-picker/Cargo.lock
@@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"arg-picker",
"mingling_core",
@@ -83,7 +83,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -91,7 +91,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-argument-picker/src/main.rs b/examples/example-argument-picker/src/main.rs
index 7fcc5db..aefb86e 100644
--- a/examples/example-argument-picker/src/main.rs
+++ b/examples/example-argument-picker/src/main.rs
@@ -42,19 +42,34 @@ use mingling::setup::picker::BasicProgramSetup;
// --------- IMPORTANT ---------
-dispatcher!("calc", CMDCalculate => EntryCalculate);
+dispatcher!("calc", EntryCalculate);
-pack_err!(ErrorNumberANotProvided);
-pack_err!(ErrorNumberBNotProvided);
-pack_err!(ErrorNumberOperatorNotProvided);
-pack_err!(ErrorDivisionByZero);
+#[derive(Grouped, Default)]
+pub struct ErrorNumberANotProvided;
-pack!(StateAdd = (f32, f32));
-pack!(StateSubtract = (f32, f32));
-pack!(StateMultiply = (f32, f32));
-pack!(StateDivide = (f32, f32));
+#[derive(Grouped, Default)]
+pub struct ErrorNumberBNotProvided;
-pack!(ResultNumber = f32);
+#[derive(Grouped, Default)]
+pub struct ErrorNumberOperatorNotProvided;
+
+#[derive(Grouped, Default)]
+pub struct ErrorDivisionByZero;
+
+#[derive(Grouped, Wrap)]
+pub struct StateAdd((f32, f32));
+
+#[derive(Grouped, Wrap)]
+pub struct StateSubtract((f32, f32));
+
+#[derive(Grouped, Wrap)]
+pub struct StateMultiply((f32, f32));
+
+#[derive(Grouped, Wrap)]
+pub struct StateDivide((f32, f32));
+
+#[derive(Grouped, Wrap)]
+pub struct ResultNumber(f32);
#[derive(Grouped)]
struct StateCalculate {
@@ -125,7 +140,6 @@ fn main() {
program.with_resource(ResNumberDisplaySetting { round: *round });
// --------- IMPORTANT ---------
- program.with_dispatcher(CMDCalculate);
program.exec_and_exit();
}
@@ -136,13 +150,13 @@ fn handle_calc(args: EntryCalculate) -> Next {
// Use the arg! macro to define a positional argument of type f32
// |
// vvvvvvvvvv
- args.pick_or_route(&arg![f32], || ErrorNumberANotProvided::default().to_chain())
+ args.pick_or_route(&arg![f32], || ErrorNumberANotProvided.to_chain())
.pick_or_route(&arg![Operator], || {
- ErrorNumberOperatorNotProvided::default().to_chain()
+ ErrorNumberOperatorNotProvided.to_chain()
}) // Returns a routable type when not found or fails to parse
// |
- // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
- .pick_or_route(&arg![f32], || ErrorNumberBNotProvided::default().to_chain())
+ // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ .pick_or_route(&arg![f32], || ErrorNumberBNotProvided.to_chain())
// Use `to_result` to parse arguments
// and convert to Result<(Tuple, ...), Route> type
.to_result()
@@ -150,7 +164,7 @@ fn handle_calc(args: EntryCalculate) -> Next {
// --------- IMPORTANT ---------
if operator == Operator::Slash && number_b == 0. {
- return ErrorDivisionByZero::default().to_chain();
+ return ErrorDivisionByZero.to_chain();
}
StateCalculate {
@@ -164,41 +178,41 @@ fn handle_calc(args: EntryCalculate) -> Next {
#[chain]
fn handle_state_calculate(state: StateCalculate) -> Next {
match (state.operator, state.number_a, state.number_b) {
- (Operator::Plus, a, b) => StateAdd::new((a, b)).to_chain(),
- (Operator::Dash, a, b) => StateSubtract::new((a, b)).to_chain(),
- (Operator::Slash, a, b) => StateDivide::new((a, b)).to_chain(),
- (Operator::Star, a, b) => StateMultiply::new((a, b)).to_chain(),
+ (Operator::Plus, a, b) => StateAdd((a, b)).to_chain(),
+ (Operator::Dash, a, b) => StateSubtract((a, b)).to_chain(),
+ (Operator::Slash, a, b) => StateDivide((a, b)).to_chain(),
+ (Operator::Star, a, b) => StateMultiply((a, b)).to_chain(),
}
}
#[chain]
fn handle_state_add(state_add: StateAdd) -> ResultNumber {
- let (a, b) = state_add.inner;
- ResultNumber::new(a + b)
+ let (a, b) = state_add.0;
+ ResultNumber(a + b)
}
#[chain]
fn handle_state_subtract(state_subtract: StateSubtract) -> ResultNumber {
- let (a, b) = state_subtract.inner;
- ResultNumber::new(a - b)
+ let (a, b) = state_subtract.0;
+ ResultNumber(a - b)
}
#[chain]
fn handle_state_multiply(state_multiply: StateMultiply) -> ResultNumber {
- let (a, b) = state_multiply.inner;
- ResultNumber::new(a * b)
+ let (a, b) = state_multiply.0;
+ ResultNumber(a * b)
}
#[chain]
fn handle_state_divide(state_divide: StateDivide) -> ResultNumber {
- let (a, b) = state_divide.inner;
- ResultNumber::new(a / b)
+ let (a, b) = state_divide.0;
+ ResultNumber(a / b)
}
#[renderer]
fn render_result_number(result: ResultNumber, setting: &ResNumberDisplaySetting) -> String {
let round = setting.round;
- let result = if round { result.round() } else { result.inner };
+ let result = if round { result.round() } else { result.0 };
format!("Result: {}", result)
}
diff --git a/examples/example-async-support/Cargo.lock b/examples/example-async-support/Cargo.lock
index 67cd6b6..f122f6d 100644
--- a/examples/example-async-support/Cargo.lock
+++ b/examples/example-async-support/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -58,16 +75,16 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -75,7 +92,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -146,12 +163,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-async-support/Cargo.toml b/examples/example-async-support/Cargo.toml
index d1b952d..a0d2a75 100644
--- a/examples/example-async-support/Cargo.toml
+++ b/examples/example-async-support/Cargo.toml
@@ -6,8 +6,8 @@ edition = "2024"
[dependencies.mingling]
path = "../../mingling"
-# Enable `parser` features
-features = ["async", "parser"]
+# Enable `picker` features
+features = ["async", "picker"]
# Import any async runtime, e.g. Tokio
[dependencies.tokio]
diff --git a/examples/example-async-support/src/main.rs b/examples/example-async-support/src/main.rs
index af86408..7e212d9 100644
--- a/examples/example-async-support/src/main.rs
+++ b/examples/example-async-support/src/main.rs
@@ -30,8 +30,6 @@ use std::io::Write;
async fn main() {
let mut program = ThisProgram::new();
- program.with_dispatcher(CMDDownload);
-
// Add a hook to display when the download begins
program.with_hook(ProgramHook::empty().on_begin::<_, ()>(|_| println!("Download begin")));
@@ -41,15 +39,16 @@ async fn main() {
// --------- IMPORTANT ---------
}
-dispatcher!("download", CMDDownload => EntryDownload);
+dispatcher!("download", EntryDownload);
-pack!(ResultDownloaded = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultDownloaded(String);
// --------- IMPORTANT ---------
#[chain]
// vvvvv_ `async` keyword can be used directly here
pub async fn handle_download(args: EntryDownload) -> Next {
- let file_name = args.pick(()).unpack();
+ let file_name = args.pick_or_default(&arg![String]).unwrap();
fake_download(file_name).await.into()
}
@@ -67,5 +66,5 @@ gen_program!();
async fn fake_download(file_name: String) -> ResultDownloaded {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
- ResultDownloaded::new(file_name)
+ ResultDownloaded(file_name)
}
diff --git a/examples/example-basic/Cargo.lock b/examples/example-basic/Cargo.lock
index 6be449c..e38b91d 100644
--- a/examples/example-basic/Cargo.lock
+++ b/examples/example-basic/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-basic/src/main.rs b/examples/example-basic/src/main.rs
index 17077e2..ce41b2d 100644
--- a/examples/example-basic/src/main.rs
+++ b/examples/example-basic/src/main.rs
@@ -17,40 +17,38 @@ use mingling::prelude::*;
use std::io::Write;
// Define the `greet` subcommand
-// _____________________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
-// / _____________________ dispatcher name
-// | / _________ entry, records raw arguments
-// | | / ^^^^^^^^^^^^^
-// vvvvv vvvvvvvv vvvvvvvvvv \_ equivalent to pack!(EntryGreet = Vec<String>)
-dispatcher!("greet", CMDGreet => EntryGreet);
+// _________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
+// /
+// | _________ entry, records raw arguments
+// | / ^^^^^^^^^^^^^
+// vvvvv vvvvvvvvvv \_ a newtype wrapper around Vec<String>
+dispatcher!("greet", EntryGreet);
fn main() {
// Create a new ThisProgram
- let mut program = ThisProgram::new();
-
- // Add the CMDGreet dispatcher
- program.with_dispatcher(CMDGreet);
+ let program = ThisProgram::new();
// Run the program, then exit the process
program.exec_and_exit();
}
// Quickly wrap a type into a type recognizable by the current program
-// ____________________ Wrapped type name
-// / _______ Wrapped type inner value
-// | /
-// vvvvvvvvvv vvvvvv
-pack!(ResultName = String);
+// ___________________ Registers this type into ThisProgram
+// / _______ Adds DerefMut, Deref, Into, From wrappers
+// | /
+// vvvvvvvvvv vvvvv
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
// Define the `handle_greet` chain for parsing input text
// ____________________ Previous type:
// / Mingling deduces types at runtime and routes them to this function
// | _____ will be expanded to:
-// | / impl Into<mingling::ChainProcess<ThisProgram>>
+// | / ChainProcess<ThisProgram>
#[chain] // vvvvvvvvvv vvvv
fn handle_greet(args: EntryGreet) -> Next {
let name: ResultName = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
diff --git a/examples/example-clap-binding/Cargo.lock b/examples/example-clap-binding/Cargo.lock
index 46d334e..1eb895f 100644
--- a/examples/example-clap-binding/Cargo.lock
+++ b/examples/example-clap-binding/Cargo.lock
@@ -166,7 +166,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -174,7 +174,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -182,7 +182,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-clap-binding/src/main.rs b/examples/example-clap-binding/src/main.rs
index d25c5f3..6ff963b 100644
--- a/examples/example-clap-binding/src/main.rs
+++ b/examples/example-clap-binding/src/main.rs
@@ -60,7 +60,6 @@ fn main() {
// Capture Clap's help information and write to RenderResult
// --------- IMPORTANT ---------
- program.with_dispatcher(CMDGreet);
program.exec_and_exit();
}
@@ -72,7 +71,7 @@ fn main() {
// vvvvvvv vvvvvvvvvvvv vvvvvvv
#[derive(Default, clap::Parser, Grouped)]
#[dispatcher_clap(
- "greet", CMDGreet, // Bind EntryGreet to "greet" command
+ "greet", // Bind EntryGreet to "greet" command
help = true, // Generate clap help for EntryGreet
error = ErrorGreetParsed, // Generate and bind error type for parse failure
// ^^^^^\__ Using `error` intercepts parse failure information into the specified type,
diff --git a/examples/example-combine-pathf-dispatch-tree/Cargo.lock b/examples/example-combine-pathf-dispatch-tree/Cargo.lock
index 8560b73..9fdbf4f 100644
--- a/examples/example-combine-pathf-dispatch-tree/Cargo.lock
+++ b/examples/example-combine-pathf-dispatch-tree/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -84,7 +84,7 @@ dependencies = [
[[package]]
name = "mingling_pathf"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs b/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs
index 2b7aba9..b04c683 100644
--- a/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs
+++ b/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs
@@ -4,12 +4,13 @@ use std::io::Write;
dispatcher!("hello");
-pack!(ResultMessage = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultMessage(String);
#[chain]
pub fn handle_my(args: EntryHello) -> Next {
let name: ResultMessage = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
diff --git a/examples/example-combine-pathf-metadata/Cargo.lock b/examples/example-combine-pathf-metadata/Cargo.lock
index 745167a..0e1782e 100644
--- a/examples/example-combine-pathf-metadata/Cargo.lock
+++ b/examples/example-combine-pathf-metadata/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -84,7 +84,7 @@ dependencies = [
[[package]]
name = "mingling_pathf"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-combine-pathf-metadata/src/main.rs b/examples/example-combine-pathf-metadata/src/main.rs
index a68eac5..894e235 100644
--- a/examples/example-combine-pathf-metadata/src/main.rs
+++ b/examples/example-combine-pathf-metadata/src/main.rs
@@ -24,10 +24,7 @@ mod sub;
use mingling::prelude::*;
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(sub::CMDHello);
- program.with_dispatcher(sub::CMDDescription);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
gen_program!();
diff --git a/examples/example-combine-pathf-metadata/src/sub/mod.rs b/examples/example-combine-pathf-metadata/src/sub/mod.rs
index 2e6776e..38efa2f 100644
--- a/examples/example-combine-pathf-metadata/src/sub/mod.rs
+++ b/examples/example-combine-pathf-metadata/src/sub/mod.rs
@@ -7,8 +7,9 @@ use std::io::Write;
// Implicit dispatcher form — creates `CMDHello` / `EntryHello` in this module
dispatcher!("hello");
+
// Creates `CMDDescription` / `EntryDescription` in this module
-dispatcher!("desc", CMDDescription => EntryDescription);
+dispatcher!("desc", EntryDescription);
/// The metadata type attached to an entry (`DataType`).
#[derive(Debug, PartialEq, Eq)]
@@ -27,14 +28,17 @@ pub fn hello_desc() -> Description {
}
}
-pack!(ResultName = String);
-pack!(DescResult = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
+
+#[derive(Grouped, Wrap)]
+pub struct DescResult(String);
/// Chain for `hello` — reads the name and produces a `ResultName`.
#[chain]
pub fn handle_hello(args: EntryHello) -> Next {
let name: ResultName = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
@@ -51,7 +55,7 @@ pub fn handle_desc(_args: EntryDescription) -> Next {
None => "EntryHello has no description".to_string(),
};
// --------- IMPORTANT ---------
- DescResult::new(msg).to_render()
+ DescResult(msg).to_render()
}
/// Renders the greeting message with the provided name.
diff --git a/examples/example-command-macro/Cargo.lock b/examples/example-command-macro/Cargo.lock
index cd1babf..53d6f18 100644
--- a/examples/example-command-macro/Cargo.lock
+++ b/examples/example-command-macro/Cargo.lock
@@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"arg-picker",
"mingling_core",
@@ -83,7 +83,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -91,7 +91,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-command-macro/src/main.rs b/examples/example-command-macro/src/main.rs
index 2bf932a..6740518 100644
--- a/examples/example-command-macro/src/main.rs
+++ b/examples/example-command-macro/src/main.rs
@@ -19,37 +19,33 @@
use mingling::{macros::buffer, picker::IntoPicker, prelude::*};
fn main() {
- let mut program = ThisProgram::new();
-
- // Import the dispatchers generated by the `#[command]` macro
- program.with_dispatcher(CMDHelloWorld);
- program.with_dispatcher(CMDGreetSomeone);
- program.with_dispatcher(CMDGoodBye);
-
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
-pack!(ResultGreeting = String);
-pack!(ResultGoodbye = ());
+#[derive(Grouped, Wrap)]
+pub struct ResultGreeting(String);
+
+#[derive(Grouped)]
+pub struct ResultGoodbye;
// --------- IMPORTANT ---------
-// Auto-generates dispatcher!("hello.world", CMDHelloWorld => EntryHelloWorld);
+// Auto-generates dispatcher!("hello.world", EntryHelloWorld);
#[command]
fn hello_world() -> ResultGreeting {
- ResultGreeting::new("World".to_string())
+ ResultGreeting("World".to_string())
}
-// Auto-generates dispatcher!("hello-world", CMDGreetSomeone => EntryGreetSomeone);
+// Auto-generates dispatcher!("hello-world", EntryGreetSomeone);
#[command(node = "greet-someone")]
fn greet_someone(args: Vec<String>) -> ResultGreeting {
let name = args.pick_or(&arg![String], || "World".to_string()).unwrap();
- ResultGreeting::new(name)
+ ResultGreeting(name)
}
-// Auto-generates dispatcher!("goodbye", CMDGoodBye => EntryGoodBye);
-#[command(name = CMDGoodBye, entry = EntryGoodBye)]
+// Auto-generates dispatcher!("goodbye", EntryGoodBye);
+#[command(entry = EntryGoodBye)]
fn goodbye() -> ResultGoodbye {
- ResultGoodbye::default()
+ ResultGoodbye
}
// --------- IMPORTANT ---------
diff --git a/examples/example-completion/Cargo.lock b/examples/example-completion/Cargo.lock
index dab3f37..d4b2f33 100644
--- a/examples/example-completion/Cargo.lock
+++ b/examples/example-completion/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt 0.2.0",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -84,16 +101,16 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt 0.2.0",
"just_template",
@@ -102,7 +119,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt 0.2.0",
"proc-macro2",
@@ -167,12 +184,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-completion/Cargo.toml b/examples/example-completion/Cargo.toml
index 00c7f8c..9884f4e 100644
--- a/examples/example-completion/Cargo.toml
+++ b/examples/example-completion/Cargo.toml
@@ -9,7 +9,7 @@ path = "../../mingling"
features = [
# Enable `comp` features
"comp",
- "parser",
+ "picker",
]
[build-dependencies.mingling]
diff --git a/examples/example-completion/src/main.rs b/examples/example-completion/src/main.rs
index d65be49..389cf74 100644
--- a/examples/example-completion/src/main.rs
+++ b/examples/example-completion/src/main.rs
@@ -44,19 +44,11 @@
//! Hello, Alice, Alice, Alice!
//! ```
-use mingling::{macros::suggest, prelude::*, ShellContext, Suggest};
+use mingling::{ShellContext, Suggest, macros::suggest, prelude::*};
use std::io::Write;
fn main() {
- let mut program = ThisProgram::new();
-
- program.with_dispatcher(CMDGreet);
-
- // --------- IMPORTANT ---------
- // The `comp` feature makes `gen_program!()` generate a CMDCompletion automatically
- // It adds a hidden `__comp` subcommand for communication with the completion script
- program.with_dispatcher(crate::CMDCompletion);
- // --------- IMPORTANT ---------
+ let program = ThisProgram::new();
// TIP: Note that the completion script reads stdout,
// so make sure no output is produced before the CMDCompletion is dispatched.
@@ -64,12 +56,12 @@ fn main() {
}
// --------- IMPORTANT ---------
-// __________________________________________ Entry point bound to completion behavior
-// / _________________________ Shell context for obtaining user input state
-// | / ________ Suggest, used to return completion results
-// vvvvvvvvvv | /
-#[completion(EntryGreet)] // vvvvvvvvvvvv vvvvvvv
-fn complete_greet_entry(ctx: &ShellContext) -> Suggest {
+// _________________________________________ Entry point bound to completion behavior
+// / _________________________ Shell context for obtaining user input state
+// | / ________ Suggest, used to return completion results
+// vvvvvvvvvv | /
+#[completion(EntryGreet)] // vvvvvvvvvvvv vvvvvvv
+fn complete_greet_entry(ctx: ShellContext) -> Suggest {
// When the previous word is `greet` (the current command being typed)
if ctx.previous_word == "greet" {
// Return suggestions
@@ -82,18 +74,22 @@ fn complete_greet_entry(ctx: &ShellContext) -> Suggest {
}
// When the user is typing `--repeat`
- if ctx.filling_argument(["-r", "--repeat"]) {
+ if ctx.previous_word == "-r" || ctx.previous_word == "--repeat" {
return suggest! {}; // Don't suggest anything
}
// When the user is typing `-`
- if ctx.typing_argument() {
- return suggest! {
+ if ctx.current_word.starts_with('-') {
+ // Remove arguments that have already been typed by the user
+ let typed: Vec<&str> = ctx.all_words.iter().map(String::as_str).collect();
+ let mut set = suggest! {
"-r": "Number of repetitions",
"--repeat": "Number of repetitions",
+ };
+ if let Suggest::Suggest(items) = &mut set {
+ items.retain(|item| !typed.contains(&item.suggest().as_str()));
}
- // Remove arguments that have already been typed by the user
- .strip_typed_argument(ctx);
+ return set;
}
// Otherwise, suggest nothing
@@ -104,15 +100,16 @@ fn complete_greet_entry(ctx: &ShellContext) -> Suggest {
}
// --------- IMPORTANT ---------
-dispatcher!("greet", CMDGreet => EntryGreet);
-pack!(ResultName = (u8, String));
+dispatcher!("greet", EntryGreet);
+#[derive(Grouped, Wrap)]
+pub struct ResultName((u8, String));
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
let result: ResultName = args
- .pick_or(["-r", "--repeat"], 1)
- .pick_or((), "World")
- .unpack()
+ .pick_or(&arg![repeat: u8, 'r'], || 1)
+ .pick_or(&arg![String], || "World".to_string())
+ .unwrap()
.into();
result.into()
}
@@ -120,7 +117,7 @@ fn handle_greet(args: EntryGreet) -> Next {
/// Renders the greeting with the result name and repeat count.
#[renderer]
fn render_name(result: ResultName) -> RenderResult {
- let (repeat, name) = result.inner;
+ let (repeat, name) = result.0;
let mut render_result = RenderResult::new();
let mut parts = Vec::with_capacity(repeat as usize);
for _ in 0..repeat {
diff --git a/examples/example-custom-pickable/Cargo.lock b/examples/example-custom-pickable/Cargo.lock
deleted file mode 100644
index 11f417a..0000000
--- a/examples/example-custom-pickable/Cargo.lock
+++ /dev/null
@@ -1,223 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "equivalent"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
-
-[[package]]
-name = "example-custom-pickable"
-version = "0.1.0"
-dependencies = [
- "mingling",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
-
-[[package]]
-name = "indexmap"
-version = "2.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "just_fmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6170dccbc3ea15dfb7f2da964097f814aba1dd8f746d4ffc56f33245c38e6d96"
-
-[[package]]
-name = "memchr"
-version = "2.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
-
-[[package]]
-name = "might_be_async"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eca871cea620b07bd2e6da0c883891a25bead698c43a9ab64b0fd663a7a78d5f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.118",
- "toml",
-]
-
-[[package]]
-name = "mingling"
-version = "0.4.0"
-dependencies = [
- "mingling_core",
- "mingling_macros",
- "size",
-]
-
-[[package]]
-name = "mingling_core"
-version = "0.4.0"
-dependencies = [
- "just_fmt",
- "might_be_async",
-]
-
-[[package]]
-name = "mingling_macros"
-version = "0.4.0"
-dependencies = [
- "just_fmt",
- "proc-macro2",
- "quote",
- "syn 2.0.118",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.229"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
-dependencies = [
- "serde_core",
-]
-
-[[package]]
-name = "serde_core"
-version = "1.0.229"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.229"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 3.0.3",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
-name = "syn"
-version = "2.0.118"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "3.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_write",
- "winnow",
-]
-
-[[package]]
-name = "toml_write"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
-
-[[package]]
-name = "winnow"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
-dependencies = [
- "memchr",
-]
diff --git a/examples/example-custom-pickable/Cargo.toml b/examples/example-custom-pickable/Cargo.toml
deleted file mode 100644
index 9324bd6..0000000
--- a/examples/example-custom-pickable/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "example-custom-pickable"
-version = "0.1.0"
-edition = "2024"
-
-[dependencies.mingling]
-path = "../../mingling"
-
-features = ["parser", "extras"]
-
-[workspace]
diff --git a/examples/example-custom-pickable/page.toml b/examples/example-custom-pickable/page.toml
deleted file mode 100644
index 1c3bfa0..0000000
--- a/examples/example-custom-pickable/page.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[example]
-id = "example-custom-pickable"
-name = "Custom Pickable"
-icon = "🎯"
-category = "parsing"
-desc = """
-Shows how to implement the `Pickable` trait on custom types for seamless extraction from CLI arguments via Picker.
-"""
-tags = ["Pickable", "custom"]
-files = ["src/main.rs", "Cargo.toml"]
diff --git a/examples/example-custom-pickable/src/main.rs b/examples/example-custom-pickable/src/main.rs
deleted file mode 100644
index b163278..0000000
--- a/examples/example-custom-pickable/src/main.rs
+++ /dev/null
@@ -1,132 +0,0 @@
-//! Example Custom Pickable
-//!
-//! > This example demonstrates how to use the Pickable trait to add parsing for your types
-//!
-//! Run:
-//! ```bash
-//! cargo run --manifest-path examples/example-custom-pickable/Cargo.toml --quiet -- connect 127.0.0.1:5012
-//! cargo run --manifest-path examples/example-custom-pickable/Cargo.toml --quiet -- connect 127.0.0.1
-//! ```
-//!
-//! Output:
-//! ```plaintext
-//! Connected to "127.0.0.1:5012"
-//! Failed to parse address
-//! ```
-
-use mingling::{macros::route, parser::Pickable, prelude::*, Grouped};
-use std::io::Write;
-
-// Define types that can be recognized by Mingling
-// ________________________ `Pickable` trait needs to implement Default
-// / ________ The Grouped derive macro registers an ID for this type
-// | / Mingling uses this ID to identify the type
-// vvvvvvv vvvvvvv
-#[derive(Debug, Default, Clone, Grouped)]
-pub struct Address {
- pub ip: [u8; 4],
- pub port: u16,
-}
-
-// --------- IMPORTANT ---------
-impl Pickable for Address {
- type Output = Address;
- fn pick(args: &mut mingling::parser::Argument, flag: mingling::Flag) -> Option<Self::Output> {
- // Extract the raw string from Argument using the Flag
- let raw: String = args.pick_argument(flag)?.clone();
-
- // Use TryFrom to parse the address
- Address::try_from(raw).ok()
- }
-}
-// --------- IMPORTANT ---------
-
-dispatcher!("connect", CMDConnect => EntryConnect);
-pack!(ErrorParseAddressFailed = ());
-
-#[chain]
-fn handle_connect(prev: EntryConnect) -> Next {
- let connect: Address =
- route! { prev.pick_or_route((), ErrorParseAddressFailed::default()).unpack() };
- connect.to_chain()
-}
-
-/// Renders the connected address.
-#[renderer]
-pub fn render_address(addr: Address) -> RenderResult {
- let mut render_result = RenderResult::new();
- write!(render_result, "Connected to \"{}\"", addr).ok();
- render_result
-}
-
-/// Renders the error message when address parsing fails.
-#[renderer]
-pub fn render_error_parse_address_failed(_: ErrorParseAddressFailed) -> RenderResult {
- let mut render_result = RenderResult::new();
- write!(render_result, "Failed to parse address").ok();
- render_result
-}
-
-gen_program!();
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDConnect);
- program.exec_and_exit();
-}
-
-// Address conversion
-
-impl TryFrom<String> for Address {
- type Error = String;
-
- fn try_from(raw: String) -> Result<Self, Self::Error> {
- // Expected format: "192.168.1.1:8080"
- let parts: Vec<&str> = raw.split(':').collect();
- if parts.len() != 2 {
- return Err("Invalid format: expected 'IP:PORT'".to_string());
- }
-
- let ip_str = parts[0];
- let port_str = parts[1];
-
- // Parse IP address (4 octets separated by dots)
- let ip_parts: Vec<&str> = ip_str.split('.').collect();
- if ip_parts.len() != 4 {
- return Err("Invalid IP address format".to_string());
- }
-
- let mut ip = [0u8; 4];
- for (i, part) in ip_parts.iter().enumerate() {
- ip[i] = part
- .parse::<u8>()
- .map_err(|_| format!("Invalid IP octet: {part}"))?;
- }
-
- // Parse port
- let port = port_str
- .parse::<u16>()
- .map_err(|_| format!("Invalid port: {port_str}"))?;
-
- Ok(Address { ip, port })
- }
-}
-
-impl From<Address> for String {
- fn from(addr: Address) -> String {
- format!(
- "{}.{}.{}.{}:{}",
- addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], addr.port
- )
- }
-}
-
-impl std::fmt::Display for Address {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(
- f,
- "{}.{}.{}.{}:{}",
- self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port
- )
- }
-}
diff --git a/examples/example-custom-pickable/test.toml b/examples/example-custom-pickable/test.toml
deleted file mode 100644
index 8fc20eb..0000000
--- a/examples/example-custom-pickable/test.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[[runs]]
-input = [ "connect", "192.168.1.1:8080" ]
-
-expect.exit-code = 0
-expect.result = "Connected to \"192.168.1.1:8080\""
-
-[[runs]]
-input = [ "connect" ]
-
-expect.exit-code = 0
-expect.result = "Failed to parse address"
-
-[[runs]]
-input = [ "connect", "invalid" ]
-
-expect.exit-code = 0
-expect.result = "Failed to parse address"
diff --git a/examples/example-dispatch-tree/Cargo.lock b/examples/example-dispatch-tree/Cargo.lock
index 015d536..b80a18e 100644
--- a/examples/example-dispatch-tree/Cargo.lock
+++ b/examples/example-dispatch-tree/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-dispatch-tree/src/main.rs b/examples/example-dispatch-tree/src/main.rs
index 9f76f15..bba9c2e 100644
--- a/examples/example-dispatch-tree/src/main.rs
+++ b/examples/example-dispatch-tree/src/main.rs
@@ -3,11 +3,9 @@
//! > This example will introduce how to use `dispatch_tree`
//! > to optimize your command line lookup efficiency
//!
-//! When the number of commands in your project increases, you can use `dispatch_tree` to complete command registration at compile time.
-//! It will generate a trie for quickly finding related commands by prefix.
-//!
-//! Therefore, after enabling this feature,
-//! `Program` will no longer store a Dispatcher list internally, and the `with_dispatcher` function will not be compiled.
+//! When the number of commands in your project increases, you can enable
+//! `dispatch_tree` to switch command matching from a linear scan to a
+//! character-level trie.
//!
//! Run:
//! ```bash
@@ -25,30 +23,24 @@ use std::io::Write;
// --------- IMPORTANT ---------
// You have a large number of subcommands
-dispatcher!("cmd1", CMD1 => Entry1);
-dispatcher!("cmd2.sub1", CMD2Sub1 => Entry2Sub1);
-dispatcher!("cmd2.sub2", CMD2Sub2 => Entry2Sub2);
-dispatcher!("cmd3.sub1.leaf1", CMD3Sub1Leaf1 => Entry3Sub1Leaf1);
-dispatcher!("cmd3.sub1.leaf2", CMD3Sub1Leaf2 => Entry3Sub1Leaf2);
-dispatcher!("cmd3.sub2", CMD3Sub2 => Entry3Sub2);
-dispatcher!("cmd4.sub1.subsub1.deep", CMD4Deep => Entry4Deep);
-dispatcher!("cmd4.sub1.subsub2", CMD4SubSub2 => Entry4SubSub2);
-dispatcher!("cmd5", CMD5 => Entry5);
-dispatcher!("cmd5.extra", CMD5Extra => Entry5Extra);
-dispatcher!("nested.a.b.c", CMDA => EntryA);
-dispatcher!("nested.a.b.d", CMDB => EntryB);
-dispatcher!("nested.a.e", CMDC => EntryC);
-dispatcher!("nested.f", CMDD => EntryD);
+dispatcher!("cmd1", Entry1);
+dispatcher!("cmd2.sub1", Entry2Sub1);
+dispatcher!("cmd2.sub2", Entry2Sub2);
+dispatcher!("cmd3.sub1.leaf1", Entry3Sub1Leaf1);
+dispatcher!("cmd3.sub1.leaf2", Entry3Sub1Leaf2);
+dispatcher!("cmd3.sub2", Entry3Sub2);
+dispatcher!("cmd4.sub1.subsub1.deep", Entry4Deep);
+dispatcher!("cmd4.sub1.subsub2", Entry4SubSub2);
+dispatcher!("cmd5", Entry5);
+dispatcher!("cmd5.extra", Entry5Extra);
+dispatcher!("nested.a.b.c", EntryA);
+dispatcher!("nested.a.b.d", EntryB);
+dispatcher!("nested.a.e", EntryC);
+dispatcher!("nested.f", EntryD);
// --------- IMPORTANT ---------
fn main() {
let program = ThisProgram::new();
-
- // --------- IMPORTANT ---------
- // // You no longer need to use `with_dispatcher` anymore;
- // // it'll be collected automatically once the `dispatch_tree` feature is enabled
- // program.with_dispatcher(...);
-
program.exec_and_exit();
}
diff --git a/examples/example-enum-tag/Cargo.lock b/examples/example-enum-tag/Cargo.lock
index b9de59b..492d708 100644
--- a/examples/example-enum-tag/Cargo.lock
+++ b/examples/example-enum-tag/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt 0.2.0",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -84,16 +101,16 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt 0.2.0",
"just_template",
@@ -102,7 +119,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt 0.2.0",
"proc-macro2",
@@ -167,12 +184,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-enum-tag/Cargo.toml b/examples/example-enum-tag/Cargo.toml
index 9c0a0ff..489f401 100644
--- a/examples/example-enum-tag/Cargo.toml
+++ b/examples/example-enum-tag/Cargo.toml
@@ -8,7 +8,7 @@ path = "../../mingling"
features = [
"comp",
- "parser"
+ "picker"
]
[workspace]
diff --git a/examples/example-enum-tag/src/main.rs b/examples/example-enum-tag/src/main.rs
index b57511d..63ac3ba 100644
--- a/examples/example-enum-tag/src/main.rs
+++ b/examples/example-enum-tag/src/main.rs
@@ -16,8 +16,10 @@
//! ```
use mingling::{
- macros::suggest_enum, parser::PickableEnum, prelude::*, EnumTag, Grouped, ShellContext,
- Suggest,
+ EnumTag, Grouped, ShellContext, Suggest,
+ macros::suggest_enum,
+ picker::{PickerArgResult, SinglePickable},
+ prelude::*,
};
use std::io::Write;
@@ -57,9 +59,7 @@ pub enum ProgrammingLanguages {
#[enum_desc("A general-purpose programming language with clean syntax, known for readability")]
Python,
- #[enum_desc(
- "An object-oriented scripting language, famous for its concise and elegant syntax"
- )]
+ #[enum_desc("An object-oriented scripting language, famous for its concise and elegant syntax")]
Ruby,
#[default]
@@ -68,17 +68,39 @@ pub enum ProgrammingLanguages {
}
// --------- IMPORTANT ---------
-// Implement the PickableEnum trait for ProgrammingLanguages,
-// so that `Picker` can parse this enum
-impl PickableEnum for ProgrammingLanguages {}
+// NOTE: Due to the migration from the legacy `parser` to `picker`, the `EnumTag` -> `Picker` path
+// is not yet complete, so a manual implementation is used for now.
+// Once that path is complete, `#[derive(EnumTag)]` can automatically implement `SinglePickable`,
+// replacing this manual implementation.
+impl SinglePickable for ProgrammingLanguages {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ let Some(str) = str else {
+ return PickerArgResult::NotFound;
+ };
+ let lang = match str.to_lowercase().as_str() {
+ "c" => Self::C,
+ "c++" | "cpp" => Self::CPlusPlus,
+ "c#" | "csharp" => Self::Csharp,
+ "java" => Self::Java,
+ "javascript" | "js" => Self::JavaScript,
+ "kotlin" => Self::Kotlin,
+ "ocaml" => Self::OCaml,
+ "python" => Self::Python,
+ "ruby" => Self::Ruby,
+ "rust" => Self::Rust,
+ _ => return PickerArgResult::NotFound,
+ };
+ PickerArgResult::Parsed(lang)
+ }
+}
// --------- IMPORTANT ---------
-dispatcher!("lang-select", CMDLanguageSelection => EntryLanguageSelection);
+dispatcher!("lang-select", EntryLanguageSelection);
#[chain]
fn handle_language_selection(args: EntryLanguageSelection) -> Next {
// You can use Picker to directly parse ProgrammingLanguages
- let lang: ProgrammingLanguages = args.pick(()).unpack();
+ let lang: ProgrammingLanguages = args.pick_or_default(&arg![ProgrammingLanguages]).unwrap();
lang.into()
}
@@ -92,7 +114,7 @@ pub fn render_programming_language(lang: ProgrammingLanguages) -> RenderResult {
}
#[completion(EntryLanguageSelection)]
-fn complete_language_selection(_: &ShellContext) -> Suggest {
+fn complete_language_selection(_: ShellContext) -> Suggest {
// Use `suggest_enum!` directly to generate enum suggestions
suggest_enum!(ProgrammingLanguages)
}
@@ -100,8 +122,5 @@ fn complete_language_selection(_: &ShellContext) -> Suggest {
gen_program!();
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDCompletion);
- program.with_dispatcher(CMDLanguageSelection);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
diff --git a/examples/example-error-handling/Cargo.lock b/examples/example-error-handling/Cargo.lock
index f03ca4d..3110ae9 100644
--- a/examples/example-error-handling/Cargo.lock
+++ b/examples/example-error-handling/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-error-handling/src/main.rs b/examples/example-error-handling/src/main.rs
index 0cd973a..ec7e6c9 100644
--- a/examples/example-error-handling/src/main.rs
+++ b/examples/example-error-handling/src/main.rs
@@ -26,38 +26,44 @@ use std::io::Write;
// In Mingling, instead of using ? to propagate errors upward,
// errors are treated as branches that continue execution.
-dispatcher!("hello", CMDHello => EntryHello);
+dispatcher!("hello", EntryHello);
// Define error types
-pack!(ErrorNoNameProvided = ());
-pack!(ErrorNameTooLong = u16);
-pack!(ErrorNameNotAvailable = ());
+#[derive(Grouped)]
+pub struct ErrorNoNameProvided;
+
+#[derive(Grouped, Wrap)]
+pub struct ErrorNameTooLong(u16);
+
+#[derive(Grouped)]
+pub struct ErrorNameNotAvailable;
// Define success type
-pack!(ResultName = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
// Pre-registered names
static VEC_REGISTERED_NAMES: &[&str] = &["Alice", "Bob", "Charlie", "David", "Eve"];
#[chain]
fn handle_hello(args: EntryHello) -> Next {
- let Some(name) = args.inner.first().cloned() else {
+ let Some(name) = args.0.first().cloned() else {
// If no name is provided, pass ErrorNoNameProvided
- return ErrorNoNameProvided::default().to_render();
+ return ErrorNoNameProvided.to_render();
};
if name.len() > 10 {
// If the name is too long, pass ErrorNameTooLong
- return ErrorNameTooLong::new(name.len() as u16).to_render();
+ return ErrorNameTooLong(name.len() as u16).to_render();
}
if VEC_REGISTERED_NAMES.contains(&name.as_str()) {
// If the name already exists, pass ErrorNameNotAvailable
- return ErrorNameNotAvailable::default().to_render();
+ return ErrorNameNotAvailable.to_render();
}
// If the name is valid, pass ResultName
- ResultName::new(name).to_render()
+ ResultName(name).to_render()
}
/// Renders a successful greeting with the given name.
@@ -96,19 +102,12 @@ fn render_error_name_too_long(len: ErrorNameTooLong) -> RenderResult {
#[renderer]
fn render_entry_fallback(err: EntryFallback) -> RenderResult {
let mut render_result = RenderResult::new();
- writeln!(
- render_result,
- "Command not found: \"{}\"",
- err.inner.join(" ")
- )
- .ok();
+ writeln!(render_result, "Command not found: \"{}\"", err.0.join(" ")).ok();
render_result
}
gen_program!();
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDHello);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
diff --git a/examples/example-exitcode/Cargo.lock b/examples/example-exitcode/Cargo.lock
index 2924262..37170f2 100644
--- a/examples/example-exitcode/Cargo.lock
+++ b/examples/example-exitcode/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-exitcode/src/main.rs b/examples/example-exitcode/src/main.rs
index 6b22eae..c7f731d 100644
--- a/examples/example-exitcode/src/main.rs
+++ b/examples/example-exitcode/src/main.rs
@@ -31,24 +31,26 @@ fn main() {
program.with_setup(ExitCodeSetup::default());
// --------- IMPORTANT ---------
- program.with_dispatcher(CMDHello);
program.exec_and_exit();
}
-dispatcher!("hello", CMDHello => EntryHello);
+dispatcher!("hello", EntryHello);
-pack!(ErrorNoNameProvided = ());
-pack!(ResultName = String);
+#[derive(Grouped)]
+pub struct ErrorNoNameProvided;
+
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
#[chain]
fn handle_hello(args: EntryHello) -> Next {
- let Some(name) = args.inner.first().cloned() else {
+ let Some(name) = args.0.first().cloned() else {
// If no name is provided, pass ErrorNoNameProvided
- return ErrorNoNameProvided::default().to_render();
+ return ErrorNoNameProvided.to_render();
};
// If the name is valid, pass ResultName
- ResultName::new(name).to_render()
+ ResultName(name).to_render()
}
/// Renders a successful greeting with the given name.
diff --git a/examples/example-help/Cargo.lock b/examples/example-help/Cargo.lock
index 5a482a5..9c39a41 100644
--- a/examples/example-help/Cargo.lock
+++ b/examples/example-help/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-help/src/main.rs b/examples/example-help/src/main.rs
index 3282683..75170c7 100644
--- a/examples/example-help/src/main.rs
+++ b/examples/example-help/src/main.rs
@@ -16,7 +16,7 @@
use mingling::{macros::help, prelude::*, setup::BasicProgramSetup};
use std::io::Write;
-dispatcher!("greet", CMDGreet => EntryGreet);
+dispatcher!("greet", EntryGreet);
// Define help _________ When `program.user_context.help` is `true`
// / the command will not enter `#[chain]` / `#[renderer]`
@@ -36,8 +36,6 @@ fn main() {
program.with_setup(BasicProgramSetup);
// --------- IMPORTANT ---------
- program.with_dispatcher(CMDGreet);
-
program.exec_and_exit();
}
diff --git a/examples/example-hook/Cargo.lock b/examples/example-hook/Cargo.lock
index 588e6ef..e4d68ce 100644
--- a/examples/example-hook/Cargo.lock
+++ b/examples/example-hook/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-hook/src/main.rs b/examples/example-hook/src/main.rs
index da92045..721cea0 100644
--- a/examples/example-hook/src/main.rs
+++ b/examples/example-hook/src/main.rs
@@ -26,7 +26,7 @@ use mingling::{
};
use std::io::Write;
-dispatcher!("greet", CMDGreet => EntryGreet);
+dispatcher!("greet", EntryGreet);
fn main() {
let mut program = ThisProgram::new();
@@ -50,16 +50,16 @@ fn main() {
);
// --------- IMPORTANT ---------
- program.with_dispatcher(CMDGreet);
program.exec_and_exit();
}
-pack!(ResultName = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
let name: ResultName = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
diff --git a/examples/example-implicit-dispatcher/Cargo.lock b/examples/example-implicit-dispatcher/Cargo.lock
index f9f8838..9ca0f10 100644
--- a/examples/example-implicit-dispatcher/Cargo.lock
+++ b/examples/example-implicit-dispatcher/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-implicit-dispatcher/src/main.rs b/examples/example-implicit-dispatcher/src/main.rs
index 340d585..89a5ec3 100644
--- a/examples/example-implicit-dispatcher/src/main.rs
+++ b/examples/example-implicit-dispatcher/src/main.rs
@@ -4,20 +4,13 @@
use mingling::prelude::*;
-// When using implicit syntax, the entry and dispatcher names will be automatically derived
-dispatcher!("remote.add" /*, CMDRemoteAdd => EntryRemoteAdd */);
-dispatcher!("remote.remove", CMDRemoteRemove => EntryRemoteRemove);
+// When using implicit syntax, the entry name will be automatically derived
+// from the command name (the dispatcher struct is generated internally)
+dispatcher!("remote.add" /* => EntryRemoteAdd */);
+dispatcher!("remote.remove", EntryRemoteRemove);
fn main() {
- let mut program = ThisProgram::new();
-
- // --------- IMPORTANT ---------
- program.with_dispatcher(CMDRemoteAdd);
- // ^^^^^^^^^^^^\_ CMDRemoteAdd is implicitly created
- // --------- IMPORTANT ---------
-
- program.with_dispatcher(CMDRemoteRemove);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
gen_program!();
diff --git a/examples/example-lazy-resources/Cargo.lock b/examples/example-lazy-resources/Cargo.lock
index 0786373..21cb251 100644
--- a/examples/example-lazy-resources/Cargo.lock
+++ b/examples/example-lazy-resources/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-lazy-resources/src/main.rs b/examples/example-lazy-resources/src/main.rs
index 7dda658..2243f14 100644
--- a/examples/example-lazy-resources/src/main.rs
+++ b/examples/example-lazy-resources/src/main.rs
@@ -49,10 +49,11 @@ fn init_res_large_data() -> ResLargeData {
ResLargeData { data }
}
-dispatcher!("show", CMDShow => EntryShow);
-dispatcher!("none", CMDNone => EntryNone);
+dispatcher!("show", EntryShow);
+dispatcher!("none", EntryNone);
-pack!(ResultShow = BTreeMap<Key, Value>);
+#[derive(Grouped, Wrap)]
+pub struct ResultShow(BTreeMap<Key, Value>);
fn main() {
let mut program = ThisProgram::new();
@@ -64,7 +65,6 @@ fn main() {
program.with_resource(ResLargeData::lazy_init(init_res_large_data));
// --------- IMPORTANT ---------
- program.with_dispatcher(CMDShow).with_dispatcher(CMDNone);
program.exec_and_exit();
}
diff --git a/examples/example-metadata/Cargo.lock b/examples/example-metadata/Cargo.lock
index 8517b6a..bfa1d01 100644
--- a/examples/example-metadata/Cargo.lock
+++ b/examples/example-metadata/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-metadata/src/main.rs b/examples/example-metadata/src/main.rs
index 855241e..99a8aae 100644
--- a/examples/example-metadata/src/main.rs
+++ b/examples/example-metadata/src/main.rs
@@ -25,20 +25,16 @@ use mingling::{macros::metadata, prelude::*};
use std::io::Write;
// Define the `greet` subcommand
-dispatcher!("greet", CMDGreet => EntryGreet);
+dispatcher!("greet", EntryGreet);
// Define the `desc` subcommand, which queries metadata bound to EntryGreet
-dispatcher!("desc", CMDDescription => EntryDescription);
+dispatcher!("desc", EntryDescription);
// Define the `nodoc` subcommand, which queries metadata for an entry that has none
-dispatcher!("nodoc", CMDNoDescription => EntryNoDescription);
+dispatcher!("nodoc", EntryNoDescription);
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDGreet);
- program.with_dispatcher(CMDDescription);
- program.with_dispatcher(CMDNoDescription);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
/// The metadata type attached to an entry.
@@ -60,14 +56,17 @@ pub fn greet_desc() -> Description {
}
// --------- IMPORTANT ---------
-pack!(ResultName = String);
-pack!(DescResult = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
+
+#[derive(Grouped, Wrap)]
+pub struct DescResult(String);
/// Chain for `greet` — reads the name and produces a `ResultName`.
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
let name: ResultName = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
@@ -85,7 +84,7 @@ fn handle_desc(_args: EntryDescription) -> Next {
None => "EntryGreet has no description".to_string(),
};
// --------- IMPORTANT ---------
- DescResult::new(msg).to_render()
+ DescResult(msg).to_render()
}
/// Chain for `nodoc` — asks for metadata on an entry that has none.
@@ -98,7 +97,7 @@ fn handle_nodoc(_args: EntryNoDescription) -> Next {
None => "EntryDescription has no description".to_string(),
};
// --------- IMPORTANT ---------
- DescResult::new(msg).to_render()
+ DescResult(msg).to_render()
}
/// Renders the greeting message with the provided name.
diff --git a/examples/example-outside-type/Cargo.lock b/examples/example-outside-type/Cargo.lock
index a12fc80..49c8c6f 100644
--- a/examples/example-outside-type/Cargo.lock
+++ b/examples/example-outside-type/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-outside-type/src/main.rs b/examples/example-outside-type/src/main.rs
index 3159d19..8721d9a 100644
--- a/examples/example-outside-type/src/main.rs
+++ b/examples/example-outside-type/src/main.rs
@@ -43,7 +43,8 @@ group!(ErrorIo = std::io::Error);
// you can use this syntax to create an alias simultaneously
// --------- IMPORTANT ---------
-pack!(ParsedNumber = i32);
+#[derive(Grouped, Wrap)]
+pub struct ParsedNumber(i32);
/// Parse the first argument as an `i32`
///
@@ -51,9 +52,9 @@ pack!(ParsedNumber = i32);
/// On failure, routes to `render_parse_error` via the registered outside type.
#[chain]
fn parse_number(args: EntryParse) -> Next {
- let input = args.inner.first().cloned().unwrap_or_default();
+ let input = args.0.first().cloned().unwrap_or_default();
match input.parse::<i32>() {
- Ok(num) => ParsedNumber::new(num).to_chain(),
+ Ok(num) => ParsedNumber(num).to_chain(),
Err(e) => e.to_chain(),
}
}
@@ -90,10 +91,7 @@ fn render_error_io(err: ErrorIo) -> RenderResult {
}
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDParse);
- program.with_dispatcher(CMDError);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
gen_program!();
diff --git a/examples/example-pack-err/Cargo.lock b/examples/example-pack-err/Cargo.lock
deleted file mode 100644
index 1bc9022..0000000
--- a/examples/example-pack-err/Cargo.lock
+++ /dev/null
@@ -1,235 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "equivalent"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
-
-[[package]]
-name = "example-pack-err"
-version = "0.1.0"
-dependencies = [
- "mingling",
- "serde",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
-
-[[package]]
-name = "indexmap"
-version = "2.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
-
-[[package]]
-name = "just_fmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6170dccbc3ea15dfb7f2da964097f814aba1dd8f746d4ffc56f33245c38e6d96"
-
-[[package]]
-name = "memchr"
-version = "2.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
-
-[[package]]
-name = "might_be_async"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eca871cea620b07bd2e6da0c883891a25bead698c43a9ab64b0fd663a7a78d5f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "toml",
-]
-
-[[package]]
-name = "mingling"
-version = "0.4.0"
-dependencies = [
- "mingling_core",
- "mingling_macros",
- "serde",
-]
-
-[[package]]
-name = "mingling_core"
-version = "0.4.0"
-dependencies = [
- "just_fmt",
- "might_be_async",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "mingling_macros"
-version = "0.4.0"
-dependencies = [
- "just_fmt",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
-dependencies = [
- "serde_core",
- "serde_derive",
-]
-
-[[package]]
-name = "serde_core"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.150"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
-dependencies = [
- "itoa",
- "memchr",
- "serde",
- "serde_core",
- "zmij",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.118"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_write",
- "winnow",
-]
-
-[[package]]
-name = "toml_write"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
-
-[[package]]
-name = "winnow"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "zmij"
-version = "1.0.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/examples/example-pack-err/Cargo.toml b/examples/example-pack-err/Cargo.toml
deleted file mode 100644
index ddab6fd..0000000
--- a/examples/example-pack-err/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "example-pack-err"
-version = "0.1.0"
-edition = "2024"
-
-[dependencies]
-serde = { version = "1.0.228", features = ["derive"] }
-
-[dependencies.mingling]
-path = "../../mingling"
-features = [
- "structural_renderer",
- "extras",
-]
-
-[workspace]
diff --git a/examples/example-pack-err/page.toml b/examples/example-pack-err/page.toml
deleted file mode 100644
index 7423087..0000000
--- a/examples/example-pack-err/page.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[example]
-id = "example-pack-err"
-name = "Pack an Error"
-icon = "🛑"
-category = "macros"
-desc = """
-Demonstrates how to use the `pack_err!` macro to define error types with automatic `name` field (snake_case at compile time) and optional `info` field. Also shows `--json` serialization when `structural_renderer` is enabled.
-"""
-tags = ["pack_err!", "extras", "structural_renderer", "--json"]
-files = ["src/main.rs", "Cargo.toml"]
diff --git a/examples/example-pack-err/src/main.rs b/examples/example-pack-err/src/main.rs
deleted file mode 100644
index 5bf5066..0000000
--- a/examples/example-pack-err/src/main.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-//! Example `pack_err!`
-//!
-//! > This example demonstrates how to use the `pack_err!` macro to define error types
-//! > with automatic `name` field (set to snake_case at compile time) and optional `info` field.
-//! > Also demonstrates `--json` serialization when `structural_renderer` is enabled.
-//!
-//! Run:
-//! ```bash
-//! cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find
-//! cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find Cargo.toml
-//! cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find src
-//! cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural --json
-//! cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural Cargo.toml --json
-//! cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural src --json
-//! ```
-//!
-//! Output:
-//! ```plaintext
-//! Search path not provided
-//! Not a directory: Cargo.toml
-//! Found directory: src
-//! {"name":"error_not_found"}
-//! {"name":"error_not_dir","info":"Cargo.toml"}
-//! {"inner":"src"}
-//! {"name":"error_not_found_structural"}
-//! {"name":"error_not_dir_structural","info":"Cargo.toml"}
-//! ```
-
-use mingling::prelude::*;
-use mingling::setup::StructuralRendererSetup;
-use std::io::Write;
-use std::path::PathBuf;
-
-dispatcher!("find", CMDFind => EntryFind);
-dispatcher!("find-structural", CMDFindStructural => EntryFindStructural);
-
-// --------- IMPORTANT ---------
-// `pack_err!` is a convenient macro for defining error types.
-//
-// Simple form: pack_err!(ErrorNotFound);
-// Typed form: pack_err!(ErrorNotDir = PathBuf);
-//
-// The simple form generates a struct with `name: String` and `impl Default`.
-// name = "error_not_found" (automatically snake_cased at compile time)
-//
-// The typed form additionally generates `pub fn new(info)`.
-// name = "error_not_dir"
-//
-// When `structural_renderer` is enabled, the struct also gets
-// `#[derive(serde::Serialize)]` for --json / --yaml output.
-// --------- IMPORTANT ---------
-
-// Simple form — name = "error_not_found"
-pack_err!(ErrorNotFound);
-
-// Typed form — name = "error_not_dir"
-pack_err!(ErrorNotDir = PathBuf);
-
-// Simple form — with StructuralData support for --json / --yaml
-pack_err_structural!(ErrorNotFoundStructural);
-
-// Typed form — with StructuralData support for --json / --yaml
-pack_err_structural!(ErrorNotDirStructural = PathBuf);
-
-// Success type with StructuralData support
-pack_structural!(ResultPath = PathBuf);
-
-#[chain]
-fn handle_find(args: EntryFind) -> Next {
- let Some(path_str) = args.inner.first().cloned() else {
- // No path provided → use the simple error form (Default)
- return ErrorNotFound::default().to_render();
- };
-
- let path = PathBuf::from(&path_str);
- if path.is_dir() {
- // Is a directory → success
- ResultPath::new(path).to_render()
- } else {
- // Not a directory (or doesn't exist) → use the typed error form
- ErrorNotDir::new(path).to_render()
- }
-}
-
-#[chain]
-fn handle_find_structural(args: EntryFindStructural) -> Next {
- let Some(path_str) = args.inner.first().cloned() else {
- // No path provided → use the simple error form (Default)
- return ErrorNotFoundStructural::default().to_render();
- };
-
- let path = PathBuf::from(&path_str);
- if path.is_dir() {
- // Is a directory → success
- ResultPath::new(path).to_render()
- } else {
- // Not a directory (or doesn't exist) → use the typed error form
- ErrorNotDirStructural::new(path).to_render()
- }
-}
-
-/// Renders the successful result with the found directory path.
-#[renderer]
-fn render_result_path(path: ResultPath) -> RenderResult {
- let mut render_result = RenderResult::new();
- writeln!(render_result, "Found directory: {}", path.display()).ok();
- render_result
-}
-
-/// Renders the error when no search path is provided.
-#[renderer]
-fn render_error_not_found(_: ErrorNotFound) -> RenderResult {
- let mut render_result = RenderResult::new();
- writeln!(render_result, "Search path not provided").ok();
- render_result
-}
-
-/// Renders the error when the given path is not a directory.
-#[renderer]
-fn render_error_not_dir(err: ErrorNotDir) -> RenderResult {
- let mut render_result = RenderResult::new();
- writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
- render_result
-}
-
-/// Renders the structural error when no search path is provided.
-#[renderer]
-fn render_error_not_found_structural(_: ErrorNotFoundStructural) -> RenderResult {
- let mut render_result = RenderResult::new();
- writeln!(render_result, "Search path not provided").ok();
- render_result
-}
-
-/// Renders the structural error when the given path is not a directory.
-#[renderer]
-fn render_error_not_dir_structural(err: ErrorNotDirStructural) -> RenderResult {
- let mut render_result = RenderResult::new();
- writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
- render_result
-}
-
-gen_program!();
-
-fn main() {
- let mut program = ThisProgram::new();
- // Add StructuralRendererSetup to support --json / --yaml flags
- program.with_setup(StructuralRendererSetup);
- program.with_dispatcher(CMDFind);
- program.with_dispatcher(CMDFindStructural);
- let _ = program.exec();
-}
diff --git a/examples/example-pack-err/test.toml b/examples/example-pack-err/test.toml
deleted file mode 100644
index c4509cb..0000000
--- a/examples/example-pack-err/test.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-[[runs]]
-input = [ "find" ]
-
-expect.exit-code = 0
-expect.result = "Search path not provided"
-
-[[runs]]
-input = [ "find", "Cargo.toml" ]
-
-expect.exit-code = 0
-expect.result = "Not a directory: Cargo.toml"
-
-[[runs]]
-input = [ "find", "examples" ]
-
-expect.exit-code = 0
-expect.result = "Found directory: examples"
-
-[[runs]]
-input = [ "find-structural", "--json" ]
-
-expect.exit-code = 0
-expect.result = "{\"name\":\"error_not_found_structural\"}"
-
-[[runs]]
-input = [ "find-structural", "Cargo.toml", "--json" ]
-
-expect.exit-code = 0
-expect.result = "{\"name\":\"error_not_dir_structural\",\"info\":\"Cargo.toml\"}"
-
-[[runs]]
-input = [ "find-structural", "examples", "--json" ]
-
-expect.exit-code = 0
-expect.result = "{\"inner\":\"examples\"}"
diff --git a/examples/example-panic-unwind/Cargo.lock b/examples/example-panic-unwind/Cargo.lock
index 6481eb4..20671f5 100644
--- a/examples/example-panic-unwind/Cargo.lock
+++ b/examples/example-panic-unwind/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -57,16 +74,16 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -74,7 +91,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -139,12 +156,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-panic-unwind/Cargo.toml b/examples/example-panic-unwind/Cargo.toml
index 559bdb9..463a288 100644
--- a/examples/example-panic-unwind/Cargo.toml
+++ b/examples/example-panic-unwind/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2024"
[dependencies.mingling]
path = "../../mingling"
-features = ["parser"]
+features = ["picker"]
# Enable panic unwinding in release builds
[profile.release]
diff --git a/examples/example-panic-unwind/src/main.rs b/examples/example-panic-unwind/src/main.rs
index 2c432eb..f91b0f0 100644
--- a/examples/example-panic-unwind/src/main.rs
+++ b/examples/example-panic-unwind/src/main.rs
@@ -19,12 +19,13 @@ use mingling::config::PanicSilence;
use mingling::{hook::ProgramHook, prelude::*};
use std::io::Write;
-dispatcher!("panic", CMDPanic => EntryPanic);
-pack!(NotPanic = ());
+dispatcher!("panic", EntryPanic);
+
+#[derive(Grouped)]
+pub struct NotPanic;
fn main() {
let mut program = ThisProgram::new();
- program.with_dispatcher(CMDPanic);
// --------- IMPORTANT ---------
// Enable silence_panic to suppress automatic Panic output
@@ -42,13 +43,13 @@ fn main() {
#[chain]
fn handle_panic(prev: EntryPanic) -> Next {
- let panic_info = prev.pick::<Option<String>>(()).unpack();
+ let panic_info = prev.pick_or_default(&arg![Option<String>]).unwrap();
match panic_info {
Some(s) => {
// Panic happens here, will be caught
panic!("{}", s)
}
- None => NotPanic::default().into(),
+ None => NotPanic.into(),
}
}
diff --git a/examples/example-pathfinder/Cargo.lock b/examples/example-pathfinder/Cargo.lock
index e00aa91..b93e443 100644
--- a/examples/example-pathfinder/Cargo.lock
+++ b/examples/example-pathfinder/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -84,7 +84,7 @@ dependencies = [
[[package]]
name = "mingling_pathf"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-pathfinder/src/main.rs b/examples/example-pathfinder/src/main.rs
index 0f93a8d..cd7cc7d 100644
--- a/examples/example-pathfinder/src/main.rs
+++ b/examples/example-pathfinder/src/main.rs
@@ -19,12 +19,9 @@
mod sub;
use mingling::macros::gen_program;
-use crate::sub::CMDGreet;
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDGreet);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
gen_program!();
diff --git a/examples/example-pathfinder/src/sub/mod.rs b/examples/example-pathfinder/src/sub/mod.rs
index 8cbc1c5..b90c618 100644
--- a/examples/example-pathfinder/src/sub/mod.rs
+++ b/examples/example-pathfinder/src/sub/mod.rs
@@ -2,13 +2,15 @@ use crate::Next;
use mingling::prelude::*;
use std::io::Write;
-dispatcher!("greet", CMDGreet => EntryGreet);
-pack!(ResultName = String);
+dispatcher!("greet", EntryGreet);
+
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
#[chain]
pub fn handle_greet(args: EntryGreet) -> Next {
let name: ResultName = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
diff --git a/examples/example-repl-basic/Cargo.lock b/examples/example-repl-basic/Cargo.lock
index d4d5bd9..9764a85 100644
--- a/examples/example-repl-basic/Cargo.lock
+++ b/examples/example-repl-basic/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt 0.2.0",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -64,16 +81,16 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt 0.2.0",
"might_be_async",
@@ -81,7 +98,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt 0.2.0",
"proc-macro2",
@@ -146,12 +163,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-repl-basic/Cargo.toml b/examples/example-repl-basic/Cargo.toml
index 3289939..7f2e463 100644
--- a/examples/example-repl-basic/Cargo.toml
+++ b/examples/example-repl-basic/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2024"
[dependencies.mingling]
path = "../../mingling"
-features = ["repl", "parser", "extras"]
+features = ["repl", "picker", "extras"]
[dependencies]
just_fmt = "0.1.2"
diff --git a/examples/example-repl-basic/src/main.rs b/examples/example-repl-basic/src/main.rs
index 361488d..9b81ced 100644
--- a/examples/example-repl-basic/src/main.rs
+++ b/examples/example-repl-basic/src/main.rs
@@ -37,12 +37,6 @@ fn main() {
// Resource
program.with_resource(ResCurrentDir::default());
- // Dispatchers
- program.with_dispatcher(CMDCd);
- program.with_dispatcher(CMDLs);
- program.with_dispatcher(CMDExit);
- program.with_dispatcher(CMDClear);
-
// Setups
// Enable basic std::io::stdin().read_line(&mut input)
program.with_setup(BasicREPLReadlineSetup);
@@ -76,25 +70,28 @@ fn main() {
}
// Create error route
-pack!(ErrorDirectoryNotExist = PathBuf);
+#[derive(Grouped, Wrap)]
+pub struct ErrorDirectoryNotExist(PathBuf);
// Create commands: cd ls exit
-dispatcher!("cd", CMDCd => EntryCd);
-dispatcher!("ls", CMDLs => EntryLs);
-dispatcher!("exit", CMDExit => EntryExit);
-dispatcher!("clear", CMDClear => EntryClear);
+dispatcher!("cd", EntryCd);
+dispatcher!("ls", EntryLs);
+dispatcher!("exit", EntryExit);
+dispatcher!("clear", EntryClear);
// Define data needed for the cd command's execution phase
-pack!(StateChangeDirectory = String);
+#[derive(Grouped, Wrap)]
+pub struct StateChangeDirectory(String);
// Define data needed for the ls command's rendering phase
-pack!(ResultList = Vec<String>);
+#[derive(Grouped, Wrap)]
+pub struct ResultList(Vec<String>);
// Parse cd command arguments
#[chain]
fn parse_cd_args(prev: EntryCd) -> Next {
- let join = prev.pick(()).unpack();
- StateChangeDirectory::new(join).into()
+ let join = prev.pick_or_default(&arg![String]).unwrap();
+ StateChangeDirectory(join).into()
}
// Execute directory change
@@ -102,12 +99,12 @@ fn parse_cd_args(prev: EntryCd) -> Next {
fn handle_cd(prev: StateChangeDirectory, current_dir: &mut ResCurrentDir) -> Next {
use just_fmt::fmt_path::fmt_path;
- let join = prev.inner;
+ let join = prev.0;
let new_dir = fmt_path(current_dir.dir.join(join)).unwrap_or_default();
// If the path is not found, route to error handling
if !new_dir.exists() {
- return ErrorDirectoryNotExist::new(new_dir).to_render();
+ return ErrorDirectoryNotExist(new_dir).to_render();
}
current_dir.dir = new_dir;
@@ -132,14 +129,14 @@ fn handle_ls(_prev: EntryLs, current_dir: &ResCurrentDir) -> Next {
.collect();
// Render ResultList
- ResultList::new(entries).to_render()
+ ResultList(entries).to_render()
}
/// Render ResultList data
#[renderer]
fn render_list(list: ResultList) -> RenderResult {
let mut render_result = RenderResult::new();
- for item in list.inner {
+ for item in list.0 {
writeln!(render_result, "{}", item).ok();
}
render_result
@@ -166,12 +163,7 @@ fn handle_clear(_prev: EntryClear) {
#[renderer]
fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) -> RenderResult {
let mut render_result = RenderResult::new();
- writeln!(
- render_result,
- "Directory not found: {}",
- err.inner.display()
- )
- .ok();
+ writeln!(render_result, "Directory not found: {}", err.0.display()).ok();
render_result
}
diff --git a/examples/example-resources/Cargo.lock b/examples/example-resources/Cargo.lock
index a559bdb..bfc04f0 100644
--- a/examples/example-resources/Cargo.lock
+++ b/examples/example-resources/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -57,16 +74,16 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -74,7 +91,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -139,12 +156,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-resources/Cargo.toml b/examples/example-resources/Cargo.toml
index faf24e4..72a530e 100644
--- a/examples/example-resources/Cargo.toml
+++ b/examples/example-resources/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2024"
[dependencies.mingling]
path = "../../mingling"
-features = ["parser"]
+features = ["picker"]
[workspace]
diff --git a/examples/example-resources/src/main.rs b/examples/example-resources/src/main.rs
index 38e4561..4d792b3 100644
--- a/examples/example-resources/src/main.rs
+++ b/examples/example-resources/src/main.rs
@@ -37,14 +37,11 @@ fn main() {
});
// --------- IMPORTANT ---------
- program
- .with_dispatcher(CMDCurrent)
- .with_dispatcher(CMDModifyCurrent);
program.exec_and_exit();
}
-dispatcher!("current", CMDCurrent => EntryCurrent);
-dispatcher!("modify-current", CMDModifyCurrent => EntryModifyCurrent);
+dispatcher!("current", EntryCurrent);
+dispatcher!("modify-current", EntryModifyCurrent);
// Define chain for modifying current directory _________________ Injected muttable resource
// /
@@ -52,7 +49,7 @@ dispatcher!("modify-current", CMDModifyCurrent => EntryModifyCurrent);
fn render_modify_current(args: EntryModifyCurrent, current_dir: &mut ResCurrentDir) -> Next {
current_dir.current_dir = current_dir
.current_dir
- .join(args.pick::<String>(()).unpack());
+ .join(args.pick_or_default(&arg![String]).unwrap());
EntryCurrent::default().into()
}
diff --git a/examples/example-setup/Cargo.lock b/examples/example-setup/Cargo.lock
index 47d36e5..c8e0e34 100644
--- a/examples/example-setup/Cargo.lock
+++ b/examples/example-setup/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-setup/src/main.rs b/examples/example-setup/src/main.rs
index bf610ca..59c503f 100644
--- a/examples/example-setup/src/main.rs
+++ b/examples/example-setup/src/main.rs
@@ -1,8 +1,28 @@
//! Example Setup
//!
-//! > This example demonstrates how to build a custom Setup for modular management of project components
+//! > This example demonstrates how to build a custom Setup that encapsulates a
+//! > group of related resources and registers them with `with_resource`.
use mingling::{Program, macros::program_setup, prelude::*};
+use std::io::Write;
+
+// A group of related resources — here, the demo app's identity.
+// Resource types are plain structs: any `Default + Clone + Send + Sync` type
+// can be used as a resource, and it is identified by its type.
+#[derive(Default, Clone)]
+struct ResAppName {
+ name: String,
+}
+
+#[derive(Default, Clone)]
+struct ResAppVersion {
+ version: String,
+}
+
+#[derive(Default, Clone)]
+struct ResGreetingPrefix {
+ prefix: String,
+}
fn main() {
let mut program = ThisProgram::new();
@@ -17,21 +37,45 @@ fn main() {
// --------- IMPORTANT ---------
// Define `CustomSetup` (inferred from `custom_setup`)
-// Package part of the program construction logic into this type for modular management
+// Package part of the program construction logic into this type for modular
+// management — e.g. register a group of related resources here.
#[program_setup]
fn custom_setup(program: &mut Program<ThisProgram>) {
- program.with_dispatcher(CMD1);
- program.with_dispatcher(CMD2);
- program.with_dispatcher(CMD3);
- program.with_dispatcher(CMD4);
- program.with_dispatcher(CMD5);
+ program.with_resource(ResAppName {
+ name: "mingling".to_string(),
+ });
+ program.with_resource(ResAppVersion {
+ version: "0.5.0".to_string(),
+ });
+ program.with_resource(ResGreetingPrefix {
+ prefix: "Hello".to_string(),
+ });
}
// --------- IMPORTANT ---------
-dispatcher!("1", CMD1 => Entry1);
-dispatcher!("2", CMD2 => Entry2);
-dispatcher!("3", CMD3 => Entry3);
-dispatcher!("4", CMD4 => Entry4);
-dispatcher!("5", CMD5 => Entry5);
+dispatcher!("greet", EntryGreet);
+
+#[derive(Grouped, Wrap)]
+pub struct ResultGreeting(String);
+
+/// Chain: reads the `ResAppName` and `ResAppVersion` resources.
+#[chain]
+fn handle_greet(args: EntryGreet, app: &ResAppName, version: &ResAppVersion) -> Next {
+ let who = args
+ .0
+ .first()
+ .cloned()
+ .unwrap_or_else(|| "World".to_string());
+ let greeting: ResultGreeting = format!("{} from {} v{}", who, app.name, version.version).into();
+ greeting.into()
+}
+
+/// Renderer: injects the `ResGreetingPrefix` resource to decorate the output.
+#[renderer]
+fn render_greet(greeting: ResultGreeting, prefix: &ResGreetingPrefix) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "{}, {}!", prefix.prefix, *greeting).ok();
+ render_result
+}
gen_program!();
diff --git a/examples/example-setup/test.toml b/examples/example-setup/test.toml
index 811a108..c9b7ed8 100644
--- a/examples/example-setup/test.toml
+++ b/examples/example-setup/test.toml
@@ -1,29 +1,11 @@
[[runs]]
-input = [ "1" ]
+input = [ "greet" ]
expect.exit-code = 0
-expect.result = ""
+expect.result = "Hello, World from mingling v0.5.0!"
[[runs]]
-input = [ "2" ]
+input = [ "greet", "Alice" ]
expect.exit-code = 0
-expect.result = ""
-
-[[runs]]
-input = [ "3" ]
-
-expect.exit-code = 0
-expect.result = ""
-
-[[runs]]
-input = [ "4" ]
-
-expect.exit-code = 0
-expect.result = ""
-
-[[runs]]
-input = [ "5" ]
-
-expect.exit-code = 0
-expect.result = ""
+expect.result = "Hello, Alice from mingling v0.5.0!"
diff --git a/examples/example-structural-renderer/Cargo.lock b/examples/example-structural-renderer/Cargo.lock
index c3f24c7..cf2cfe3 100644
--- a/examples/example-structural-renderer/Cargo.lock
+++ b/examples/example-structural-renderer/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -64,17 +81,17 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
"serde",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -85,7 +102,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -183,12 +200,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/example-structural-renderer/Cargo.toml b/examples/example-structural-renderer/Cargo.toml
index e29e9c3..2851303 100644
--- a/examples/example-structural-renderer/Cargo.toml
+++ b/examples/example-structural-renderer/Cargo.toml
@@ -11,7 +11,7 @@ path = "../../mingling"
features = [
"structural_renderer",
"yaml_serde_fmt",
- "parser",
+ "picker",
]
[workspace]
diff --git a/examples/example-structural-renderer/src/main.rs b/examples/example-structural-renderer/src/main.rs
index 070e75d..c1cfd69 100644
--- a/examples/example-structural-renderer/src/main.rs
+++ b/examples/example-structural-renderer/src/main.rs
@@ -17,23 +17,23 @@
//! member_age: 22
//! ```
-use mingling::prelude::*;
-use mingling::{parser::Picker, setup::StructuralRendererSetup, Grouped, StructuralData};
+use mingling::setup::picker::StructuralRendererSetup;
+use mingling::{Grouped, StructuralData, prelude::*};
use serde::Serialize;
use std::io::Write;
-dispatcher!("render", CMDRender => EntryRender);
+dispatcher!("render", EntryRender);
fn main() {
let mut program = ThisProgram::new();
// Add `StructuralRendererSetup` to receive user input `--json` `--yaml` parameters
program.with_setup(StructuralRendererSetup);
- program.with_dispatcher(CMDRender);
let _ = program.exec();
}
// --------- IMPORTANT ---------
-// For beautiful output structure, do not use `pack!` to wrap the types that need to be output.
+// For beautiful output structure, do not wrap the types that need to be output
+// in a newtype; instead, use a named struct.
// Instead, manually implement
// ____________________________________ Mark as structured data so it can be rendered
// / ____________________ Implement serde::Serialize
@@ -49,17 +49,17 @@ struct Info {
}
// This will output: {"member_name":"name","member_age":32} structure
-// If using pack!(Info = (String, i32));
+// If wrapping with a tuple newtype (e.g. `#[derive(Grouped, Wrap)] pub struct Info((String, i32));`)
// Output: {"inner":["name", 32]}
// --------- IMPORTANT ---------
#[chain]
fn parse_render(prev: EntryRender) -> Next {
- let (name, age) = Picker::new(prev.inner)
- .pick::<String>(())
- .pick::<i32>(())
- .unpack();
+ let (name, age) = prev
+ .pick_or_default(&arg![String])
+ .pick_or_default(&arg![i32])
+ .unwrap();
Info { name, age }.to_render()
}
diff --git a/examples/example-unit-test/Cargo.lock b/examples/example-unit-test/Cargo.lock
index a1b4e59..455fa9d 100644
--- a/examples/example-unit-test/Cargo.lock
+++ b/examples/example-unit-test/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"mingling_core",
"mingling_macros",
@@ -65,7 +65,7 @@ dependencies = [
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -73,7 +73,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
diff --git a/examples/example-unit-test/src/main.rs b/examples/example-unit-test/src/main.rs
index 33ddde0..e4c6504 100644
--- a/examples/example-unit-test/src/main.rs
+++ b/examples/example-unit-test/src/main.rs
@@ -36,60 +36,66 @@ mod tests {
let hello_with_valid_name = handle_hello(entry!("Peter")).into();
assert_render_result!(hello_with_valid_name);
let result_name = unpack_chain_process!(hello_with_valid_name, ResultName);
- assert_eq!(result_name.inner, "Peter");
+ assert_eq!(result_name.0, "Peter");
}
#[test]
fn test_render_result_name() {
- let r = render_result_name(ResultName::new("Peter".into()));
+ let r = render_result_name(ResultName("Peter".into()));
assert_eq!(r.to_string().as_str(), "Hello, Peter!")
}
#[test]
fn test_render_error_no_name_provided() {
- let r = render_error_no_name_provided(ErrorNoNameProvided::default());
+ let r = render_error_no_name_provided(ErrorNoNameProvided);
assert_eq!(r.to_string().as_str(), "No name provided")
}
#[test]
fn test_render_error_name_not_available() {
- let r = render_error_name_not_available(ErrorNameNotAvailable::default());
+ let r = render_error_name_not_available(ErrorNameNotAvailable);
assert_eq!(r.to_string().as_str(), "Name not available")
}
#[test]
fn test_render_error_name_too_long() {
- let r = render_error_name_too_long(ErrorNameTooLong::new(17));
+ let r = render_error_name_too_long(ErrorNameTooLong(17));
assert_eq!(r.to_string().as_str(), "Name too long: 17 > 10")
}
// --------- IMPORTANT ---------
}
-dispatcher!("hello", CMDHello => EntryHello);
+dispatcher!("hello", EntryHello);
-pack!(ErrorNoNameProvided = ());
-pack!(ErrorNameTooLong = u16);
-pack!(ErrorNameNotAvailable = ());
+#[derive(Grouped)]
+pub struct ErrorNoNameProvided;
-pack!(ResultName = String);
+#[derive(Grouped, Wrap)]
+pub struct ErrorNameTooLong(u16);
+
+#[derive(Grouped)]
+pub struct ErrorNameNotAvailable;
+
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
static VEC_REGISTERED_NAMES: &[&str] = &["Alice", "Bob", "Charlie", "David", "Eve"];
#[chain]
fn handle_hello(args: EntryHello) -> Next {
- let Some(name) = args.inner.first().cloned() else {
- return ErrorNoNameProvided::default().to_render();
+ let Some(name) = args.0.first().cloned() else {
+ return ErrorNoNameProvided.to_render();
};
if name.len() > 10 {
- return ErrorNameTooLong::new(name.len() as u16).to_render();
+ return ErrorNameTooLong(name.len() as u16).to_render();
}
if VEC_REGISTERED_NAMES.contains(&name.as_str()) {
- return ErrorNameNotAvailable::default().to_render();
+ return ErrorNameNotAvailable.to_render();
}
- ResultName::new(name).to_render()
+ ResultName(name).to_render()
}
/// Renders a successful greeting with the given name.
@@ -128,19 +134,12 @@ fn render_error_name_too_long(len: ErrorNameTooLong) -> RenderResult {
#[renderer]
fn render_entry_fallback(err: EntryFallback) -> RenderResult {
let mut render_result = RenderResult::new();
- writeln!(
- render_result,
- "Command not found: \"{}\"",
- err.inner.join(" ")
- )
- .ok();
+ writeln!(render_result, "Command not found: \"{}\"", err.0.join(" ")).ok();
render_result
}
gen_program!();
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDHello);
- program.exec_and_exit();
+ ThisProgram::new().exec_and_exit();
}
diff --git a/examples/full-todolist/Cargo.lock b/examples/full-todolist/Cargo.lock
index 28d551b..ad9f475 100644
--- a/examples/full-todolist/Cargo.lock
+++ b/examples/full-todolist/Cargo.lock
@@ -3,6 +3,23 @@
version = 4
[[package]]
+name = "arg-picker"
+version = "0.2.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.2.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -65,17 +82,17 @@ dependencies = [
[[package]]
name = "mingling"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
+ "arg-picker",
"mingling_core",
"mingling_macros",
"serde",
- "size",
]
[[package]]
name = "mingling_core"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"might_be_async",
@@ -85,7 +102,7 @@ dependencies = [
[[package]]
name = "mingling_macros"
-version = "0.4.0"
+version = "0.5.0"
dependencies = [
"just_fmt",
"proc-macro2",
@@ -164,12 +181,6 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
-
-[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/examples/full-todolist/Cargo.toml b/examples/full-todolist/Cargo.toml
index 9d6f1a7..fb3d3be 100644
--- a/examples/full-todolist/Cargo.toml
+++ b/examples/full-todolist/Cargo.toml
@@ -10,7 +10,7 @@ serde_json = "1.0.150"
[dependencies.mingling]
path = "../../mingling"
features = [
- "parser",
+ "picker",
"extras",
"structural_renderer",
]
diff --git a/examples/full-todolist/src/main.rs b/examples/full-todolist/src/main.rs
index 0748832..9c7bfe8 100644
--- a/examples/full-todolist/src/main.rs
+++ b/examples/full-todolist/src/main.rs
@@ -9,9 +9,10 @@
use mingling::{
LazyInit, LazyRes,
macros::route,
+ picker::value::Flag,
prelude::*,
res::ResExitCode,
- setup::{ExitCodeSetup, HelpFlagSetup, StructuralRendererSetup},
+ setup::{ExitCodeSetup, picker::HelpFlagSetup, picker::StructuralRendererSetup},
};
use std::io::Write;
@@ -35,15 +36,25 @@ dispatcher!("clean");
// Define states
-pack!(StateAddTodo = String);
-pack!(StateCompleteTodo = i32);
-pack!(StateListTodo = bool);
+#[derive(Grouped, Wrap)]
+pub struct StateAddTodo(String);
+
+#[derive(Grouped, Wrap)]
+pub struct StateCompleteTodo(i32);
+
+#[derive(Grouped, Wrap)]
+pub struct StateListTodo(bool);
// Define errors
-pack!(ErrorNoTaskDescriptionProvided = ());
-pack!(ErrorNoIndexProvided = ());
-pack!(ErrorIndexOutOfBounds = ());
+#[derive(Grouped)]
+pub struct ErrorNoTaskDescriptionProvided;
+
+#[derive(Grouped)]
+pub struct ErrorNoIndexProvided;
+
+#[derive(Grouped)]
+pub struct ErrorIndexOutOfBounds;
fn main() {
let mut program = ThisProgram::new();
@@ -51,7 +62,7 @@ fn main() {
// Setups
program.with_setup(ExitCodeSetup::default());
program.with_setup(StructuralRendererSetup);
- program.with_setup(HelpFlagSetup::new(["--help", "-h"]));
+ program.with_setup(HelpFlagSetup::new(&arg![help: Flag, 'h']));
// Flags
let all = program.pick_global_flag(["-A", "--all"]);
@@ -65,12 +76,7 @@ fn main() {
);
program.with_resource(ResProgramFlags { all });
- // Dispatchers
- program.with_dispatcher(CMDAdd);
- program.with_dispatcher(CMDComplete);
- program.with_dispatcher(CMDList);
- program.with_dispatcher(CMDClean);
-
+ // Execute
program.exec_and_exit();
}
@@ -79,11 +85,12 @@ fn main() {
#[chain]
fn handle_add(args: EntryAdd) -> Next {
let task: String = route! {
- args
- .pick_or_route((), ErrorNoTaskDescriptionProvided::new(()))
- .unpack()
+ args.pick_or_route(&arg![String], || {
+ ErrorNoTaskDescriptionProvided.to_chain()
+ })
+ .to_result()
};
- StateAddTodo::new(task).to_chain()
+ StateAddTodo(task).to_chain()
}
#[chain]
@@ -95,7 +102,7 @@ fn handle_state_add_todo(
let todolist = todolist.get_mut();
// Unpack state and read description
- let description = state.inner;
+ let description = state.0;
todolist.items.push(Todo {
item: description,
@@ -120,9 +127,10 @@ fn handle_list(_args: EntryList, todolist: &mut LazyRes<ResTodoList>) -> Next {
#[chain]
fn handle_complete(args: EntryComplete) -> Next {
let index: i32 = route! {
- args.pick_or_route((), ErrorNoIndexProvided::new(())).unpack()
+ args.pick_or_route(&arg![i32], || ErrorNoIndexProvided.to_chain())
+ .to_result()
};
- StateCompleteTodo::new(index).to_chain()
+ StateCompleteTodo(index).to_chain()
}
#[chain]
@@ -131,12 +139,12 @@ fn handle_state_complete_todo(
todolist: &mut LazyRes<ResTodoList>,
) -> Next {
let todolist = todolist.get_mut();
- let index = state.inner as usize;
+ let index = state.0 as usize;
if index < todolist.items.len() {
todolist.items[index].completed = true;
todolist.clone().to_render()
} else {
- ErrorIndexOutOfBounds::new(()).to_render()
+ ErrorIndexOutOfBounds.to_render()
}
}