aboutsummaryrefslogtreecommitdiff
path: root/mingling_picker/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_picker/src')
-rw-r--r--mingling_picker/src/flag.rs4
-rw-r--r--mingling_picker/src/lib.rs3
-rw-r--r--mingling_picker/src/parselib.rs3
-rw-r--r--mingling_picker/src/parselib/seek.rs1
-rw-r--r--mingling_picker/src/pickable.rs22
-rw-r--r--mingling_picker/src/pickable/implements.rs52
-rw-r--r--mingling_picker/src/picker.rs2
-rw-r--r--mingling_picker/src/picker/parse.rs2
-rw-r--r--mingling_picker/src/picker/patterns.rs10
-rw-r--r--mingling_picker/src/tag.rs176
10 files changed, 231 insertions, 44 deletions
diff --git a/mingling_picker/src/flag.rs b/mingling_picker/src/flag.rs
index 0b351f8..86712c9 100644
--- a/mingling_picker/src/flag.rs
+++ b/mingling_picker/src/flag.rs
@@ -24,7 +24,7 @@ use std::marker::PhantomData;
#[derive(Default, Clone, Copy)]
pub struct PickerFlag<'a, Type>
where
- Type: Default + Pickable,
+ Type: Default + Pickable<'a>,
{
/// Full name, may include variant names (aliases), e.g., `["config", "cfg"]`.
pub full: &'a [&'a str],
@@ -41,7 +41,7 @@ where
impl<'a, Type> PickerFlag<'a, Type>
where
- Type: Default + Pickable,
+ Type: Default + Pickable<'a>,
{
/// Creates a new `PickerFlag` with the provided parameters.
pub fn new(full: &'a [&'a str], short: Option<char>, positional: bool) -> Self {
diff --git a/mingling_picker/src/lib.rs b/mingling_picker/src/lib.rs
index d3d3fdd..fa45d71 100644
--- a/mingling_picker/src/lib.rs
+++ b/mingling_picker/src/lib.rs
@@ -10,6 +10,9 @@ pub use flag::*;
mod result;
pub use result::*;
+mod tag;
+pub use tag::*;
+
pub mod parselib;
pub mod prelude {
diff --git a/mingling_picker/src/parselib.rs b/mingling_picker/src/parselib.rs
index 132045b..21f0ba2 100644
--- a/mingling_picker/src/parselib.rs
+++ b/mingling_picker/src/parselib.rs
@@ -1,2 +1,5 @@
+mod seek;
+// pub use seek::*;
+
mod style;
pub use style::*;
diff --git a/mingling_picker/src/parselib/seek.rs b/mingling_picker/src/parselib/seek.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/mingling_picker/src/parselib/seek.rs
@@ -0,0 +1 @@
+
diff --git a/mingling_picker/src/pickable.rs b/mingling_picker/src/pickable.rs
index 9fe2c9d..7a89631 100644
--- a/mingling_picker/src/pickable.rs
+++ b/mingling_picker/src/pickable.rs
@@ -1,4 +1,4 @@
-use crate::PickerResult;
+use crate::{PickerFlag, PickerResult, PickerTag};
mod implements;
@@ -20,20 +20,28 @@ mod implements;
/// # Examples
///
/// ```
-/// # use mingling_picker::{Pickable, PickerResult};
+/// # use mingling_picker::{Pickable, PickerResult, PickerFlag, PickerTag};
/// #[derive(Default)]
/// struct MyType(String);
///
-/// impl Pickable for MyType {
-/// fn pick(raw_str: &str) -> PickerResult<Self> {
-/// PickerResult::Parsed(MyType(raw_str.to_string()))
+/// impl<'a> Pickable<'a> for MyType {
+/// fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a> {
+/// let tag = PickerTag::from(flag);
+/// }
+///
+/// fn pick(raw_strs: &[&str]) -> PickerResult<Self> {
+/// PickerResult::Parsed(MyType(raw_strs.join(" ")))
/// }
/// }
/// ```
-pub trait Pickable
+pub trait Pickable<'a>
where
Self: Sized + Default,
{
+ /// Given a [`PickerFlag`], returns a [`PickerTag`] that tells the parser
+ /// about the argument's characteristics (e.g., positional, optional, multi).
+ fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a>;
+
/// Parses a `Self` value from the given raw string input.
- fn pick(raw_str: &str) -> PickerResult<Self>;
+ fn pick(raw_strs: &[&str]) -> PickerResult<Self>;
}
diff --git a/mingling_picker/src/pickable/implements.rs b/mingling_picker/src/pickable/implements.rs
index 34f9727..665bde5 100644
--- a/mingling_picker/src/pickable/implements.rs
+++ b/mingling_picker/src/pickable/implements.rs
@@ -1,15 +1,20 @@
-use crate::{Pickable, PickerResult};
-use std::path::PathBuf;
+use crate::{Pickable, PickerFlag, PickerResult, PickerTag};
macro_rules! impl_pickable {
($($t:ty),*) => {
- $(
- impl Pickable for $t {
- fn pick(raw_str: &str) -> PickerResult<Self> {
- raw_str.parse::<$t>().into()
- }
+ $(impl<'a> Pickable<'a> for $t {
+ fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a> {
+ flag.into()
}
- )*
+
+ fn pick(raw_strs: &[&str]) -> PickerResult<Self> {
+ raw_strs
+ .first()
+ .and_then(|s| s.parse().ok())
+ .map(PickerResult::Parsed)
+ .unwrap_or(PickerResult::NotFound)
+ }
+ })*
};
}
@@ -17,27 +22,18 @@ impl_pickable!(
i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, f32, f64, isize
);
-impl Pickable for String {
- fn pick(raw_str: &str) -> PickerResult<Self> {
- PickerResult::Parsed(raw_str.to_string())
+impl<'a> Pickable<'a> for String {
+ fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a> {
+ let mut tag: PickerTag = flag.into();
+ tag.set_optional(false);
+ tag.set_multi(false);
+ tag
}
-}
-impl Pickable for PathBuf {
- fn pick(raw_str: &str) -> PickerResult<Self> {
- PickerResult::Parsed(PathBuf::from(raw_str))
- }
-}
-
-impl<T: Pickable> Pickable for Option<T> {
- fn pick(raw_str: &str) -> PickerResult<Self> {
- if raw_str.is_empty() {
- PickerResult::Parsed(None)
- } else {
- match T::pick(raw_str) {
- PickerResult::Parsed(v) => PickerResult::Parsed(Some(v)),
- _ => PickerResult::Parsed(None),
- }
- }
+ fn pick(raw_strs: &[&str]) -> PickerResult<Self> {
+ raw_strs
+ .first()
+ .map(|s| PickerResult::Parsed(s.to_string()))
+ .unwrap_or(PickerResult::NotFound)
}
}
diff --git a/mingling_picker/src/picker.rs b/mingling_picker/src/picker.rs
index 01c94a9..3a740cf 100644
--- a/mingling_picker/src/picker.rs
+++ b/mingling_picker/src/picker.rs
@@ -241,7 +241,7 @@ pub trait IntoPicker<'a> {
fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N>
where
Self: Sized,
- N: Pickable + Default + Sized,
+ N: Pickable<'a> + Default + Sized,
{
PickerPattern1 {
args: self.to_picker().args,
diff --git a/mingling_picker/src/picker/parse.rs b/mingling_picker/src/picker/parse.rs
index defbcbf..f69e078 100644
--- a/mingling_picker/src/picker/parse.rs
+++ b/mingling_picker/src/picker/parse.rs
@@ -7,7 +7,7 @@ internal_repeat!(1..=32 => {
internal_repeat!(1..=32 => {
impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)>
- where (T$: Pickable + Default,+)
+ where (T$: Pickable<'a> + Default,+)
{
#[allow(clippy::type_complexity)]
pub fn parse(self) -> PickerResult<((T$,+))> {
diff --git a/mingling_picker/src/picker/patterns.rs b/mingling_picker/src/picker/patterns.rs
index a33860b..b12f151 100644
--- a/mingling_picker/src/picker/patterns.rs
+++ b/mingling_picker/src/picker/patterns.rs
@@ -5,7 +5,7 @@ use crate::{Pickable, Picker, PickerArgs, PickerFlag, PickerResult};
internal_repeat!(1..=32 => {
#[doc(hidden)]
pub struct PickerPattern$<'a, (T$,+)>
- where (T$: Pickable + Default,+)
+ where (T$: Pickable<'a> + Default,+)
{
pub args: PickerArgs<'a>,
(
@@ -19,7 +19,7 @@ internal_repeat!(1..=32 => {
internal_repeat!(1..=32 => {
impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)>
- where (T$: Pickable + Default,+)
+ where (T$: Pickable<'a> + Default,+)
{
/// Sets a default value provider for this flag.
///
@@ -70,7 +70,7 @@ internal_repeat!(1..=32 => {
internal_repeat!(1..32 => {
impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)>
- where (T$: Pickable + Default,+)
+ where (T$: Pickable<'a> + Default,+)
{
#[allow(clippy::type_complexity)]
/// Adds a new flag to the picking chain, returning a new `PickerPattern` with one more type parameter.
@@ -80,7 +80,7 @@ internal_repeat!(1..32 => {
/// The new flag's result is initially `Unparsed`.
pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern$+<'a, (T$,+), N>
where
- N: Pickable + Default,
+ N: Pickable<'a> + Default,
{
PickerPattern$+ {
// Args
@@ -111,7 +111,7 @@ impl<'a> Picker<'a> {
/// The result is initially `Unparsed`.
pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N>
where
- N: Pickable + Default,
+ N: Pickable<'a> + Default,
{
PickerPattern1 {
args: self.args,
diff --git a/mingling_picker/src/tag.rs b/mingling_picker/src/tag.rs
new file mode 100644
index 0000000..6f91630
--- /dev/null
+++ b/mingling_picker/src/tag.rs
@@ -0,0 +1,176 @@
+use crate::{Pickable, PickerFlag};
+
+/// Represents a command-line argument/flag tag for a picker.
+///
+/// This struct defines how a picker argument should be parsed from the command line,
+/// including its short name (e.g., `-n`), long name (e.g., `--name`), and aliases.
+///
+/// # Fields
+///
+/// * `short` - The short form of the tag, typically a single character (e.g., `-n`).
+/// * `long` - The long form of the tag (e.g., `--name`).
+/// * `alias` - Alternative names for the tag (e.g., `["-N", "--nickname"]`).
+/// * `positional` - Whether this tag is a positional argument (no `-` or `--` prefix).
+/// * `optional` - Whether this tag is optional or required.
+/// * `multi` - Whether this tag can accept multiple values.
+pub struct PickerTag<'a> {
+ /// The short form of the tag, e.g. `'n'` for `-n`.
+ pub short: Option<char>,
+ /// The long form of the tag, e.g. `"name"` for `--name`.
+ pub long: Option<&'a str>,
+ /// Alternative names for the tag, e.g. `["-N", "--nickname"]`.
+ pub alias: Option<Vec<&'a str>>,
+ /// Whether this tag is a positional argument (no `-` or `--` prefix).
+ pub positional: bool,
+ /// Whether this tag is optional or required.
+ pub optional: bool,
+ /// Whether this tag can accept multiple values.
+ pub multi: bool,
+}
+
+impl<'a, T> From<PickerFlag<'a, T>> for PickerTag<'a>
+where
+ T: Pickable<'a> + Default,
+{
+ fn from(value: PickerFlag<'a, T>) -> Self {
+ let (long, alias) = match value.full.len() {
+ 0 => (None, None),
+ _ => {
+ let long = Some(value.full[0]);
+ let alias = if value.full.len() > 1 {
+ Some(value.full[1..].to_vec())
+ } else {
+ None
+ };
+ (long, alias)
+ }
+ };
+
+ Self {
+ short: value.short,
+ long,
+ alias,
+ positional: value.positional,
+ optional: false,
+ multi: false,
+ }
+ }
+}
+
+impl<'a, T: Pickable<'a> + Default> From<&'a PickerFlag<'a, T>> for PickerTag<'a> {
+ fn from(value: &'a PickerFlag<'a, T>) -> Self {
+ let (long, alias) = match value.full.len() {
+ 0 => (None, None),
+ _ => {
+ let long = Some(value.full[0]);
+ let alias = if value.full.len() > 1 {
+ Some(value.full[1..].to_vec())
+ } else {
+ None
+ };
+ (long, alias)
+ }
+ };
+
+ Self {
+ short: value.short,
+ long,
+ alias,
+ positional: value.positional,
+ optional: false,
+ multi: false,
+ }
+ }
+}
+
+impl<'a> PickerTag<'a> {
+ /// Create a new `PickerTag` with default values.
+ pub fn new() -> Self {
+ Self {
+ short: None,
+ long: None,
+ alias: None,
+ positional: false,
+ optional: false,
+ multi: false,
+ }
+ }
+
+ /// Set the short flag (e.g., `'n'` for `-n`).
+ pub fn with_short(mut self, short: char) -> Self {
+ self.short = Some(short);
+ self
+ }
+
+ /// Set the long flag (e.g., `"name"` for `--name`).
+ pub fn with_long(mut self, long: &'a str) -> Self {
+ self.long = Some(long);
+ self
+ }
+
+ /// Set aliases for the tag.
+ pub fn with_alias(mut self, alias: Vec<&'a str>) -> Self {
+ self.alias = Some(alias);
+ self
+ }
+
+ /// Mark the tag as positional.
+ pub fn with_positional(mut self, positional: bool) -> Self {
+ self.positional = positional;
+ self
+ }
+
+ /// Mark the tag as optional.
+ pub fn with_optional(mut self, optional: bool) -> Self {
+ self.optional = optional;
+ self
+ }
+
+ /// Mark the tag as multi-value.
+ pub fn with_multi(mut self, multi: bool) -> Self {
+ self.multi = multi;
+ self
+ }
+
+ /// Set the short flag (e.g., `'n'` for `-n`).
+ pub fn set_short(&mut self, short: char) -> &mut Self {
+ self.short = Some(short);
+ self
+ }
+
+ /// Set the long flag (e.g., `"name"` for `--name`).
+ pub fn set_long(&mut self, long: &'a str) -> &mut Self {
+ self.long = Some(long);
+ self
+ }
+
+ /// Set aliases for the tag.
+ pub fn set_alias(&mut self, alias: Vec<&'a str>) -> &mut Self {
+ self.alias = Some(alias);
+ self
+ }
+
+ /// Set whether this tag is positional.
+ pub fn set_positional(&mut self, positional: bool) -> &mut Self {
+ self.positional = positional;
+ self
+ }
+
+ /// Set whether this tag is optional.
+ pub fn set_optional(&mut self, optional: bool) -> &mut Self {
+ self.optional = optional;
+ self
+ }
+
+ /// Set whether this tag accepts multiple values.
+ pub fn set_multi(&mut self, multi: bool) -> &mut Self {
+ self.multi = multi;
+ self
+ }
+}
+
+impl<'a> Default for PickerTag<'a> {
+ fn default() -> Self {
+ Self::new()
+ }
+}