aboutsummaryrefslogtreecommitdiff
path: root/mingling
diff options
context:
space:
mode:
Diffstat (limited to 'mingling')
-rw-r--r--mingling/Cargo.toml7
-rw-r--r--mingling/src/constants.rs11
-rw-r--r--mingling/src/constants/exit_codes.rs14
-rw-r--r--mingling/src/constants/picker.rs115
-rw-r--r--mingling/src/example_docs.rs291
-rw-r--r--mingling/src/features.rs11
-rw-r--r--mingling/src/lib.md2
-rw-r--r--mingling/src/lib.rs87
-rw-r--r--mingling/src/parser/picker.rs4
-rw-r--r--mingling/src/picker.rs13
-rw-r--r--mingling/src/picker/entry_picker.rs126
-rw-r--r--mingling/src/picker/global.rs35
-rw-r--r--mingling/src/setups.rs7
-rw-r--r--mingling/src/setups/basic.rs26
-rw-r--r--mingling/src/setups/exit_code.rs11
-rw-r--r--mingling/src/setups/picker.rs7
-rw-r--r--mingling/src/setups/picker/basic.rs123
-rw-r--r--mingling/src/setups/picker/structural_renderer.rs76
-rw-r--r--mingling/src/setups/repl_basic.rs4
-rw-r--r--mingling/src/setups/structural_renderer.rs14
20 files changed, 941 insertions, 43 deletions
diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml
index adf900f..351384f 100644
--- a/mingling/Cargo.toml
+++ b/mingling/Cargo.toml
@@ -21,7 +21,9 @@ mingling = { path = ".", features = [
] }
[package.metadata.docs.rs]
+rustdoc-args = ["--generate-link-to-definition"]
features = [
+ "docs_rs",
"core",
"macros",
"builds",
@@ -50,7 +52,7 @@ dispatch_tree = ["mingling_core/dispatch_tree", "mingling_macros/dispatch_tree"]
repl = ["mingling_core/repl", "mingling_macros/repl"]
comp = ["mingling_core/comp", "mingling_macros/comp"]
parser = ["dep:size"]
-picker = ["dep:arg-picker", "arg-picker/mingling_support"]
+picker = ["mingling_core/picker", "dep:arg-picker", "arg-picker/mingling_support"]
pathf = ["mingling_core/pathf", "mingling_macros/pathf"]
structural_renderer = [
@@ -87,6 +89,9 @@ ron_serde_fmt = ["mingling_core/ron_serde_fmt"]
extra_macros = ["mingling_macros/extra_macros"]
+# Section only shown in docs.rs
+docs_rs = []
+
[dependencies]
mingling_core = { workspace = true, optional = true }
mingling_macros = { workspace = true, optional = true }
diff --git a/mingling/src/constants.rs b/mingling/src/constants.rs
new file mode 100644
index 0000000..75f1c73
--- /dev/null
+++ b/mingling/src/constants.rs
@@ -0,0 +1,11 @@
+#[cfg(feature = "picker")]
+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/exit_codes.rs b/mingling/src/constants/exit_codes.rs
new file mode 100644
index 0000000..2359f42
--- /dev/null
+++ b/mingling/src/constants/exit_codes.rs
@@ -0,0 +1,14 @@
+/// Exit code indicating successful command execution.
+pub const EXIT_SUCCESS: i32 = 0;
+
+/// Exit code for general errors.
+pub const EXIT_GENERAL_ERR: i32 = 1;
+
+/// Exit code for incorrect command usage (or invalid arguments).
+pub const EXIT_USAGE_ERR: i32 = 2;
+
+/// Exit code indicating permission denied (or the command is not executable).
+pub const EXIT_PERM_DENIED: i32 = 126;
+
+/// Exit code for command not found (or PATH error).
+pub const EXIT_CMD_NOT_FOUND: i32 = 127;
diff --git a/mingling/src/constants/picker.rs b/mingling/src/constants/picker.rs
new file mode 100644
index 0000000..d98dcab
--- /dev/null
+++ b/mingling/src/constants/picker.rs
@@ -0,0 +1,115 @@
+use arg_picker::{PickerArg, value::Flag};
+use std::marker::PhantomData;
+
+/// Help flag: display usage information.
+/// - `full`: `["help"]`
+/// - `short`: `'h'`
+pub const HELP_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["help"],
+ short: Some('h'),
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// Quiet flag: suppress output.
+/// - `full`: `["quiet"]`
+/// - `short`: `'q'`
+pub const QUIET_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["quiet"],
+ short: Some('q'),
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// Confirm flag: require user confirmation before proceeding.
+/// - `full`: `["confirm"]`
+/// - `short`: `'C'`
+pub const CONFIRM_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["confirm"],
+ short: Some('C'),
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// Renderer flag: explicitly specify the Structural Renderer argument.
+/// - `full`: `["renderer"]`
+/// - `short`: (none)
+#[cfg(feature = "structural_renderer")]
+pub const RENDERER_ARG: PickerArg<String> = PickerArg::<String> {
+ full: &["renderer"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// JSON flag: enable JSON output format.
+/// - `full`: `["json"]`
+/// - `short`: (none)
+/// Available only when the `json_serde_fmt` feature is enabled.
+#[cfg(feature = "json_serde_fmt")]
+pub const JSON_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["json"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// JSON pretty flag: enable pretty-printed JSON output format.
+/// - `full`: `["json_pretty"]`
+/// - `short`: (none)
+/// Available only when the `json_serde_fmt` feature is enabled.
+#[cfg(feature = "json_serde_fmt")]
+pub const JSON_PRETTY_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["json_pretty"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// YAML flag: enable YAML output format.
+/// - `full`: `["yaml"]`
+/// - `short`: (none)
+/// Available only when the `yaml_serde_fmt` feature is enabled.
+#[cfg(feature = "yaml_serde_fmt")]
+pub const YAML_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["yaml"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// TOML flag: enable TOML output format.
+/// - `full`: `["toml"]`
+/// - `short`: (none)
+/// Available only when the `toml_serde_fmt` feature is enabled.
+#[cfg(feature = "toml_serde_fmt")]
+pub const TOML_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["toml"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// RON flag: enable RON output format.
+/// - `full`: `["ron"]`
+/// - `short`: (none)
+/// Available only when the `ron_serde_fmt` feature is enabled.
+#[cfg(feature = "ron_serde_fmt")]
+pub const RON_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["ron"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
+
+/// RON pretty flag: enable pretty-printed RON output format.
+/// - `full`: `["ron_pretty"]`
+/// - `short`: (none)
+/// Available only when the `ron_serde_fmt` feature is enabled.
+#[cfg(feature = "ron_serde_fmt")]
+pub const RON_PRETTY_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
+ full: &["ron_pretty"],
+ short: None,
+ positional: false,
+ internal_type: PhantomData,
+};
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs
index c4f59c9..89d5af1 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
@@ -378,7 +623,7 @@ pub mod example_basic {}
///
/// Source code (./src/main.rs)
/// ```ignore
-/// use mingling::{Groupped, macros::dispatcher_clap, prelude::*, setup::BasicProgramSetup};
+/// use mingling::{Grouped, macros::dispatcher_clap, prelude::*, setup::BasicProgramSetup};
/// use std::io::Write;
///
/// fn main() {
@@ -407,10 +652,10 @@ pub mod example_basic {}
/// // 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
@@ -724,15 +969,15 @@ pub mod example_completion {}
///
/// Source code (./src/main.rs)
/// ```ignore
-/// 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,
@@ -963,7 +1208,7 @@ pub mod example_dispatch_tree {}
/// Source code (./src/main.rs)
/// ```ignore
/// 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;
@@ -972,7 +1217,7 @@ pub mod example_dispatch_tree {}
/// // ________ 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,
@@ -1404,7 +1649,7 @@ pub mod example_help {}
/// .on_pre_chain(|info| {
/// println!("[DEBUG] Pre chain: {}", info.input);
/// })
-/// .on_post_chain(|info| println!("[DEBUG] Post chain: {}", info.output.member_id))
+/// .on_post_chain(|info| println!("[DEBUG] Post chain: {}", info.output.member_id()))
/// .on_finish(|_| {
/// println!("[DEBUG] Loop end");
/// ProgramControlUnit::OverrideExitCode(0) // Override exit code
@@ -1691,7 +1936,7 @@ pub mod example_lazy_resources {}
/// /// 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();
@@ -2436,7 +2681,7 @@ pub mod example_setup {}
/// Source code (./src/main.rs)
/// ```ignore
/// 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;
///
@@ -2453,12 +2698,12 @@ pub mod example_setup {}
/// // --------- 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,
@@ -2551,25 +2796,25 @@ pub mod example_structural_renderer {}
/// #[test]
/// fn test_render_result_name() {
/// let r = render_result_name(ResultName::new("Peter".into()));
-/// assert_eq!(r.to_string().as_str(), "Hello, Peter!\n")
+/// 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());
-/// assert_eq!(r.to_string().as_str(), "No name provided\n")
+/// 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());
-/// assert_eq!(r.to_string().as_str(), "Name not available\n")
+/// 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));
-/// assert_eq!(r.to_string().as_str(), "Name too long: 17 > 10\n")
+/// assert_eq!(r.to_string().as_str(), "Name too long: 17 > 10")
/// }
/// // --------- IMPORTANT ---------
/// }
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 718d282..fd274aa 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")]
@@ -16,12 +21,13 @@ pub mod parser;
/// `Mingling` argument parser (Picker2)
#[cfg(feature = "picker")]
-pub mod picker {
- pub use arg_picker::*;
+pub mod picker;
- pub mod parselib {
- pub use arg_picker::parselib::*;
- }
+mod constants;
+
+/// Constants used throughout the Mingling framework.
+pub mod consts {
+ pub use crate::constants::*;
}
/// Re-export of all macros from `mingling_macros`.
@@ -41,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
@@ -67,6 +75,9 @@ pub mod macros {
pub use mingling_macros::group_structural;
/// `#[help]` - Used to generate a struct implementing the `HelpRequest` trait via a method
pub use mingling_macros::help;
+ /// `#[mlint(...)]` - Marker attribute for the Mingling lint system.
+ /// Content is ignored by rustc and reserved for mlint tooling.
+ pub use mingling_macros::mlint;
/// `node!("remote.rm")` - Used to create a `Node` struct via a literal
pub use mingling_macros::node;
/// `pack!(StateGreet = String)` - Used to create a wrapper type for use with `Chain` and `Renderer`
@@ -90,6 +101,21 @@ pub mod macros {
/// `#[program_setup]` - Used to generate program setup
#[cfg(feature = "extra_macros")]
pub use mingling_macros::program_setup;
+ /// `r_append!` - Appends the contents of one `RenderResult` to another.
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_append;
+ /// `r_eprint!` - Prints text to a `RenderResult` error buffer (without newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_eprint;
+ /// `r_eprintln!` - Prints text to a `RenderResult` error buffer (with newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_eprintln;
+ /// `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)]
@@ -100,11 +126,24 @@ pub mod macros {
pub use mingling_macros::register_renderer;
#[doc(hidden)]
pub use mingling_macros::register_type;
+ /// `render_route! { /* ... */ }` - Routes errors to the rendering pipeline.
+ /// Similar to `route!`, but used in `#[renderer]` and `#[help]` functions
+ /// where the return type is `RenderResult` instead of `ChainProcess`.
+ #[cfg(feature = "extra_macros")]
+ pub use mingling_macros::render_route;
/// `#[renderer]` - Used to generate a struct implementing the `Renderer` trait via a method
pub use mingling_macros::renderer;
+ /// `#[renderify]` - An extension attribute macro that transforms `expr?` into `render_route!(expr)`.
+ /// Can be used standalone or as a renderer/help extension: `#[renderer(renderify, ...)]`, `#[help(renderify, ...)]`.
+ #[cfg(feature = "extra_macros")]
+ pub use mingling_macros::renderify;
/// `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;
@@ -117,17 +156,18 @@ pub mod macros {
#[cfg(feature = "macros")]
pub use mingling_macros::EnumTag;
-/// derive macro Groupped
+/// derive macro Grouped
#[cfg(feature = "macros")]
-pub use mingling_macros::Groupped;
+pub use mingling_macros::Grouped;
/// derive macro `StructuralData` — marks a type as supporting structured output
#[cfg(feature = "structural_renderer")]
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::*;
}
@@ -170,12 +210,15 @@ pub mod res;
/// use mingling::prelude::*;
/// ```
pub mod prelude {
- /// Re-export of the `Groupped` derive macro for grouping types.
+ /// Re-export of the `Grouped` trait
#[cfg(feature = "core")]
- pub use crate::Groupped;
+ 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;
@@ -207,6 +250,21 @@ 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_append!` - Appends the contents of one `RenderResult` to another.
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_append;
+ /// `r_eprint!` - Prints text to a `RenderResult` error buffer (without newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_eprint;
+ /// `r_eprintln!` - Prints text to a `RenderResult` error buffer (with newline).
+ /// See the macro documentation for implicit vs. explicit buffer usage.
+ pub use mingling_macros::r_eprintln;
+ /// `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"))]
@@ -217,9 +275,8 @@ pub mod prelude {
pub use crate::parser::AsPicker;
#[cfg(feature = "picker")]
- pub use arg_picker::prelude::*;
+ pub use arg_picker::prelude::arg;
- /// Used to enable the `writeln!` macro for `RenderResult`
- #[cfg(feature = "core")]
- pub use std::io::Write;
+ #[cfg(feature = "picker")]
+ pub use crate::picker::EntryPicker;
}
diff --git a/mingling/src/parser/picker.rs b/mingling/src/parser/picker.rs
index 601cd3f..ca4561c 100644
--- a/mingling/src/parser/picker.rs
+++ b/mingling/src/parser/picker.rs
@@ -743,6 +743,10 @@ where
}
}
+/// Trait for types that can be converted into a `Picker` to extract values from command-line arguments.
+///
+/// This trait provides a convenient way to convert a value (such as `Vec<String>`, `&[String]`, etc.)
+/// into a `Picker` and immediately start extracting values associated with specific flags.
pub trait AsPicker
where
Self: Into<Vec<String>>,
diff --git a/mingling/src/picker.rs b/mingling/src/picker.rs
new file mode 100644
index 0000000..f370656
--- /dev/null
+++ b/mingling/src/picker.rs
@@ -0,0 +1,13 @@
+/// Provides the specific parsing logic for command-line arguments and common utilities,
+/// as well as customization of command-line argument styles.
+pub mod parselib {
+ pub use arg_picker::parselib::*;
+}
+
+pub use arg_picker::*;
+
+mod entry_picker;
+pub use entry_picker::*;
+
+mod global;
+pub use global::*;
diff --git a/mingling/src/picker/entry_picker.rs b/mingling/src/picker/entry_picker.rs
new file mode 100644
index 0000000..d9fb37c
--- /dev/null
+++ b/mingling/src/picker/entry_picker.rs
@@ -0,0 +1,126 @@
+use mingling_core::{ChainProcess, Grouped, ProgramCollect};
+
+use crate::{picker::Pickable, picker::Picker, picker::PickerArg, picker::PickerPattern1};
+
+/// Trait for converting Mingling entry types (types that implement `Grouped<R>` and `Into<Vec<String>>`)
+/// into [`Picker`] instances for a given route type `R`.
+///
+/// This trait provides a bridge between entry definitions created with the `mingling` framework
+/// and the picker argument system used for CLI argument parsing and routing.
+///
+/// # Type Parameters
+///
+/// * `'a` — The lifetime of the picker and its references to argument definitions.
+/// * `This` — The program type used for dispatching runtime routes; must implement [`ProgramCollect`].
+/// * `Route` — The route type used for dispatching; must implement [`Grouped<This>`].
+pub trait EntryPicker<'a, This> {
+ /// Converts `self` into a [`Picker`] for the given route type `Route`.
+ fn to_picker(self) -> Picker<'a, ChainProcess<This>>;
+
+ /// Starts building a picker pattern with the first argument.
+ ///
+ /// Returns a [`PickerPattern1`] that can be further chained with additional
+ /// arguments, defaults, routes, and post-processing.
+ ///
+ /// # Type Parameters
+ ///
+ /// * `Next` — The nominal type of the first argument; must implement [`Pickable`].
+ ///
+ /// # Parameters
+ ///
+ /// * `arg` — The argument definition, typically obtained from [`crate::macros::arg`].
+ fn pick<Next>(
+ self,
+ arg: impl Into<&'a PickerArg<'a, Next>>,
+ ) -> PickerPattern1<'a, Next, ChainProcess<This>>
+ where
+ Self: Sized,
+ Next: Pickable<'a> + Sized,
+ {
+ let picker = Self::to_picker(self);
+ Picker::build_pattern1(picker.into_args(), arg.into(), None)
+ }
+
+ /// Starts building a picker pattern with the first argument, using a default value provider.
+ ///
+ /// This is a shorthand for calling `.pick(arg).or(func)`.
+ ///
+ /// # Type Parameters
+ ///
+ /// * `Next` — The nominal type of the first argument; must implement [`Pickable`].
+ ///
+ /// # Parameters
+ ///
+ /// * `arg` — The argument definition, typically obtained from [`crate::macros::arg`].
+ /// * `func` — A closure that provides a default value if the arg is not provided by the user.
+ fn pick_or<Next, F>(
+ self,
+ arg: impl Into<&'a PickerArg<'a, Next>>,
+ func: F,
+ ) -> PickerPattern1<'a, Next, ChainProcess<This>>
+ where
+ Self: Sized,
+ Next: Pickable<'a> + Sized,
+ F: FnMut() -> Next + 'static,
+ {
+ self.pick(arg).or(func)
+ }
+
+ /// Starts building a picker pattern with the first argument, using a default value.
+ ///
+ /// This is a shorthand for calling `.pick(arg).or_default()`.
+ ///
+ /// # Type Parameters
+ ///
+ /// * `Next` — The nominal type of the first argument; must implement [`Pickable`] and [`Default`].
+ ///
+ /// # Parameters
+ ///
+ /// * `arg` — The argument definition, typically obtained from [`crate::macros::arg`].
+ fn pick_or_default<Next>(
+ self,
+ arg: impl Into<&'a PickerArg<'a, Next>>,
+ ) -> PickerPattern1<'a, Next, ChainProcess<This>>
+ where
+ Self: Sized,
+ Next: Pickable<'a> + Default + Sized,
+ {
+ self.pick(arg).or_default()
+ }
+
+ /// Starts building a picker pattern with the first argument, using a route if the arg is not provided.
+ ///
+ /// This is a shorthand for calling `.pick(arg).or_route(func)`.
+ ///
+ /// # Type Parameters
+ ///
+ /// * `Next` — The nominal type of the first argument; must implement [`Pickable`].
+ ///
+ /// # Parameters
+ ///
+ /// * `arg` — The argument definition, typically obtained from [`crate::macros::arg`].
+ /// * `func` — A closure that produces a route value if the arg is not provided by the user.
+ fn pick_or_route<Next, F>(
+ self,
+ arg: impl Into<&'a PickerArg<'a, Next>>,
+ func: F,
+ ) -> PickerPattern1<'a, Next, ChainProcess<This>>
+ where
+ Self: Sized,
+ Next: Pickable<'a> + Sized,
+ F: FnMut() -> ChainProcess<This> + 'static,
+ {
+ self.pick(arg).or_route(func)
+ }
+}
+
+impl<'a, This, Bind> EntryPicker<'a, This> for Bind
+where
+ This: ProgramCollect<Enum = This>,
+ Bind: Grouped<This> + Into<Vec<String>>,
+{
+ fn to_picker(self) -> Picker<'a, ChainProcess<This>> {
+ let args = self.into();
+ Picker::from(args)
+ }
+}
diff --git a/mingling/src/picker/global.rs b/mingling/src/picker/global.rs
new file mode 100644
index 0000000..c203524
--- /dev/null
+++ b/mingling/src/picker/global.rs
@@ -0,0 +1,35 @@
+use arg_picker::{IntoPicker, Pickable, PickerArg, value::Flag};
+use mingling_core::{Program, ProgramCollect};
+
+use crate::consts::REMAINS;
+
+/// Picks a global flag from the program's arguments.
+///
+/// This function takes ownership of the program's current arguments, picks the specified `flag`
+/// from them, and then returns the remaining arguments back to the program. It returns the
+/// boolean value of the flag.
+pub fn pick_global_flag<C>(program: &mut Program<C>, flag: &PickerArg<Flag>) -> bool
+where
+ C: ProgramCollect<Enum = C>,
+{
+ let args = program.take_args();
+ let (flag, args) = args.pick(flag).pick(&REMAINS).unwrap();
+ program.replace_args(args.into());
+ *flag
+}
+
+/// Picks a global argument from the program's arguments.
+///
+/// This function takes ownership of the program's current arguments, picks the specified `arg`
+/// from them, and then returns the remaining arguments back to the program. It returns the
+/// picked argument value, or `None` if the argument was not present.
+pub fn pick_global_argument<C, A>(program: &mut Program<C>, arg: &PickerArg<A>) -> Option<A>
+where
+ A: for<'a> Pickable<'a> + Default,
+ C: ProgramCollect<Enum = C>,
+{
+ let args = program.take_args();
+ let (arg, remains) = args.pick(arg).pick(&REMAINS).unpack();
+ program.replace_args(remains.unwrap().into());
+ arg
+}
diff --git a/mingling/src/setups.rs b/mingling/src/setups.rs
index e572cf5..6fd728a 100644
--- a/mingling/src/setups.rs
+++ b/mingling/src/setups.rs
@@ -7,6 +7,13 @@ pub use dirs::*;
mod exit_code;
pub use exit_code::*;
+/// Picker's `ProgramSetup` variant.
+///
+/// Internally does not use its own argument parsing,
+/// but relies on `arg_picker`'s argument parsing capability.
+#[cfg(feature = "picker")]
+pub mod picker;
+
#[cfg(feature = "structural_renderer")]
mod structural_renderer;
diff --git a/mingling/src/setups/basic.rs b/mingling/src/setups/basic.rs
index 6a69733..e081c3e 100644
--- a/mingling/src/setups/basic.rs
+++ b/mingling/src/setups/basic.rs
@@ -1,3 +1,5 @@
+#![allow(deprecated)]
+
use mingling_core::{Flag, Program, ProgramCollect, setup::ProgramSetup};
/// Performs basic program initialization:
@@ -5,6 +7,12 @@ use mingling_core::{Flag, Program, ProgramCollect, setup::ProgramSetup};
/// - Collects `--quiet` flag to control message rendering
/// - Collects `--help` flag to enable help mode
/// - Collects `--confirm` flag to skip user confirmation
+#[cfg_attr(
+ feature = "picker",
+ deprecated(
+ note = "When the `picker` feature is enabled, you can use `mingling::setup::picker::BasicProgramSetup` instead"
+ )
+)]
pub struct BasicProgramSetup;
impl<C> ProgramSetup<C> for BasicProgramSetup
@@ -21,6 +29,12 @@ where
/// Provides setup for parsing the user help flag
///
/// The default value is `--help / -h`
+#[cfg_attr(
+ feature = "picker",
+ deprecated(
+ note = "When the `picker` feature is enabled, you can use `mingling::setup::picker::HelpFlagSetup` instead"
+ )
+)]
pub struct HelpFlagSetup {
flag: Flag,
}
@@ -54,6 +68,12 @@ impl Default for HelpFlagSetup {
/// Provides setup for parsing the quiet flag
///
/// The default value is `--quiet / -q`
+#[cfg_attr(
+ feature = "picker",
+ deprecated(
+ note = "When the `picker` feature is enabled, you can use `mingling::setup::picker::QuietFlagSetup` instead"
+ )
+)]
pub struct QuietFlagSetup {
flag: Flag,
}
@@ -88,6 +108,12 @@ impl Default for QuietFlagSetup {
/// Provides setup for parsing the confirm flag
///
/// The default value is `--confirm / -C`
+#[cfg_attr(
+ feature = "picker",
+ deprecated(
+ note = "When the `picker` feature is enabled, you can use `mingling::setup::picker::ConfirmFlagSetup` instead"
+ )
+)]
pub struct ConfirmFlagSetup {
flag: Flag,
}
diff --git a/mingling/src/setups/exit_code.rs b/mingling/src/setups/exit_code.rs
index 025ed8a..6b8a1ef 100644
--- a/mingling/src/setups/exit_code.rs
+++ b/mingling/src/setups/exit_code.rs
@@ -2,7 +2,7 @@ use std::marker::PhantomData;
use mingling_core::{
ProgramCollect,
- hook::{ProgramControlUnit, ProgramHook},
+ hook::{ProgramControlUnit, ProgramControls, ProgramHook},
setup::ProgramSetup,
this,
};
@@ -39,7 +39,14 @@ where
// Insert hook to override exit code before program ends
program.with_hook(ProgramHook::empty().on_finish(|_| {
let this = this::<C>().res_or_default::<ResExitCode>();
- ProgramControlUnit::OverrideExitCode(this.exit_code)
+ let ec = this.exit_code;
+
+ // Only override when ResExitCode has been modified
+ if ec != 0 {
+ ProgramControlUnit::OverrideExitCode(this.exit_code).into()
+ } else {
+ ProgramControls::Empty
+ }
}));
}
}
diff --git a/mingling/src/setups/picker.rs b/mingling/src/setups/picker.rs
new file mode 100644
index 0000000..0b7bd33
--- /dev/null
+++ b/mingling/src/setups/picker.rs
@@ -0,0 +1,7 @@
+mod basic;
+pub use basic::*;
+
+#[cfg(feature = "structural_renderer")]
+mod structural_renderer;
+#[cfg(feature = "structural_renderer")]
+pub use structural_renderer::*;
diff --git a/mingling/src/setups/picker/basic.rs b/mingling/src/setups/picker/basic.rs
new file mode 100644
index 0000000..c9f82b3
--- /dev/null
+++ b/mingling/src/setups/picker/basic.rs
@@ -0,0 +1,123 @@
+use arg_picker::{PickerArg, value::Flag};
+use mingling_core::{Program, ProgramCollect, setup::ProgramSetup};
+
+use crate::{
+ consts::{CONFIRM_FLAG, HELP_FLAG, QUIET_FLAG},
+ picker::pick_global_flag,
+};
+
+/// Performs basic program initialization:
+///
+/// - Collects `--quiet` flag to control message rendering
+/// - Collects `--help` flag to enable help mode
+/// - Collects `--confirm` flag to skip user confirmation
+pub struct BasicProgramSetup;
+
+impl<C> ProgramSetup<C> for BasicProgramSetup
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn setup(self, program: &mut Program<C>) {
+ program.with_setup(HelpFlagSetup::default());
+ program.with_setup(QuietFlagSetup::default());
+ program.with_setup(ConfirmFlagSetup::default());
+ }
+}
+
+/// Provides setup for parsing the user help flag
+///
+/// The default value is `--help / -h`
+pub struct HelpFlagSetup<'a> {
+ flag: &'a PickerArg<'a, Flag>,
+}
+
+impl<'a> HelpFlagSetup<'a> {
+ /// Creates a new `HelpFlagSetup` with the given flag aliases.
+ pub fn new(flag: &'a PickerArg<Flag>) -> Self {
+ Self { flag }
+ }
+}
+
+impl<'a, C> ProgramSetup<C> for HelpFlagSetup<'a>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn setup(self, program: &mut Program<C>) {
+ let help = pick_global_flag(program, self.flag);
+ if help {
+ program.user_context.help = true;
+ }
+ }
+}
+
+impl<'a> Default for HelpFlagSetup<'a> {
+ fn default() -> Self {
+ Self { flag: &HELP_FLAG }
+ }
+}
+
+/// Provides setup for parsing the quiet flag
+///
+/// The default value is `--quiet / -q`
+pub struct QuietFlagSetup<'a> {
+ flag: &'a PickerArg<'a, Flag>,
+}
+
+impl<'a> QuietFlagSetup<'a> {
+ /// Creates a new `QuietFlagSetup` with the given flag aliases.
+ pub fn new(flag: &'a PickerArg<Flag>) -> Self {
+ Self { flag }
+ }
+}
+
+impl<'a, C> ProgramSetup<C> for QuietFlagSetup<'a>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn setup(self, program: &mut Program<C>) {
+ let help = pick_global_flag(program, self.flag);
+ if help {
+ program.stdout_setting.quiet = true;
+ }
+ }
+}
+
+impl<'a> Default for QuietFlagSetup<'a> {
+ fn default() -> Self {
+ Self { flag: &QUIET_FLAG }
+ }
+}
+
+/// Provides setup for parsing the confirm flag
+///
+/// The default value is `--confirm / -C`
+pub struct ConfirmFlagSetup<'a> {
+ flag: &'a PickerArg<'a, Flag>,
+}
+
+impl<'a> ConfirmFlagSetup<'a> {
+ /// Creates a new `ConfirmFlagSetup` with the given flag aliases.
+ pub fn new(flag: &'a PickerArg<Flag>) -> Self {
+ Self { flag }
+ }
+}
+
+impl<'a, C> ProgramSetup<C> for ConfirmFlagSetup<'a>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn setup(self, program: &mut Program<C>) {
+ let help = pick_global_flag(program, self.flag);
+ if help {
+ program.user_context.confirm = true;
+ }
+ }
+}
+
+impl<'a> Default for ConfirmFlagSetup<'a> {
+ fn default() -> Self {
+ Self {
+ flag: &CONFIRM_FLAG,
+ }
+ }
+}
diff --git a/mingling/src/setups/picker/structural_renderer.rs b/mingling/src/setups/picker/structural_renderer.rs
new file mode 100644
index 0000000..1fa48fd
--- /dev/null
+++ b/mingling/src/setups/picker/structural_renderer.rs
@@ -0,0 +1,76 @@
+use mingling_core::{Program, ProgramCollect, setup::ProgramSetup};
+
+use crate::{
+ consts::RENDERER_ARG,
+ picker::{pick_global_argument, pick_global_flag},
+};
+
+/// Sets up the structural renderer for the program:
+///
+/// - Adds a `--renderer` global argument to specify the renderer type
+pub struct StructuralRendererSimpleSetup;
+
+impl<C> ProgramSetup<C> for StructuralRendererSimpleSetup
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn setup(self, program: &mut Program<C>) {
+ if let Some(renderer) = pick_global_argument(program, &RENDERER_ARG) {
+ program.structural_renderer_name = renderer.into();
+ }
+ }
+}
+
+/// Sets up the structural renderer for the program:
+///
+/// - Adds global flags to specify the renderer type:
+/// * `--json` for JSON output
+/// * `--json-pretty` for pretty-printed JSON output
+/// * `--yaml` for YAML output
+/// * `--toml` for TOML output
+/// * `--ron` for RON output
+/// * `--ron-pretty` for pretty-printed RON output
+///
+/// # Flag priority
+///
+/// If multiple flags are specified, the last matching flag in the following
+/// declaration order takes precedence:
+/// 1. `--json`
+/// 2. `--json-pretty`
+/// 3. `--yaml`
+/// 4. `--toml`
+/// 5. `--ron`
+/// 6. `--ron-pretty`
+pub struct StructuralRendererSetup;
+
+impl<C> ProgramSetup<C> for StructuralRendererSetup
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn setup(self, program: &mut Program<C>) {
+ #[cfg(feature = "json_serde_fmt")]
+ if pick_global_flag(program, &crate::consts::JSON_FLAG) {
+ program.structural_renderer_name = crate::StructuralRendererSetting::Json;
+ }
+ #[cfg(feature = "json_serde_fmt")]
+ if pick_global_flag(program, &crate::consts::JSON_PRETTY_FLAG) {
+ program.structural_renderer_name = crate::StructuralRendererSetting::JsonPretty;
+ }
+ #[cfg(feature = "yaml_serde_fmt")]
+ if pick_global_flag(program, &crate::consts::YAML_FLAG) {
+ program.structural_renderer_name = crate::StructuralRendererSetting::Yaml;
+ }
+ #[cfg(feature = "toml_serde_fmt")]
+ if pick_global_flag(program, &crate::consts::TOML_FLAG) {
+ program.structural_renderer_name = crate::StructuralRendererSetting::Toml;
+ }
+ #[cfg(feature = "ron_serde_fmt")]
+ if pick_global_flag(program, &crate::consts::RON_FLAG) {
+ program.structural_renderer_name = crate::StructuralRendererSetting::Ron;
+ }
+ #[cfg(feature = "ron_serde_fmt")]
+ if pick_global_flag(program, &crate::consts::RON_PRETTY_FLAG) {
+ program.structural_renderer_name = crate::StructuralRendererSetting::RonPretty;
+ }
+ }
+}
diff --git a/mingling/src/setups/repl_basic.rs b/mingling/src/setups/repl_basic.rs
index 71a38d2..150048b 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),
}
@@ -73,7 +75,7 @@ where
fn setup(self, program: &mut Program<C>) {
program.with_hook(ProgramHook::empty().on_repl_receive_result(|r| {
if !r.result.is_empty() {
- println!("{}", r.result.trim())
+ println!("{}", r.result)
}
}));
}
diff --git a/mingling/src/setups/structural_renderer.rs b/mingling/src/setups/structural_renderer.rs
index af3ed91..0ab2347 100644
--- a/mingling/src/setups/structural_renderer.rs
+++ b/mingling/src/setups/structural_renderer.rs
@@ -1,8 +1,16 @@
+#![allow(deprecated)]
+
use mingling_core::{Program, ProgramCollect, setup::ProgramSetup};
/// Sets up the structural renderer for the program:
///
/// - Adds a `--renderer` global argument to specify the renderer type
+#[cfg_attr(
+ feature = "picker",
+ deprecated(
+ note = "When the `picker` feature is enabled, you can use `mingling::setup::picker::StructuralRendererSimpleSetup` instead"
+ )
+)]
pub struct StructuralRendererSimpleSetup;
impl<C> ProgramSetup<C> for StructuralRendererSimpleSetup
@@ -25,6 +33,12 @@ where
/// * `--toml` for TOML output
/// * `--ron` for RON output
/// * `--ron-pretty` for pretty-printed RON output
+#[cfg_attr(
+ feature = "picker",
+ deprecated(
+ note = "When the `picker` feature is enabled, you can use `mingling::setup::picker::StructuralRendererSetup` instead"
+ )
+)]
pub struct StructuralRendererSetup;
impl<C> ProgramSetup<C> for StructuralRendererSetup