//! This module contains traits that are usable with the `#[derive(...)].` //! macros in [`clap_derive`]. use crate::{ArgMatches, Command, Error, PossibleValue}; 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](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md) /// for attributes and best practices. /// /// **NOTE:** Deriving requires the `derive` feature flag /// /// # 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)] /// #[clap(name = "demo")] /// struct Context { /// /// More verbose output /// #[clap(long)] /// verbose: bool, /// /// An optional name /// #[clap(short, long)] /// name: Option, /// } /// ``` /// /// The equivalent [`Command`] struct + `From` implementation: /// /// ```rust /// # use clap::{Command, Arg, ArgMatches}; /// Command::new("demo") /// .about("My super CLI") /// .arg(Arg::new("verbose") /// .long("verbose") /// .help("More verbose output")) /// .arg(Arg::new("name") /// .long("name") /// .short('n') /// .help("An optional name") /// .takes_value(true)); /// /// struct Context { /// verbose: bool, /// name: Option, /// } /// /// impl From for Context { /// fn from(m: ArgMatches) -> Self { /// Context { /// verbose: m.is_present("verbose"), /// name: m.value_of("name").map(|n| n.to_owned()), /// } /// } /// } /// ``` /// pub trait Parser: FromArgMatches + CommandFactory + Sized { /// Parse from `std::env::args_os()`, exit on error fn parse() -> Self { let matches = ::command().get_matches(); let res = ::from_arg_matches(&matches).map_err(format_error::); 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 { let matches = ::command().try_get_matches()?; ::from_arg_matches(&matches).map_err(format_error::) } /// Parse from iterator, exit on error fn parse_from(itr: I) -> Self where I: IntoIterator, T: Into + Clone, { let matches = ::command().get_matches_from(itr); let res = ::from_arg_matches(&matches).map_err(format_error::); 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(itr: I) -> Result where I: IntoIterator, T: Into + Clone, { let matches = ::command().try_get_matches_from(itr)?; ::from_arg_matches(&matches).map_err(format_error::) } /// Update from iterator, exit on error fn update_from(&mut self, itr: I) where I: IntoIterator, T: Into + Clone, { let matches = ::command_for_update().get_matches_from(itr); let res = ::update_from_arg_matches(self, &matches) .map_err(format_error::); 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(&mut self, itr: I) -> Result<(), Error> where I: IntoIterator, T: Into + Clone, { let matches = ::command_for_update().try_get_matches_from(itr)?; ::update_from_arg_matches(self, &matches) .map_err(format_error::) } /// Deprecated, `StructOpt::clap` replaced with [`IntoCommand::command`] (derive as part of /// [`Parser`]) #[deprecated( since = "3.0.0", note = "`StructOpt::clap` is replaced with `IntoCommand::command` (derived as part of `Parser`)" )] #[doc(hidden)] fn clap<'help>() -> Command<'help> { ::command() } /// Deprecated, `StructOpt::from_clap` replaced with [`FromArgMatches::from_arg_matches`] (derive as part of /// [`Parser`]) #[deprecated( since = "3.0.0", note = "`StructOpt::from_clap` is replaced with `FromArgMatches::from_arg_matches` (derived as part of `Parser`)" )] #[doc(hidden)] fn from_clap(matches: &ArgMatches) -> Self { ::from_arg_matches(matches).unwrap() } /// Deprecated, `StructOpt::from_args` replaced with `Parser::parse` (note the change in derives) #[deprecated( since = "3.0.0", note = "`StructOpt::from_args` is replaced with `Parser::parse` (note the change in derives)" )] #[doc(hidden)] fn from_args() -> Self { Self::parse() } /// Deprecated, `StructOpt::from_args_safe` replaced with `Parser::try_parse` (note the change in derives) #[deprecated( since = "3.0.0", note = "`StructOpt::from_args_safe` is replaced with `Parser::try_parse` (note the change in derives)" )] #[doc(hidden)] fn from_args_safe() -> Result { Self::try_parse() } /// Deprecated, `StructOpt::from_iter` replaced with `Parser::parse_from` (note the change in derives) #[deprecated( since = "3.0.0", note = "`StructOpt::from_iter` is replaced with `Parser::parse_from` (note the change in derives)" )] #[doc(hidden)] fn from_iter(itr: I) -> Self where I: IntoIterator, T: Into + Clone, { Self::parse_from(itr) } /// Deprecated, `StructOpt::from_iter_safe` replaced with `Parser::try_parse_from` (note the /// change in derives) #[deprecated( since = "3.0.0", note = "`StructOpt::from_iter_safe` is replaced with `Parser::try_parse_from` (note the change in derives)" )] #[doc(hidden)] fn from_iter_safe(itr: I) -> Result where I: IntoIterator, T: Into + Clone, { Self::try_parse_from(itr) } } /// 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`] for instantiating `Self`. fn command<'help>() -> Command<'help> { #[allow(deprecated)] Self::into_app() } /// Deprecated, replaced with `CommandFactory::command` #[deprecated(since = "3.1.0", note = "Replaced with `CommandFactory::command")] fn into_app<'help>() -> Command<'help>; /// Build a [`Command`] that can update `self`. /// /// See [`FromArgMatches::update_from_arg_matches`] for updating `self`. fn command_for_update<'help>() -> Command<'help> { #[allow(deprecated)] Self::into_app_for_update() } /// Deprecated, replaced with `CommandFactory::command_for_update` #[deprecated( since = "3.1.0", note = "Replaced with `CommandFactory::command_for_update" )] fn into_app_for_update<'help>() -> Command<'help>; } /// 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 /// ` 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 for Context { /// fn from(m: ArgMatches) -> Self { /// Context { /// name: m.value_of("name").unwrap().to_string(), /// debug: m.is_present("debug"), /// } /// } /// } /// ``` fn from_arg_matches(matches: &ArgMatches) -> Result; /// Assign values from `ArgMatches` to `self`. fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>; } /// Parse a set of arguments into a user-defined container. /// /// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`. /// with: /// - `#[clap(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](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md) /// for attributes and best practices. /// /// **NOTE:** Deriving requires the `derive` feature flag /// /// # Example /// #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] #[cfg_attr(feature = "derive", doc = " ```")] /// #[derive(clap::Parser)] /// struct Args { /// #[clap(flatten)] /// logging: LogArgs, /// } /// /// #[derive(clap::Args)] /// struct LogArgs { /// #[clap(long, short = 'v', parse(from_occurrences))] /// verbose: i8, /// } /// ``` pub trait Args: FromArgMatches + Sized { /// 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 `#[clap(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: /// - `#[clap(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum /// variants that impl `Subcommand`. /// - `#[clap(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl /// `Subcommand`. /// /// See the /// [derive reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md) /// for attributes and best practices. /// /// **NOTE:** Deriving requires the `derive` feature flag /// /// # Example /// #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] #[cfg_attr(feature = "derive", doc = " ```")] /// #[derive(clap::Parser)] /// struct Args { /// #[clap(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 `#[clap(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 `ArgEnum` can have the attribute /// `#[clap(arg_enum)]` which will /// - Call [`Arg::possible_values`][crate::Arg::possible_values] /// - Allowing using the `#[clap(default_value_t)]` attribute without implementing `Display`. /// /// See the /// [derive reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md) /// for attributes and best practices. /// /// **NOTE:** Deriving requires the `derive` feature flag /// /// # Example /// #[cfg_attr(not(feature = "derive"), doc = " ```ignore")] #[cfg_attr(feature = "derive", doc = " ```")] /// #[derive(clap::Parser)] /// struct Args { /// #[clap(arg_enum)] /// level: Level, /// } /// /// #[derive(clap::ArgEnum, Clone)] /// enum Level { /// Debug, /// Info, /// Warning, /// Error, /// } /// ``` pub trait ArgEnum: 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::value_variants() .iter() .find(|v| { v.to_possible_value() .expect("ArgEnum::value_variants contains only values with a corresponding ArgEnum::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<'a>(&self) -> Option>; } impl Parser for Box { fn parse() -> Self { Box::new(::parse()) } fn try_parse() -> Result { ::try_parse().map(Box::new) } fn parse_from(itr: I) -> Self where I: IntoIterator, It: Into + Clone, { Box::new(::parse_from(itr)) } fn try_parse_from(itr: I) -> Result where I: IntoIterator, It: Into + Clone, { ::try_parse_from(itr).map(Box::new) } } #[allow(deprecated)] impl CommandFactory for Box { fn into_app<'help>() -> Command<'help> { ::into_app() } fn into_app_for_update<'help>() -> Command<'help> { ::into_app_for_update() } } impl FromArgMatches for Box { fn from_arg_matches(matches: &ArgMatches) -> Result { ::from_arg_matches(matches).map(Box::new) } fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> { ::update_from_arg_matches(self, matches) } } impl Args for Box { fn augment_args(cmd: Command<'_>) -> Command<'_> { ::augment_args(cmd) } fn augment_args_for_update(cmd: Command<'_>) -> Command<'_> { ::augment_args_for_update(cmd) } } impl Subcommand for Box { fn augment_subcommands(cmd: Command<'_>) -> Command<'_> { ::augment_subcommands(cmd) } fn augment_subcommands_for_update(cmd: Command<'_>) -> Command<'_> { ::augment_subcommands_for_update(cmd) } fn has_subcommand(name: &str) -> bool { ::has_subcommand(name) } } fn format_error(err: crate::Error) -> crate::Error { let mut cmd = I::command(); err.format(&mut cmd) }