aboutsummaryrefslogtreecommitdiff
path: root/mingling
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-19 00:22:23 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-19 00:27:16 +0800
commit5e460470f6ea2ce31a403b6e936ec2fe8f45312a (patch)
treeec1d675d9544b31ab9382ebbd10bbeda43923cc8 /mingling
parent9b4cffd48482481691f782e74a4726294043bc57 (diff)
feat: migrate mingling-specific picker code into mingling crate
BREAKING CHANGE: Remove `mingling_support` feature from arg-picker crate. The `EntryPicker` trait and `corebind` module are now part of the mingling crate directly, and `build_pattern1` is now a public method.
Diffstat (limited to 'mingling')
-rw-r--r--mingling/Cargo.toml2
-rw-r--r--mingling/src/constants.rs8
-rw-r--r--mingling/src/constants/exit_codes.rs14
-rw-r--r--mingling/src/constants/picker.rs (renamed from mingling/src/setups/picker/consts.rs)11
-rw-r--r--mingling/src/lib.rs11
-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/picker.rs3
-rw-r--r--mingling/src/setups/picker/basic.rs39
-rw-r--r--mingling/src/setups/picker/structural_renderer.rs93
11 files changed, 260 insertions, 95 deletions
diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml
index adf900f..6945b67 100644
--- a/mingling/Cargo.toml
+++ b/mingling/Cargo.toml
@@ -50,7 +50,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 = ["dep:arg-picker"]
pathf = ["mingling_core/pathf", "mingling_macros/pathf"]
structural_renderer = [
diff --git a/mingling/src/constants.rs b/mingling/src/constants.rs
new file mode 100644
index 0000000..65d02e8
--- /dev/null
+++ b/mingling/src/constants.rs
@@ -0,0 +1,8 @@
+#[cfg(feature = "picker")]
+mod picker;
+
+#[cfg(feature = "picker")]
+pub use picker::*;
+
+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/setups/picker/consts.rs b/mingling/src/constants/picker.rs
index 5e93f3f..f2a448b 100644
--- a/mingling/src/setups/picker/consts.rs
+++ b/mingling/src/constants/picker.rs
@@ -45,6 +45,17 @@ pub const CONFIRM_FLAG: PickerArg<Flag> = PickerArg::<Flag> {
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)
diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs
index 718d282..499390d 100644
--- a/mingling/src/lib.rs
+++ b/mingling/src/lib.rs
@@ -16,12 +16,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`.
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..7a980c6
--- /dev/null
+++ b/mingling/src/picker/entry_picker.rs
@@ -0,0 +1,126 @@
+use mingling_core::{ChainProcess, Groupped, ProgramCollect};
+
+use crate::{picker::Pickable, picker::Picker, picker::PickerArg, picker::PickerPattern1};
+
+/// Trait for converting Mingling entry types (types that implement `Groupped<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 [`Groupped<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> + Default + 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> + Default + 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> + Default + 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: Groupped<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/picker.rs b/mingling/src/setups/picker.rs
index 3c0d1c8..0b7bd33 100644
--- a/mingling/src/setups/picker.rs
+++ b/mingling/src/setups/picker.rs
@@ -5,6 +5,3 @@ pub use basic::*;
mod structural_renderer;
#[cfg(feature = "structural_renderer")]
pub use structural_renderer::*;
-
-mod consts;
-pub use consts::*;
diff --git a/mingling/src/setups/picker/basic.rs b/mingling/src/setups/picker/basic.rs
index 318edbd..b8cc237 100644
--- a/mingling/src/setups/picker/basic.rs
+++ b/mingling/src/setups/picker/basic.rs
@@ -1,27 +1,11 @@
-use arg_picker::{IntoPicker, PickerArg, value::Flag};
+use arg_picker::{PickerArg, value::Flag};
use mingling_core::{Program, ProgramCollect, setup::ProgramSetup};
use crate::{
- setup::picker::REMAINS,
- setups::picker::{CONFIRM_FLAG, HELP_FLAG, QUIET_FLAG},
+ consts::{CONFIRM_FLAG, HELP_FLAG, QUIET_FLAG},
+ picker::pick_global_flag,
};
-/// Helper: picks a boolean flag from the program arguments, calls `f` with the
-/// flag value, then replaces the program arguments with the remaining args.
-fn pick_flag<'a, C>(
- program: &mut Program<C>,
- flag: &PickerArg<'a, Flag>,
- f: impl FnOnce(bool, &mut Program<C>),
-) where
- C: ProgramCollect<Enum = C>,
-{
- let args = program.take_args();
- let remains_arg = PickerArg::<PickerArgs<'a>>::new(&[], None, true);
- let (active, remains) = args.pick(flag).pick(&remains_arg).unwrap();
- f(*active, program);
- program.replace_args(remains.into());
-}
-
/// Performs basic program initialization:
///
/// - Collects `--quiet` flag to control message rendering
@@ -59,9 +43,7 @@ where
C: ProgramCollect<Enum = C>,
{
fn setup(self, program: &mut Program<C>) {
- pick_flag(program, self.flag, |active, ctx| {
- ctx.user_context.help = active;
- });
+ pick_global_flag(program, self.flag);
}
}
@@ -90,12 +72,7 @@ where
C: ProgramCollect<Enum = C>,
{
fn setup(self, program: &mut Program<C>) {
- pick_flag(program, self.flag, |active, ctx| {
- if active {
- ctx.stdout_setting.render_output = false;
- ctx.stdout_setting.error_output = false;
- }
- });
+ pick_global_flag(program, self.flag);
}
}
@@ -124,11 +101,7 @@ where
C: ProgramCollect<Enum = C>,
{
fn setup(self, program: &mut Program<C>) {
- pick_flag(program, self.flag, |active, ctx| {
- if active {
- ctx.user_context.confirm = true;
- }
- });
+ pick_global_flag(program, self.flag);
}
}
diff --git a/mingling/src/setups/picker/structural_renderer.rs b/mingling/src/setups/picker/structural_renderer.rs
index 8e5eac6..1fa48fd 100644
--- a/mingling/src/setups/picker/structural_renderer.rs
+++ b/mingling/src/setups/picker/structural_renderer.rs
@@ -1,11 +1,8 @@
-use arg_picker::IntoPicker;
use mingling_core::{Program, ProgramCollect, setup::ProgramSetup};
use crate::{
- setup::picker::REMAINS,
- setups::picker::{
- JSON_FLAG, JSON_PRETTY_FLAG, RON_FLAG, RON_PRETTY_FLAG, TOML_FLAG, YAML_FLAG,
- },
+ consts::RENDERER_ARG,
+ picker::{pick_global_argument, pick_global_flag},
};
/// Sets up the structural renderer for the program:
@@ -18,9 +15,9 @@ where
C: ProgramCollect<Enum = C>,
{
fn setup(self, program: &mut Program<C>) {
- program.global_argument("--renderer", |p, renderer| {
- p.structural_renderer_name = renderer.into();
- });
+ if let Some(renderer) = pick_global_argument(program, &RENDERER_ARG) {
+ program.structural_renderer_name = renderer.into();
+ }
}
}
@@ -33,6 +30,17 @@ where
/// * `--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
@@ -40,50 +48,29 @@ where
C: ProgramCollect<Enum = C>,
{
fn setup(self, program: &mut Program<C>) {
- let args = program.take_args();
- let args = process_renderer_flags(args, program);
- program.replace_args(args);
+ #[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;
+ }
}
}
-
-fn process_renderer_flags<C>(args: Vec<String>, program: &mut Program<C>) -> Vec<String>
-where
- C: ProgramCollect<Enum = C>,
-{
- let (json, json_pretty, yaml, toml, ron, ron_pretty, remains) = args
- .pick(&JSON_FLAG)
- .pick(&JSON_PRETTY_FLAG)
- .pick(&YAML_FLAG)
- .pick(&TOML_FLAG)
- .pick(&RON_FLAG)
- .pick(&RON_PRETTY_FLAG)
- .pick(&REMAINS)
- .unwrap();
-
- #[cfg(feature = "json_serde_fmt")]
- if *json {
- program.structural_renderer_name = crate::StructuralRendererSetting::Json;
- }
- #[cfg(feature = "json_serde_fmt")]
- if *json_pretty {
- program.structural_renderer_name = crate::StructuralRendererSetting::JsonPretty;
- }
- #[cfg(feature = "yaml_serde_fmt")]
- if *yaml {
- program.structural_renderer_name = crate::StructuralRendererSetting::Yaml;
- }
- #[cfg(feature = "toml_serde_fmt")]
- if *toml {
- program.structural_renderer_name = crate::StructuralRendererSetting::Toml;
- }
- #[cfg(feature = "ron_serde_fmt")]
- if *ron {
- program.structural_renderer_name = crate::StructuralRendererSetting::Ron;
- }
- #[cfg(feature = "ron_serde_fmt")]
- if *ron_pretty {
- program.structural_renderer_name = crate::StructuralRendererSetting::RonPretty;
- }
-
- remains.into()
-}