Skip to content

Commit

Permalink
Merge pull request #4509 from epage/possible
Browse files Browse the repository at this point in the history
feat: Improve ValueParser experience
  • Loading branch information
epage authored Nov 24, 2022
2 parents fb1d960 + 94aca92 commit 20e02eb
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 48 deletions.
8 changes: 6 additions & 2 deletions src/builder/possible_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ use crate::util::eq_ignore_case;
///
/// This is used for specifying [possible values] of [Args].
///
/// **NOTE:** This struct is likely not needed for most usecases as it is only required to
/// [hide] single values from help messages and shell completions or to attach [help] to possible values.
/// See also [`PossibleValuesParser`][crate::builder::PossibleValuesParser]
///
/// **NOTE:** Most likely you can use strings, rather than `PossibleValue` as it is only required
/// to [hide] single values from help messages and shell completions or to attach [help] to
/// possible values.
///
/// # Examples
///
Expand All @@ -23,6 +26,7 @@ use crate::util::eq_ignore_case;
/// PossibleValue::new("secret speed").hide(true)
/// ]);
/// ```
///
/// [Args]: crate::Arg
/// [possible values]: crate::builder::ValueParser::possible_values
/// [hide]: PossibleValue::hide()
Expand Down
82 changes: 40 additions & 42 deletions src/builder/value_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,41 @@ where
}
}

/// Create a [`ValueParser`] with [`PossibleValuesParser`]
///
/// See [`PossibleValuesParser`] for more flexibility in creating the
/// [`PossibleValue`][crate::builder::PossibleValue]s.
///
/// # Examples
///
/// ```rust
/// let possible = vec!["always", "auto", "never"];
/// let mut cmd = clap::Command::new("raw")
/// .arg(
/// clap::Arg::new("color")
/// .long("color")
/// .value_parser(possible)
/// .default_value("auto")
/// );
///
/// let m = cmd.try_get_matches_from_mut(
/// ["cmd", "--color", "never"]
/// ).unwrap();
///
/// let color: &String = m.get_one("color")
/// .expect("default");
/// assert_eq!(color, "never");
/// ```
impl<P> From<Vec<P>> for ValueParser
where
P: Into<super::PossibleValue>,
{
fn from(values: Vec<P>) -> Self {
let inner = PossibleValuesParser::from(values);
Self::from(inner)
}
}

impl std::fmt::Debug for ValueParser {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match &self.0 {
Expand Down Expand Up @@ -957,31 +992,11 @@ impl Default for PathBufValueParser {
///
/// ```rust
/// # use std::ffi::OsStr;
/// # use clap::ColorChoice;
/// # use clap::builder::TypedValueParser;
/// # let cmd = clap::Command::new("test");
/// # let arg = None;
///
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// enum ColorChoice {
/// Always,
/// Auto,
/// Never,
/// }
///
/// impl clap::ValueEnum for ColorChoice {
/// fn value_variants<'a>() -> &'a [Self] {
/// &[Self::Always, Self::Auto, Self::Never]
/// }
///
/// fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
/// match self {
/// Self::Always => Some(clap::builder::PossibleValue::new("always")),
/// Self::Auto => Some(clap::builder::PossibleValue::new("auto")),
/// Self::Never => Some(clap::builder::PossibleValue::new("never")),
/// }
/// }
/// }
///
/// // Usage
/// let mut cmd = clap::Command::new("raw")
/// .arg(
Expand Down Expand Up @@ -1086,8 +1101,9 @@ impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> Default for EnumValueP
/// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue].
///
/// See also:
/// - [`EnumValueParser`] for directly supporting `enum`s
/// - [`TypedValueParser::map`] for adapting values to a more specialized type
/// - [`EnumValueParser`] for directly supporting [`ValueEnum`][crate::ValueEnum] types
/// - [`TypedValueParser::map`] for adapting values to a more specialized type, like an external
/// enums that can't implement [`ValueEnum`][crate::ValueEnum]
///
/// # Example
///
Expand Down Expand Up @@ -2327,6 +2343,7 @@ pub mod via_prelude {
///
/// Example mappings:
/// ```rust
/// # use clap::ColorChoice;
/// // Built-in types
/// let parser = clap::value_parser!(String);
/// assert_eq!(format!("{:?}", parser), "ValueParser::string");
Expand All @@ -2344,25 +2361,6 @@ pub mod via_prelude {
/// assert_eq!(format!("{:?}", parser), "_AnonymousValueParser(ValueParser::other(usize))");
///
/// // ValueEnum types
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// enum ColorChoice {
/// Always,
/// Auto,
/// Never,
/// }
/// impl clap::ValueEnum for ColorChoice {
/// // ...
/// # fn value_variants<'a>() -> &'a [Self] {
/// # &[Self::Always, Self::Auto, Self::Never]
/// # }
/// # fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
/// # match self {
/// # Self::Always => Some(clap::builder::PossibleValue::new("always")),
/// # Self::Auto => Some(clap::builder::PossibleValue::new("auto")),
/// # Self::Never => Some(clap::builder::PossibleValue::new("never")),
/// # }
/// # }
/// }
/// let parser = clap::value_parser!(ColorChoice);
/// assert_eq!(format!("{:?}", parser), "EnumValueParser(PhantomData)");
/// ```
Expand Down
4 changes: 0 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,7 @@ pub use crate::builder::Command;
pub use crate::builder::ValueHint;
pub use crate::builder::{Arg, ArgGroup};
pub use crate::parser::ArgMatches;
#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;
#[cfg(not(feature = "color"))]
#[allow(unused_imports)]
pub(crate) use crate::util::color::ColorChoice;
pub use crate::util::Id;

/// Command Line Argument Parser Error
Expand Down
22 changes: 22 additions & 0 deletions src/util/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ impl Default for ColorChoice {
}
}

impl std::fmt::Display for ColorChoice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_possible_value()
.expect("no values are skipped")
.get_name()
.fmt(f)
}
}

impl std::str::FromStr for ColorChoice {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
for variant in Self::value_variants() {
if variant.to_possible_value().unwrap().matches(s, false) {
return Ok(*variant);
}
}
Err(format!("Invalid variant: {}", s))
}
}

impl ValueEnum for ColorChoice {
fn value_variants<'a>() -> &'a [Self] {
&[Self::Auto, Self::Always, Self::Never]
Expand Down

0 comments on commit 20e02eb

Please sign in to comment.