Skip to content

Commit 20e02eb

Browse files
authored
Merge pull request #4509 from epage/possible
feat: Improve ValueParser experience
2 parents fb1d960 + 94aca92 commit 20e02eb

File tree

4 files changed

+68
-48
lines changed

4 files changed

+68
-48
lines changed

src/builder/possible_value.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ use crate::util::eq_ignore_case;
77
///
88
/// This is used for specifying [possible values] of [Args].
99
///
10-
/// **NOTE:** This struct is likely not needed for most usecases as it is only required to
11-
/// [hide] single values from help messages and shell completions or to attach [help] to possible values.
10+
/// See also [`PossibleValuesParser`][crate::builder::PossibleValuesParser]
11+
///
12+
/// **NOTE:** Most likely you can use strings, rather than `PossibleValue` as it is only required
13+
/// to [hide] single values from help messages and shell completions or to attach [help] to
14+
/// possible values.
1215
///
1316
/// # Examples
1417
///
@@ -23,6 +26,7 @@ use crate::util::eq_ignore_case;
2326
/// PossibleValue::new("secret speed").hide(true)
2427
/// ]);
2528
/// ```
29+
///
2630
/// [Args]: crate::Arg
2731
/// [possible values]: crate::builder::ValueParser::possible_values
2832
/// [hide]: PossibleValue::hide()

src/builder/value_parser.rs

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,41 @@ where
508508
}
509509
}
510510

511+
/// Create a [`ValueParser`] with [`PossibleValuesParser`]
512+
///
513+
/// See [`PossibleValuesParser`] for more flexibility in creating the
514+
/// [`PossibleValue`][crate::builder::PossibleValue]s.
515+
///
516+
/// # Examples
517+
///
518+
/// ```rust
519+
/// let possible = vec!["always", "auto", "never"];
520+
/// let mut cmd = clap::Command::new("raw")
521+
/// .arg(
522+
/// clap::Arg::new("color")
523+
/// .long("color")
524+
/// .value_parser(possible)
525+
/// .default_value("auto")
526+
/// );
527+
///
528+
/// let m = cmd.try_get_matches_from_mut(
529+
/// ["cmd", "--color", "never"]
530+
/// ).unwrap();
531+
///
532+
/// let color: &String = m.get_one("color")
533+
/// .expect("default");
534+
/// assert_eq!(color, "never");
535+
/// ```
536+
impl<P> From<Vec<P>> for ValueParser
537+
where
538+
P: Into<super::PossibleValue>,
539+
{
540+
fn from(values: Vec<P>) -> Self {
541+
let inner = PossibleValuesParser::from(values);
542+
Self::from(inner)
543+
}
544+
}
545+
511546
impl std::fmt::Debug for ValueParser {
512547
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
513548
match &self.0 {
@@ -957,31 +992,11 @@ impl Default for PathBufValueParser {
957992
///
958993
/// ```rust
959994
/// # use std::ffi::OsStr;
995+
/// # use clap::ColorChoice;
960996
/// # use clap::builder::TypedValueParser;
961997
/// # let cmd = clap::Command::new("test");
962998
/// # let arg = None;
963999
///
964-
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
965-
/// enum ColorChoice {
966-
/// Always,
967-
/// Auto,
968-
/// Never,
969-
/// }
970-
///
971-
/// impl clap::ValueEnum for ColorChoice {
972-
/// fn value_variants<'a>() -> &'a [Self] {
973-
/// &[Self::Always, Self::Auto, Self::Never]
974-
/// }
975-
///
976-
/// fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
977-
/// match self {
978-
/// Self::Always => Some(clap::builder::PossibleValue::new("always")),
979-
/// Self::Auto => Some(clap::builder::PossibleValue::new("auto")),
980-
/// Self::Never => Some(clap::builder::PossibleValue::new("never")),
981-
/// }
982-
/// }
983-
/// }
984-
///
9851000
/// // Usage
9861001
/// let mut cmd = clap::Command::new("raw")
9871002
/// .arg(
@@ -1086,8 +1101,9 @@ impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> Default for EnumValueP
10861101
/// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue].
10871102
///
10881103
/// See also:
1089-
/// - [`EnumValueParser`] for directly supporting `enum`s
1090-
/// - [`TypedValueParser::map`] for adapting values to a more specialized type
1104+
/// - [`EnumValueParser`] for directly supporting [`ValueEnum`][crate::ValueEnum] types
1105+
/// - [`TypedValueParser::map`] for adapting values to a more specialized type, like an external
1106+
/// enums that can't implement [`ValueEnum`][crate::ValueEnum]
10911107
///
10921108
/// # Example
10931109
///
@@ -2327,6 +2343,7 @@ pub mod via_prelude {
23272343
///
23282344
/// Example mappings:
23292345
/// ```rust
2346+
/// # use clap::ColorChoice;
23302347
/// // Built-in types
23312348
/// let parser = clap::value_parser!(String);
23322349
/// assert_eq!(format!("{:?}", parser), "ValueParser::string");
@@ -2344,25 +2361,6 @@ pub mod via_prelude {
23442361
/// assert_eq!(format!("{:?}", parser), "_AnonymousValueParser(ValueParser::other(usize))");
23452362
///
23462363
/// // ValueEnum types
2347-
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2348-
/// enum ColorChoice {
2349-
/// Always,
2350-
/// Auto,
2351-
/// Never,
2352-
/// }
2353-
/// impl clap::ValueEnum for ColorChoice {
2354-
/// // ...
2355-
/// # fn value_variants<'a>() -> &'a [Self] {
2356-
/// # &[Self::Always, Self::Auto, Self::Never]
2357-
/// # }
2358-
/// # fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
2359-
/// # match self {
2360-
/// # Self::Always => Some(clap::builder::PossibleValue::new("always")),
2361-
/// # Self::Auto => Some(clap::builder::PossibleValue::new("auto")),
2362-
/// # Self::Never => Some(clap::builder::PossibleValue::new("never")),
2363-
/// # }
2364-
/// # }
2365-
/// }
23662364
/// let parser = clap::value_parser!(ColorChoice);
23672365
/// assert_eq!(format!("{:?}", parser), "EnumValueParser(PhantomData)");
23682366
/// ```

src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,7 @@ pub use crate::builder::Command;
102102
pub use crate::builder::ValueHint;
103103
pub use crate::builder::{Arg, ArgGroup};
104104
pub use crate::parser::ArgMatches;
105-
#[cfg(feature = "color")]
106105
pub use crate::util::color::ColorChoice;
107-
#[cfg(not(feature = "color"))]
108-
#[allow(unused_imports)]
109-
pub(crate) use crate::util::color::ColorChoice;
110106
pub use crate::util::Id;
111107

112108
/// Command Line Argument Parser Error

src/util/color.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,28 @@ impl Default for ColorChoice {
6464
}
6565
}
6666

67+
impl std::fmt::Display for ColorChoice {
68+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69+
self.to_possible_value()
70+
.expect("no values are skipped")
71+
.get_name()
72+
.fmt(f)
73+
}
74+
}
75+
76+
impl std::str::FromStr for ColorChoice {
77+
type Err = String;
78+
79+
fn from_str(s: &str) -> Result<Self, Self::Err> {
80+
for variant in Self::value_variants() {
81+
if variant.to_possible_value().unwrap().matches(s, false) {
82+
return Ok(*variant);
83+
}
84+
}
85+
Err(format!("Invalid variant: {}", s))
86+
}
87+
}
88+
6789
impl ValueEnum for ColorChoice {
6890
fn value_variants<'a>() -> &'a [Self] {
6991
&[Self::Auto, Self::Always, Self::Never]

0 commit comments

Comments
 (0)