| //! This module contains traits that are usable with the `#[derive(...)].` |
| //! macros in [`clap_derive`]. |
| |
| use crate::builder::PossibleValue; |
| use crate::{ArgMatches, Command, Error}; |
| |
| use std::ffi::OsString; |
| |
| /// Parse command-line arguments into `Self`. |
| /// |
| /// The primary one-stop-shop trait used to create an instance of a `clap` |
| /// [`Command`], conduct the parsing, and turn the resulting [`ArgMatches`] back |
| /// into concrete instance of the user struct. |
| /// |
| /// This trait is primarily a convenience on top of [`FromArgMatches`] + |
| /// [`CommandFactory`] which uses those two underlying traits to build the two |
| /// fundamental functions `parse` which uses the `std::env::args_os` iterator, |
| /// and `parse_from` which allows the consumer to supply the iterator (along |
| /// with fallible options for each). |
| /// |
| /// See also [`Subcommand`] and [`Args`]. |
| /// |
| /// See the [derive reference](crate::_derive) for attributes and best practices. |
| /// |
| /// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] |
| /// |
| /// # Examples |
| /// |
| /// The following example creates a `Context` struct that would be used |
| /// throughout the application representing the normalized values coming from |
| /// the CLI. |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```")] |
| /// /// My super CLI |
| /// #[derive(clap::Parser)] |
| /// #[command(name = "demo")] |
| /// struct Context { |
| /// /// More verbose output |
| /// #[arg(long)] |
| /// verbose: bool, |
| /// /// An optional name |
| /// #[arg(short, long)] |
| /// name: Option<String>, |
| /// } |
| /// ``` |
| /// |
| /// The equivalent [`Command`] struct + `From` implementation: |
| /// |
| /// ```rust |
| /// # use clap::{Command, Arg, ArgMatches, ArgAction}; |
| /// Command::new("demo") |
| /// .about("My super CLI") |
| /// .arg(Arg::new("verbose") |
| /// .long("verbose") |
| /// .action(ArgAction::SetTrue) |
| /// .help("More verbose output")) |
| /// .arg(Arg::new("name") |
| /// .long("name") |
| /// .short('n') |
| /// .help("An optional name") |
| /// .action(ArgAction::Set)); |
| /// |
| /// struct Context { |
| /// verbose: bool, |
| /// name: Option<String>, |
| /// } |
| /// |
| /// impl From<ArgMatches> for Context { |
| /// fn from(m: ArgMatches) -> Self { |
| /// Context { |
| /// verbose: m.get_flag("verbose"), |
| /// name: m.get_one::<String>("name").cloned(), |
| /// } |
| /// } |
| /// } |
| /// ``` |
| /// |
| pub trait Parser: FromArgMatches + CommandFactory + Sized { |
| /// Parse from `std::env::args_os()`, exit on error |
| fn parse() -> Self { |
| let mut matches = <Self as CommandFactory>::command().get_matches(); |
| let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches) |
| .map_err(format_error::<Self>); |
| match res { |
| Ok(s) => s, |
| Err(e) => { |
| // Since this is more of a development-time error, we aren't doing as fancy of a quit |
| // as `get_matches` |
| e.exit() |
| } |
| } |
| } |
| |
| /// Parse from `std::env::args_os()`, return Err on error. |
| fn try_parse() -> Result<Self, Error> { |
| let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches()); |
| <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>) |
| } |
| |
| /// Parse from iterator, exit on error |
| fn parse_from<I, T>(itr: I) -> Self |
| where |
| I: IntoIterator<Item = T>, |
| T: Into<OsString> + Clone, |
| { |
| let mut matches = <Self as CommandFactory>::command().get_matches_from(itr); |
| let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches) |
| .map_err(format_error::<Self>); |
| match res { |
| Ok(s) => s, |
| Err(e) => { |
| // Since this is more of a development-time error, we aren't doing as fancy of a quit |
| // as `get_matches_from` |
| e.exit() |
| } |
| } |
| } |
| |
| /// Parse from iterator, return Err on error. |
| fn try_parse_from<I, T>(itr: I) -> Result<Self, Error> |
| where |
| I: IntoIterator<Item = T>, |
| T: Into<OsString> + Clone, |
| { |
| let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches_from(itr)); |
| <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>) |
| } |
| |
| /// Update from iterator, exit on error |
| fn update_from<I, T>(&mut self, itr: I) |
| where |
| I: IntoIterator<Item = T>, |
| T: Into<OsString> + Clone, |
| { |
| let mut matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr); |
| let res = <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches) |
| .map_err(format_error::<Self>); |
| if let Err(e) = res { |
| // Since this is more of a development-time error, we aren't doing as fancy of a quit |
| // as `get_matches_from` |
| e.exit() |
| } |
| } |
| |
| /// Update from iterator, return Err on error. |
| fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error> |
| where |
| I: IntoIterator<Item = T>, |
| T: Into<OsString> + Clone, |
| { |
| let mut matches = |
| ok!(<Self as CommandFactory>::command_for_update().try_get_matches_from(itr)); |
| <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches) |
| .map_err(format_error::<Self>) |
| } |
| } |
| |
| /// Create a [`Command`] relevant for a user-defined container. |
| /// |
| /// Derived as part of [`Parser`]. |
| pub trait CommandFactory: Sized { |
| /// Build a [`Command`] that can instantiate `Self`. |
| /// |
| /// See [`FromArgMatches::from_arg_matches_mut`] for instantiating `Self`. |
| fn command() -> Command; |
| /// Build a [`Command`] that can update `self`. |
| /// |
| /// See [`FromArgMatches::update_from_arg_matches_mut`] for updating `self`. |
| fn command_for_update() -> Command; |
| } |
| |
| /// Converts an instance of [`ArgMatches`] to a user-defined container. |
| /// |
| /// Derived as part of [`Parser`], [`Args`], and [`Subcommand`]. |
| pub trait FromArgMatches: Sized { |
| /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed. |
| /// |
| /// Motivation: If our application had two CLI options, `--name |
| /// <STRING>` and the flag `--debug`, we may create a struct as follows: |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```no_run")] |
| /// struct Context { |
| /// name: String, |
| /// debug: bool |
| /// } |
| /// ``` |
| /// |
| /// We then need to convert the `ArgMatches` that `clap` generated into our struct. |
| /// `from_arg_matches` serves as the equivalent of: |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```no_run")] |
| /// # use clap::ArgMatches; |
| /// # struct Context { |
| /// # name: String, |
| /// # debug: bool |
| /// # } |
| /// impl From<ArgMatches> for Context { |
| /// fn from(m: ArgMatches) -> Self { |
| /// Context { |
| /// name: m.get_one::<String>("name").unwrap().clone(), |
| /// debug: m.get_flag("debug"), |
| /// } |
| /// } |
| /// } |
| /// ``` |
| fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error>; |
| |
| /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed. |
| /// |
| /// Motivation: If our application had two CLI options, `--name |
| /// <STRING>` and the flag `--debug`, we may create a struct as follows: |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```no_run")] |
| /// struct Context { |
| /// name: String, |
| /// debug: bool |
| /// } |
| /// ``` |
| /// |
| /// We then need to convert the `ArgMatches` that `clap` generated into our struct. |
| /// `from_arg_matches_mut` serves as the equivalent of: |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```no_run")] |
| /// # use clap::ArgMatches; |
| /// # struct Context { |
| /// # name: String, |
| /// # debug: bool |
| /// # } |
| /// impl From<ArgMatches> for Context { |
| /// fn from(m: ArgMatches) -> Self { |
| /// Context { |
| /// name: m.get_one::<String>("name").unwrap().to_string(), |
| /// debug: m.get_flag("debug"), |
| /// } |
| /// } |
| /// } |
| /// ``` |
| fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> { |
| Self::from_arg_matches(matches) |
| } |
| |
| /// Assign values from `ArgMatches` to `self`. |
| fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>; |
| |
| /// Assign values from `ArgMatches` to `self`. |
| fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> { |
| self.update_from_arg_matches(matches) |
| } |
| } |
| |
| /// Parse a set of arguments into a user-defined container. |
| /// |
| /// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`. |
| /// with: |
| /// - `#[command(flatten)] args: ChildArgs`: Attribute can only be used with struct fields that impl |
| /// `Args`. |
| /// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`. |
| /// |
| /// See the [derive reference](crate::_derive) for attributes and best practices. |
| /// |
| /// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] |
| /// |
| /// # Example |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```")] |
| /// #[derive(clap::Parser)] |
| /// struct Args { |
| /// #[command(flatten)] |
| /// logging: LogArgs, |
| /// } |
| /// |
| /// #[derive(clap::Args)] |
| /// struct LogArgs { |
| /// #[arg(long, short = 'v', action = clap::ArgAction::Count)] |
| /// verbose: u8, |
| /// } |
| /// ``` |
| pub trait Args: FromArgMatches + Sized { |
| /// Report the [`ArgGroup::id`][crate::ArgGroup::id] for this set of arguments |
| fn group_id() -> Option<crate::Id> { |
| None |
| } |
| /// Append to [`Command`] so it can instantiate `Self`. |
| /// |
| /// See also [`CommandFactory`]. |
| fn augment_args(cmd: Command) -> Command; |
| /// Append to [`Command`] so it can update `self`. |
| /// |
| /// This is used to implement `#[command(flatten)]` |
| /// |
| /// See also [`CommandFactory`]. |
| fn augment_args_for_update(cmd: Command) -> Command; |
| } |
| |
| /// Parse a sub-command into a user-defined enum. |
| /// |
| /// Implementing this trait lets a parent container delegate subcommand behavior to `Self`. |
| /// with: |
| /// - `#[command(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum |
| /// variants that impl `Subcommand`. |
| /// - `#[command(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl |
| /// `Subcommand`. |
| /// |
| /// See the [derive reference](crate::_derive) for attributes and best practices. |
| /// |
| /// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] |
| /// |
| /// # Example |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```")] |
| /// #[derive(clap::Parser)] |
| /// struct Args { |
| /// #[command(subcommand)] |
| /// action: Action, |
| /// } |
| /// |
| /// #[derive(clap::Subcommand)] |
| /// enum Action { |
| /// Add, |
| /// Remove, |
| /// } |
| /// ``` |
| pub trait Subcommand: FromArgMatches + Sized { |
| /// Append to [`Command`] so it can instantiate `Self`. |
| /// |
| /// See also [`CommandFactory`]. |
| fn augment_subcommands(cmd: Command) -> Command; |
| /// Append to [`Command`] so it can update `self`. |
| /// |
| /// This is used to implement `#[command(flatten)]` |
| /// |
| /// See also [`CommandFactory`]. |
| fn augment_subcommands_for_update(cmd: Command) -> Command; |
| /// Test whether `Self` can parse a specific subcommand |
| fn has_subcommand(name: &str) -> bool; |
| } |
| |
| /// Parse arguments into enums. |
| /// |
| /// When deriving [`Parser`], a field whose type implements `ValueEnum` can have the attribute |
| /// `#[arg(value_enum)]` which will |
| /// - Call [`EnumValueParser`][crate::builder::EnumValueParser] |
| /// - Allowing using the `#[arg(default_value_t)]` attribute without implementing `Display`. |
| /// |
| /// See the [derive reference](crate::_derive) for attributes and best practices. |
| /// |
| /// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] |
| /// |
| /// # Example |
| /// |
| #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] |
| #[cfg_attr(feature = "derive", doc = " ```")] |
| /// #[derive(clap::Parser)] |
| /// struct Args { |
| /// #[arg(value_enum)] |
| /// level: Level, |
| /// } |
| /// |
| /// #[derive(clap::ValueEnum, Clone)] |
| /// enum Level { |
| /// Debug, |
| /// Info, |
| /// Warning, |
| /// Error, |
| /// } |
| /// ``` |
| pub trait ValueEnum: Sized + Clone { |
| /// All possible argument values, in display order. |
| fn value_variants<'a>() -> &'a [Self]; |
| |
| /// Parse an argument into `Self`. |
| fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> { |
| Self::value_variants() |
| .iter() |
| .find(|v| { |
| v.to_possible_value() |
| .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value") |
| .matches(input, ignore_case) |
| }) |
| .cloned() |
| .ok_or_else(|| format!("invalid variant: {input}")) |
| } |
| |
| /// The canonical argument value. |
| /// |
| /// The value is `None` for skipped variants. |
| fn to_possible_value(&self) -> Option<PossibleValue>; |
| } |
| |
| impl<T: Parser> Parser for Box<T> { |
| fn parse() -> Self { |
| Box::new(<T as Parser>::parse()) |
| } |
| |
| fn try_parse() -> Result<Self, Error> { |
| <T as Parser>::try_parse().map(Box::new) |
| } |
| |
| fn parse_from<I, It>(itr: I) -> Self |
| where |
| I: IntoIterator<Item = It>, |
| It: Into<OsString> + Clone, |
| { |
| Box::new(<T as Parser>::parse_from(itr)) |
| } |
| |
| fn try_parse_from<I, It>(itr: I) -> Result<Self, Error> |
| where |
| I: IntoIterator<Item = It>, |
| It: Into<OsString> + Clone, |
| { |
| <T as Parser>::try_parse_from(itr).map(Box::new) |
| } |
| } |
| |
| impl<T: CommandFactory> CommandFactory for Box<T> { |
| fn command<'help>() -> Command { |
| <T as CommandFactory>::command() |
| } |
| fn command_for_update<'help>() -> Command { |
| <T as CommandFactory>::command_for_update() |
| } |
| } |
| |
| impl<T: FromArgMatches> FromArgMatches for Box<T> { |
| fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> { |
| <T as FromArgMatches>::from_arg_matches(matches).map(Box::new) |
| } |
| fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> { |
| <T as FromArgMatches>::from_arg_matches_mut(matches).map(Box::new) |
| } |
| fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> { |
| <T as FromArgMatches>::update_from_arg_matches(self, matches) |
| } |
| fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> { |
| <T as FromArgMatches>::update_from_arg_matches_mut(self, matches) |
| } |
| } |
| |
| impl<T: Args> Args for Box<T> { |
| fn augment_args(cmd: Command) -> Command { |
| <T as Args>::augment_args(cmd) |
| } |
| fn augment_args_for_update(cmd: Command) -> Command { |
| <T as Args>::augment_args_for_update(cmd) |
| } |
| } |
| |
| impl<T: Subcommand> Subcommand for Box<T> { |
| fn augment_subcommands(cmd: Command) -> Command { |
| <T as Subcommand>::augment_subcommands(cmd) |
| } |
| fn augment_subcommands_for_update(cmd: Command) -> Command { |
| <T as Subcommand>::augment_subcommands_for_update(cmd) |
| } |
| fn has_subcommand(name: &str) -> bool { |
| <T as Subcommand>::has_subcommand(name) |
| } |
| } |
| |
| fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error { |
| let mut cmd = I::command(); |
| err.format(&mut cmd) |
| } |