aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/example-argument-picker/Cargo.lock94
-rw-r--r--examples/example-argument-picker/Cargo.toml12
-rw-r--r--examples/example-argument-picker/page.toml10
-rw-r--r--examples/example-argument-picker/src/main.rs225
-rw-r--r--examples/example-clap-binding/src/main.rs8
-rw-r--r--examples/example-custom-pickable/src/main.rs8
-rw-r--r--examples/example-enum-tag/src/main.rs4
-rw-r--r--examples/example-outside-type/src/main.rs2
-rw-r--r--examples/example-structural-renderer/src/main.rs14
-rw-r--r--examples/full-todolist/src/todolist.rs4
-rw-r--r--examples/test-examples.toml35
11 files changed, 396 insertions, 20 deletions
diff --git a/examples/example-argument-picker/Cargo.lock b/examples/example-argument-picker/Cargo.lock
new file mode 100644
index 0000000..9a9baa4
--- /dev/null
+++ b/examples/example-argument-picker/Cargo.lock
@@ -0,0 +1,94 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "arg-picker"
+version = "0.1.0"
+dependencies = [
+ "arg-picker-macros",
+ "just_fmt",
+]
+
+[[package]]
+name = "arg-picker-macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "example-argument-picker"
+version = "0.1.0"
+dependencies = [
+ "mingling",
+]
+
+[[package]]
+name = "just_fmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6170dccbc3ea15dfb7f2da964097f814aba1dd8f746d4ffc56f33245c38e6d96"
+
+[[package]]
+name = "mingling"
+version = "0.3.0"
+dependencies = [
+ "arg-picker",
+ "mingling_core",
+ "mingling_macros",
+]
+
+[[package]]
+name = "mingling_core"
+version = "0.3.0"
+dependencies = [
+ "just_fmt",
+]
+
+[[package]]
+name = "mingling_macros"
+version = "0.3.0"
+dependencies = [
+ "just_fmt",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.119"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
diff --git a/examples/example-argument-picker/Cargo.toml b/examples/example-argument-picker/Cargo.toml
new file mode 100644
index 0000000..686b95b
--- /dev/null
+++ b/examples/example-argument-picker/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "example-argument-picker"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies.mingling]
+path = "../../mingling"
+
+# Enable `picker` features
+features = ["picker", "extra_macros"]
+
+[workspace]
diff --git a/examples/example-argument-picker/page.toml b/examples/example-argument-picker/page.toml
new file mode 100644
index 0000000..563bccc
--- /dev/null
+++ b/examples/example-argument-picker/page.toml
@@ -0,0 +1,10 @@
+[example]
+id = "example-argument-picker"
+name = "Argument Picker"
+icon = "📋"
+category = "parsing"
+desc = """
+Demonstrates how to use Mingling's `picker` feature and `Picker` to extract typed arguments from the command line.
+"""
+tags = ["arg-picker", "SinglePickable"]
+files = ["src/main.rs", "Cargo.toml"]
diff --git a/examples/example-argument-picker/src/main.rs b/examples/example-argument-picker/src/main.rs
new file mode 100644
index 0000000..7fcc5db
--- /dev/null
+++ b/examples/example-argument-picker/src/main.rs
@@ -0,0 +1,225 @@
+//! Example Argument Picker
+//!
+//! > Demonstrates how to use Mingling's `picker` feature and `Picker` to extract typed arguments from the command line.
+//!
+//! Run:
+//! ```bash
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc 1 + 1
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc 7 * 7
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc 1
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc 1 +
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc 4 / 3
+//! cargo run --manifest-path examples/example-argument-picker/Cargo.toml --quiet -- calc 4 / 3 --round
+//! ```
+//!
+//! Output:
+//! ```plaintext
+//! Result: 2
+//! Result: 49
+//! Error: First number (number_a) was not provided.
+//! Error: Operator was not provided.
+//! Error: Second number (number_b) was not provided.
+//! Result: 1.3333334
+//! Result: 1
+//! ```
+
+use mingling::{
+ consts::REMAINS,
+ macros::route,
+ picker::{
+ IntoPicker, PickerArgResult, SinglePickable,
+ parselib::{ParserStyle, UNIX_STYLE},
+ value::Flag,
+ },
+ prelude::*,
+};
+
+// --------- IMPORTANT ---------
+// Use picker::BasicProgramSetup instead of the original BasicProgramSetup
+// It uses arg-picker to rewrite the logic of the original BasicProgramSetup
+use mingling::setup::picker::BasicProgramSetup;
+
+// --------- IMPORTANT ---------
+
+dispatcher!("calc", CMDCalculate => EntryCalculate);
+
+pack_err!(ErrorNumberANotProvided);
+pack_err!(ErrorNumberBNotProvided);
+pack_err!(ErrorNumberOperatorNotProvided);
+pack_err!(ErrorDivisionByZero);
+
+pack!(StateAdd = (f32, f32));
+pack!(StateSubtract = (f32, f32));
+pack!(StateMultiply = (f32, f32));
+pack!(StateDivide = (f32, f32));
+
+pack!(ResultNumber = f32);
+
+#[derive(Grouped)]
+struct StateCalculate {
+ number_a: f32,
+ operator: Operator,
+ number_b: f32,
+}
+
+#[derive(Debug, PartialEq, Eq)]
+enum Operator {
+ Plus,
+ Dash,
+ Slash,
+ Star,
+}
+
+// --------- IMPORTANT ---------
+// Define SinglePickable for type Operator
+// This allows the type to be picked as an argument
+impl SinglePickable for Operator {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ let Some(str) = str else {
+ return PickerArgResult::NotFound;
+ };
+ let op = match str.chars().next() {
+ Some('+') => Operator::Plus,
+ Some('-') => Operator::Dash,
+ Some('*') => Operator::Star,
+ Some('/') => Operator::Slash,
+ _ => return PickerArgResult::NotFound,
+ };
+ PickerArgResult::Parsed(op)
+ }
+}
+// --------- IMPORTANT ---------
+
+#[derive(Default, Clone)]
+struct ResNumberDisplaySetting {
+ round: bool,
+}
+
+fn main() {
+ let mut program = ThisProgram::new();
+
+ // Use ParserStyle to manage the arg-picker theme
+ ParserStyle::set_global_style(&UNIX_STYLE);
+
+ // Enable picker::BasicProgramSetup
+ program.with_setup(BasicProgramSetup);
+
+ // --------- IMPORTANT ---------
+ // Pre-process global arguments before executing commands
+ let (round, args) = program
+ .take_args()
+ // Use arg![round: Flag] to indicate the `--round` | `-R` flag
+ // |
+ // vvvvvvvvvvvvvvvv
+ .pick(&arg![round: Flag, 'R'])
+ // Use REMAINS to extract remaining arguments
+ // |
+ // vvvvvvvv
+ .pick(&REMAINS)
+ // Since Flag and REMAINS will not fail to parse,
+ // we can safely unwrap here
+ .unwrap();
+ program.replace_args(args.into());
+
+ program.with_resource(ResNumberDisplaySetting { round: *round });
+ // --------- IMPORTANT ---------
+
+ program.with_dispatcher(CMDCalculate);
+ program.exec_and_exit();
+}
+
+#[chain]
+fn handle_calc(args: EntryCalculate) -> Next {
+ // --------- IMPORTANT ---------
+ let (number_a, operator, number_b) = route!(
+ // Use the arg! macro to define a positional argument of type f32
+ // |
+ // vvvvvvvvvv
+ args.pick_or_route(&arg![f32], || ErrorNumberANotProvided::default().to_chain())
+ .pick_or_route(&arg![Operator], || {
+ ErrorNumberOperatorNotProvided::default().to_chain()
+ }) // Returns a routable type when not found or fails to parse
+ // |
+ // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ .pick_or_route(&arg![f32], || ErrorNumberBNotProvided::default().to_chain())
+ // Use `to_result` to parse arguments
+ // and convert to Result<(Tuple, ...), Route> type
+ .to_result()
+ );
+ // --------- IMPORTANT ---------
+
+ if operator == Operator::Slash && number_b == 0. {
+ return ErrorDivisionByZero::default().to_chain();
+ }
+
+ StateCalculate {
+ number_a,
+ operator,
+ number_b,
+ }
+ .to_chain()
+}
+
+#[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(),
+ }
+}
+
+#[chain]
+fn handle_state_add(state_add: StateAdd) -> ResultNumber {
+ let (a, b) = state_add.inner;
+ ResultNumber::new(a + b)
+}
+
+#[chain]
+fn handle_state_subtract(state_subtract: StateSubtract) -> ResultNumber {
+ let (a, b) = state_subtract.inner;
+ ResultNumber::new(a - b)
+}
+
+#[chain]
+fn handle_state_multiply(state_multiply: StateMultiply) -> ResultNumber {
+ let (a, b) = state_multiply.inner;
+ ResultNumber::new(a * b)
+}
+
+#[chain]
+fn handle_state_divide(state_divide: StateDivide) -> ResultNumber {
+ let (a, b) = state_divide.inner;
+ ResultNumber::new(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 };
+ format!("Result: {}", result)
+}
+
+#[renderer]
+fn render_error_division_by_zero(_: ErrorDivisionByZero) -> String {
+ "Error: Division by zero is not allowed!".to_string()
+}
+
+#[renderer]
+fn render_error_number_a_not_provided(_: ErrorNumberANotProvided) -> String {
+ "Error: First number (number_a) was not provided.".to_string()
+}
+
+#[renderer]
+fn render_error_number_b_not_provided(_: ErrorNumberBNotProvided) -> String {
+ "Error: Second number (number_b) was not provided.".to_string()
+}
+
+#[renderer]
+fn render_error_number_operator_not_provided(_: ErrorNumberOperatorNotProvided) -> String {
+ "Error: Operator was not provided.".to_string()
+}
+
+gen_program!();
diff --git a/examples/example-clap-binding/src/main.rs b/examples/example-clap-binding/src/main.rs
index d99f8d1..0f839c8 100644
--- a/examples/example-clap-binding/src/main.rs
+++ b/examples/example-clap-binding/src/main.rs
@@ -38,7 +38,7 @@
//! For more information, try '--help'.
//! ```
-use mingling::{Groupped, macros::dispatcher_clap, prelude::*, setup::BasicProgramSetup};
+use mingling::{Grouped, macros::dispatcher_clap, prelude::*, setup::BasicProgramSetup};
use std::io::Write;
fn main() {
@@ -67,10 +67,10 @@ fn main() {
// Implement Clap Parser, and bind to Dispatcher
// _______________________________ Default trait, provides fallback on parse failure
// / ______________________ clap::Parser, parsing logic implemented by Clap
-// | / ________ Implement mingling::Groupped
+// | / ________ Implement mingling::Grouped
// | | / to ensure Mingling can recognize the type
-// vvvvvvv vvvvvvvvvvvv vvvvvvvv
-#[derive(Default, clap::Parser, Groupped)]
+// vvvvvvv vvvvvvvvvvvv vvvvvvv
+#[derive(Default, clap::Parser, Grouped)]
#[dispatcher_clap(
"greet", CMDGreet, // Bind EntryGreet to "greet" command
help = true, // Generate clap help for EntryGreet
diff --git a/examples/example-custom-pickable/src/main.rs b/examples/example-custom-pickable/src/main.rs
index d203815..b163278 100644
--- a/examples/example-custom-pickable/src/main.rs
+++ b/examples/example-custom-pickable/src/main.rs
@@ -14,15 +14,15 @@
//! Failed to parse address
//! ```
-use mingling::{macros::route, parser::Pickable, prelude::*, Groupped};
+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 Groupped derive macro registers an ID for this type
+// / ________ The Grouped derive macro registers an ID for this type
// | / Mingling uses this ID to identify the type
-// vvvvvvv vvvvvvvv
-#[derive(Debug, Default, Clone, Groupped)]
+// vvvvvvv vvvvvvv
+#[derive(Debug, Default, Clone, Grouped)]
pub struct Address {
pub ip: [u8; 4],
pub port: u16,
diff --git a/examples/example-enum-tag/src/main.rs b/examples/example-enum-tag/src/main.rs
index 91c5358..b57511d 100644
--- a/examples/example-enum-tag/src/main.rs
+++ b/examples/example-enum-tag/src/main.rs
@@ -16,7 +16,7 @@
//! ```
use mingling::{
- macros::suggest_enum, parser::PickableEnum, prelude::*, EnumTag, Groupped, ShellContext,
+ macros::suggest_enum, parser::PickableEnum, prelude::*, EnumTag, Grouped, ShellContext,
Suggest,
};
use std::io::Write;
@@ -25,7 +25,7 @@ use std::io::Write;
// ________ adds metadata to the enum, enabling it to:
// / 1. Be used by the `suggest_enum!(Enum)` macro under the `comp` feature for autocompletion
// vvvvvvv 2. Implement the `PickableEnum` trait
-#[derive(Debug, Default, EnumTag, Groupped)]
+#[derive(Debug, Default, EnumTag, Grouped)]
pub enum ProgrammingLanguages {
#[enum_desc("An efficient and flexible compiled language widely used for system programming")]
C,
diff --git a/examples/example-outside-type/src/main.rs b/examples/example-outside-type/src/main.rs
index 925878a..3159d19 100644
--- a/examples/example-outside-type/src/main.rs
+++ b/examples/example-outside-type/src/main.rs
@@ -71,7 +71,7 @@ fn render_number(num: ParsedNumber) -> RenderResult {
/// Renderer for parse errors — using the outside `ParseIntError` type.
///
/// The `ParseIntError` type is registered via `group!` above, so it implements
-/// `Groupped<ThisProgram>` and can be used directly in a `#[renderer]` function.
+/// `Grouped<ThisProgram>` and can be used directly in a `#[renderer]` function.
#[renderer]
fn render_parse_error(err: ParseIntError) -> RenderResult {
let mut render_result = RenderResult::new();
diff --git a/examples/example-structural-renderer/src/main.rs b/examples/example-structural-renderer/src/main.rs
index 13c4c84..070e75d 100644
--- a/examples/example-structural-renderer/src/main.rs
+++ b/examples/example-structural-renderer/src/main.rs
@@ -18,7 +18,7 @@
//! ```
use mingling::prelude::*;
-use mingling::{Groupped, StructuralData, parser::Picker, setup::StructuralRendererSetup};
+use mingling::{parser::Picker, setup::StructuralRendererSetup, Grouped, StructuralData};
use serde::Serialize;
use std::io::Write;
@@ -35,12 +35,12 @@ fn main() {
// --------- IMPORTANT ---------
// For beautiful output structure, do not use `pack!` to wrap the types that need to be output.
// Instead, manually implement
-// __________________________________ Mark as structured data so it can be rendered
-// / ____________________ Implement serde::Serialize
-// | / _________ Implement mingling::Groupped
-// | | / to ensure Mingling can recognize the type
-// vvvvvvvvvvvv vvvvvvvvv vvvvvvvv
-#[derive(StructuralData, Serialize, Groupped)]
+// ____________________________________ Mark as structured data so it can be rendered
+// / ____________________ Implement serde::Serialize
+// | / _________ Implement mingling::Grouped
+// | | / to ensure Mingling can recognize the type
+// vvvvvvvvvvvv vvvvvvvvv vvvvvvv
+#[derive(StructuralData, Serialize, Grouped)]
struct Info {
#[serde(rename = "member_name")]
name: String,
diff --git a/examples/full-todolist/src/todolist.rs b/examples/full-todolist/src/todolist.rs
index 71338c3..d3582e3 100644
--- a/examples/full-todolist/src/todolist.rs
+++ b/examples/full-todolist/src/todolist.rs
@@ -1,13 +1,13 @@
//! Data structures, read and write logic for the todo list
-use mingling::{Groupped, RenderResult, macros::renderer};
+use mingling::{Grouped, RenderResult, macros::renderer};
use serde::{Deserialize, Serialize};
use std::io::Write;
use std::{env::current_dir, path::PathBuf};
use crate::ResProgramFlags;
-#[derive(Debug, Serialize, Deserialize, Clone, Default, Groupped)]
+#[derive(Debug, Serialize, Deserialize, Clone, Default, Grouped)]
pub struct ResTodoList {
pub items: Vec<Todo>,
}
diff --git a/examples/test-examples.toml b/examples/test-examples.toml
index d2fe602..e450919 100644
--- a/examples/test-examples.toml
+++ b/examples/test-examples.toml
@@ -277,3 +277,38 @@ expect.result = "Hello, Alice!"
command = "hello"
expect.exit-code = 0
expect.result = "Hello, World!"
+
+[[test.example-argument-picker]]
+command = "calc 1 + 1"
+expect.exit-code = 0
+expect.result = "Result: 2"
+
+[[test.example-argument-picker]]
+command = "calc 7 * 7"
+expect.exit-code = 0
+expect.result = "Result: 49"
+
+[[test.example-argument-picker]]
+command = "calc"
+expect.exit-code = 0
+expect.result = "Error: First number (number_a) was not provided."
+
+[[test.example-argument-picker]]
+command = "calc 1"
+expect.exit-code = 0
+expect.result = "Error: Operator was not provided."
+
+[[test.example-argument-picker]]
+command = "calc 1 +"
+expect.exit-code = 0
+expect.result = "Error: Second number (number_b) was not provided."
+
+[[test.example-argument-picker]]
+command = "calc 4 / 3"
+expect.exit-code = 0
+expect.result = "Result: 1.3333334"
+
+[[test.example-argument-picker]]
+command = "calc 4 / 3 --round"
+expect.exit-code = 0
+expect.result = "Result: 1"