aboutsummaryrefslogtreecommitdiff
path: root/mingling/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling/src')
-rw-r--r--mingling/src/constants.rs3
-rw-r--r--mingling/src/constants/picker.rs16
-rw-r--r--mingling/src/example_docs.rs245
-rw-r--r--mingling/src/features.rs11
-rw-r--r--mingling/src/lib.md2
-rw-r--r--mingling/src/lib.rs37
-rw-r--r--mingling/src/picker/entry_picker.rs6
-rw-r--r--mingling/src/setups/repl_basic.rs2
8 files changed, 296 insertions, 26 deletions
diff --git a/mingling/src/constants.rs b/mingling/src/constants.rs
index 65d02e8..75f1c73 100644
--- a/mingling/src/constants.rs
+++ b/mingling/src/constants.rs
@@ -4,5 +4,8 @@ mod picker;
#[cfg(feature = "picker")]
pub use picker::*;
+#[cfg(feature = "picker")]
+pub use arg_picker::consts::*;
+
mod exit_codes;
pub use exit_codes::*;
diff --git a/mingling/src/constants/picker.rs b/mingling/src/constants/picker.rs
index f2a448b..d98dcab 100644
--- a/mingling/src/constants/picker.rs
+++ b/mingling/src/constants/picker.rs
@@ -1,20 +1,6 @@
+use arg_picker::{PickerArg, value::Flag};
use std::marker::PhantomData;
-use arg_picker::{PickerArg, PickerArgs, value::Flag};
-
-/// Remaining positional arguments (anything not consumed as an option).
-/// - `full`: `[]` (empty — not triggered by any `--` prefix).
-/// - `short`: (none)
-/// - `positional`: `false` (this is a meta‑argument that collects everything left).
-/// This constant is used internally to access any leftover arguments after
-/// all defined flags/options have been processed.
-pub const REMAINS: PickerArg<PickerArgs> = PickerArg::<PickerArgs> {
- full: &[],
- short: None,
- positional: false,
- internal_type: PhantomData,
-};
-
/// Help flag: display usage information.
/// - `full`: `["help"]`
/// - `short`: `'h'`
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs
index fad287f..bdefb5a 100644
--- a/mingling/src/example_docs.rs
+++ b/mingling/src/example_docs.rs
@@ -124,6 +124,251 @@
/// }
/// ```
pub mod example_argument_parse {}
+/// 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
+/// ```
+///
+/// Source code (./Cargo.toml)
+/// ```toml
+/// [package]
+/// name = "example-argument-picker"
+/// version = "0.1.0"
+/// edition = "2024"
+///
+/// [dependencies.mingling]
+/// path = "../../mingling"
+///
+/// # Enable `picker` features
+/// features = ["picker", "extra_macros"]
+///
+/// [workspace]
+/// ```
+///
+/// Source code (./src/main.rs)
+/// ```ignore
+/// 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!();
+/// ```
+pub mod example_argument_picker {}
/// Example Async Runtime Support
///
/// > This example shows how to drive an async runtime using the `async` feature
diff --git a/mingling/src/features.rs b/mingling/src/features.rs
index cb474ae..78d6226 100644
--- a/mingling/src/features.rs
+++ b/mingling/src/features.rs
@@ -97,6 +97,17 @@ pub const MINGLING_DISPATCH_TREE: bool = false;
#[cfg(feature = "dispatch_tree")]
#[allow(unused)]
pub const MINGLING_DISPATCH_TREE: bool = true;
+/// Whether the `docs_rs` feature is enabled
+/// Current: `disabled`
+#[cfg(not(feature = "docs_rs"))]
+#[allow(unused)]
+pub const MINGLING_DOCS_RS: bool = false;
+
+/// Whether the `docs_rs` feature is enabled
+/// Current: `enabled`
+#[cfg(feature = "docs_rs")]
+#[allow(unused)]
+pub const MINGLING_DOCS_RS: bool = true;
/// Whether the `extra_macros` feature is enabled
/// Current: `disabled`
#[cfg(not(feature = "extra_macros"))]
diff --git a/mingling/src/lib.md b/mingling/src/lib.md
index 03fa61d..4d20a8b 100644
--- a/mingling/src/lib.md
+++ b/mingling/src/lib.md
@@ -76,7 +76,7 @@ Command not found: [great]
## Examples
`Mingling` provides detailed usage examples for your reference.
-See [Examples](_mingling_examples/index.html) or [Helpdoc](https://mingling-rs.github.io/mingling/docs/examples.html)
+See [Examples](EXAMPLES/index.html) or [Helpdoc](https://mingling-rs.github.io/mingling/docs/examples.html)
## About Features
diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs
index f4bc9dc..f5362d5 100644
--- a/mingling/src/lib.rs
+++ b/mingling/src/lib.rs
@@ -1,3 +1,8 @@
+#![doc(html_logo_url = "https://github.com/mingling-rs/mingling/raw/main/docs/res/icon3.png")]
+#![doc(
+ html_favicon_url = "https://github.com/mingling-rs/mingling/raw/main/docs/res/favicon_small.png"
+)]
+#![deny(missing_docs)]
#![doc = include_str!("lib.md")]
#[cfg(feature = "core")]
@@ -42,6 +47,8 @@ pub mod macros {
/// New Parser provided by the `picker` feature
#[cfg(feature = "picker")]
pub use arg_picker::macros::*;
+ /// `#[buffer]` - Wraps a unit-returning function to produce a `RenderResult`.
+ pub use mingling_macros::buffer;
/// `#[chain]` - Used to generate a struct implementing the `Chain` trait via a method
pub use mingling_macros::chain;
/// `#[completion(EntryType)]` - Used to generate completion entry
@@ -91,6 +98,12 @@ pub mod macros {
/// `#[program_setup]` - Used to generate program setup
#[cfg(feature = "extra_macros")]
pub use mingling_macros::program_setup;
+ /// `r_print!` - Prints text to a `RenderResult` buffer (without newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_print;
+ /// `r_println!` - Prints text to a `RenderResult` buffer (with newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_println;
#[doc(hidden)]
pub use mingling_macros::register_chain;
#[doc(hidden)]
@@ -106,6 +119,10 @@ pub mod macros {
/// `route! { /* ... */ }` - Used to generate a route that either returns a successful result or early returns an error.
#[cfg(feature = "extra_macros")]
pub use mingling_macros::route;
+ /// `#[routeify]` - An extension attribute macro that transforms `expr?` into `route!(expr)`.
+ /// Can be used standalone or as a chain/renderer extension: `#[chain(routeify, ...)]`.
+ #[cfg(feature = "extra_macros")]
+ pub use mingling_macros::routeify;
/// `suggest! { "hello", "bye" }` - Used to generate suggestions
#[cfg(feature = "comp")]
pub use mingling_macros::suggest;
@@ -127,8 +144,9 @@ pub use mingling_macros::Grouped;
pub use mingling_macros::StructuralData;
/// Example projects for `Mingling`, for learning how to use `Mingling`
-#[cfg(feature = "core")]
-pub mod _mingling_examples {
+#[cfg(all(feature = "core", feature = "docs_rs"))]
+#[allow(nonstandard_style)]
+pub mod EXAMPLES {
pub use crate::example_docs::*;
}
@@ -171,12 +189,15 @@ pub mod res;
/// use mingling::prelude::*;
/// ```
pub mod prelude {
- /// Re-export of the `Grouped` derive macro for grouping types.
+ /// Re-export of the `Grouped` trait
#[cfg(feature = "core")]
pub use crate::Grouped;
/// Re-export of the `RenderResult` struct for outputting rendering result
#[cfg(feature = "core")]
pub use crate::RenderResult;
+ /// Re-export of the `Routable` trait
+ #[cfg(feature = "core")]
+ pub use crate::Routable;
/// Re-export of the `chain` macro for defining a chain of commands.
#[cfg(feature = "macros")]
pub use crate::macros::chain;
@@ -208,6 +229,12 @@ pub mod prelude {
/// Like `pack!` but also marks the type for structured output
#[cfg(all(feature = "macros", feature = "structural_renderer"))]
pub use mingling_macros::pack_structural;
+ /// `r_print!` - Prints text to a `RenderResult` buffer (without newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_print;
+ /// `r_println!` - Prints text to a `RenderResult` buffer (with newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_println;
/// Re-export of the `completion` macro for generating completion entries.
#[cfg(all(feature = "macros", feature = "comp"))]
@@ -222,8 +249,4 @@ pub mod prelude {
#[cfg(feature = "picker")]
pub use crate::picker::EntryPicker;
-
- /// Used to enable the `writeln!` macro for `RenderResult`
- #[cfg(feature = "core")]
- pub use std::io::Write;
}
diff --git a/mingling/src/picker/entry_picker.rs b/mingling/src/picker/entry_picker.rs
index 7364c50..d9fb37c 100644
--- a/mingling/src/picker/entry_picker.rs
+++ b/mingling/src/picker/entry_picker.rs
@@ -35,7 +35,7 @@ pub trait EntryPicker<'a, This> {
) -> PickerPattern1<'a, Next, ChainProcess<This>>
where
Self: Sized,
- Next: Pickable<'a> + Default + Sized,
+ Next: Pickable<'a> + Sized,
{
let picker = Self::to_picker(self);
Picker::build_pattern1(picker.into_args(), arg.into(), None)
@@ -60,7 +60,7 @@ pub trait EntryPicker<'a, This> {
) -> PickerPattern1<'a, Next, ChainProcess<This>>
where
Self: Sized,
- Next: Pickable<'a> + Default + Sized,
+ Next: Pickable<'a> + Sized,
F: FnMut() -> Next + 'static,
{
self.pick(arg).or(func)
@@ -107,7 +107,7 @@ pub trait EntryPicker<'a, This> {
) -> PickerPattern1<'a, Next, ChainProcess<This>>
where
Self: Sized,
- Next: Pickable<'a> + Default + Sized,
+ Next: Pickable<'a> + Sized,
F: FnMut() -> ChainProcess<This> + 'static,
{
self.pick(arg).or_route(func)
diff --git a/mingling/src/setups/repl_basic.rs b/mingling/src/setups/repl_basic.rs
index 71a38d2..cf04372 100644
--- a/mingling/src/setups/repl_basic.rs
+++ b/mingling/src/setups/repl_basic.rs
@@ -19,7 +19,9 @@ where
/// meaning only the last configured instance will take effect globally.
/// Do not configure multiple prompts with different values — only one will be used.
pub enum BasicREPLPromptSetup {
+ /// A static prompt string that is displayed before each REPL input.
Prompt(String),
+ /// A function that returns a dynamic prompt string each time the REPL reads input.
Func(fn() -> String),
}