//! This module contains traits that are usable with the `#[derive(...)].` //! macros in [`clap_derive`]. use crate::{App, ArgMatches, Error}; use std::ffi::OsString; /// The primary one-stop-shop trait used to create an instance of a `clap` /// [`App`], 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`] + /// [`IntoApp`] 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). /// /// # Examples /// /// The following example creates a `Context` struct that would be used /// throughout the application representing the normalized values coming from /// the CLI. /// /// ```rust /// # use clap::{Clap}; /// /// My super CLI /// #[derive(Clap)] /// #[clap(name = "demo")] /// struct Context { /// /// More verbose output /// #[clap(long)] /// verbose: bool, /// /// An optional name /// #[clap(short, long)] /// name: Option, /// } /// ``` /// /// The equivalent [`App`] struct + `From` implementation: /// /// ```rust /// # use clap::{App, Arg, ArgMatches}; /// App::new("demo") /// .about("My super CLI") /// .arg(Arg::new("verbose") /// .long("verbose") /// .about("More verbose output")) /// .arg(Arg::new("name") /// .long("name") /// .short('n') /// .about("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 Clap: FromArgMatches + IntoApp + Sized { /// Parse from `std::env::args_os()`, exit on error fn parse() -> Self { let matches = ::into_app().get_matches(); ::from_arg_matches(&matches) } /// Parse from `std::env::args_os()`, return Err on error. fn try_parse() -> Result { let matches = ::into_app().try_get_matches()?; Ok(::from_arg_matches(&matches)) } /// Parse from iterator, exit on error fn parse_from(itr: I) -> Self where I: IntoIterator, // TODO (@CreepySkeleton): discover a way to avoid cloning here T: Into + Clone, { let matches = ::into_app().get_matches_from(itr); ::from_arg_matches(&matches) } /// Parse from iterator, return Err on error. fn try_parse_from(itr: I) -> Result where I: IntoIterator, // TODO (@CreepySkeleton): discover a way to avoid cloning here T: Into + Clone, { let matches = ::into_app().try_get_matches_from(itr)?; Ok(::from_arg_matches(&matches)) } /// Update from iterator, exit on error fn update_from(&mut self, itr: I) where I: IntoIterator, // TODO (@CreepySkeleton): discover a way to avoid cloning here T: Into + Clone, { // TODO find a way to get partial matches let matches = ::into_app_for_update().get_matches_from(itr); ::update_from_arg_matches(self, &matches); } /// Update from iterator, return Err on error. fn try_update_from(&mut self, itr: I) -> Result<(), Error> where I: IntoIterator, // TODO (@CreepySkeleton): discover a way to avoid cloning here T: Into + Clone, { let matches = ::into_app_for_update().try_get_matches_from(itr)?; ::update_from_arg_matches(self, &matches); Ok(()) } } /// Build an App according to the struct /// /// Also serves for flattening pub trait IntoApp: Sized { /// @TODO @release @docs fn into_app<'help>() -> App<'help>; /// @TODO @release @docs fn augment_clap(app: App<'_>) -> App<'_>; /// @TODO @release @docs fn into_app_for_update<'help>() -> App<'help>; /// @TODO @release @docs fn augment_clap_for_update(app: App<'_>) -> App<'_>; } /// Converts an instance of [`ArgMatches`] to a consumer defined struct. /// pub trait FromArgMatches: Sized { /// It's common to have an "application context" struct (sometimes called /// config) that represents all the normalized values after being processed by /// the CLI. /// /// For instance, if an application we made had two CLI options, `--name /// ` and a flag `--debug` to distinguish "debugging mode" for our made /// up CLI, we may create a context struct as follows: /// /// ```no_run /// struct Context { /// name: String, /// debug: bool /// } /// ``` /// /// And after letting `clap` parse the CLI, we get back and instance of /// `ArgMatches`, we may create a `From` implementation like so: /// /// ```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) -> Self; /// @TODO@ @release @docs fn update_from_arg_matches(&mut self, matches: &ArgMatches); } /// @TODO @release @docs pub trait Subcommand: Sized { /// @TODO @release @docs fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option; /// @TODO @release @docs fn update_from_subcommand(&mut self, subcommand: Option<(&str, &ArgMatches)>); /// @TODO @release @docs fn augment_subcommands(app: App<'_>) -> App<'_>; /// @TODO @release @docs fn augment_subcommands_for_update(app: App<'_>) -> App<'_>; } /// @TODO @release @docs pub trait ArgEnum: Sized { /// @TODO @release @docs const VARIANTS: &'static [&'static str]; /// @TODO @release @docs fn from_str(input: &str, case_insensitive: bool) -> Result; } impl Clap 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, // TODO (@CreepySkeleton): discover a way to avoid cloning here It: Into + Clone, { Box::new(::parse_from(itr)) } fn try_parse_from(itr: I) -> Result where I: IntoIterator, // TODO (@CreepySkeleton): discover a way to avoid cloning here It: Into + Clone, { ::try_parse_from(itr).map(Box::new) } } impl IntoApp for Box { fn into_app<'help>() -> App<'help> { ::into_app() } fn augment_clap(app: App<'_>) -> App<'_> { ::augment_clap(app) } fn into_app_for_update<'help>() -> App<'help> { ::into_app_for_update() } fn augment_clap_for_update(app: App<'_>) -> App<'_> { ::augment_clap_for_update(app) } } impl FromArgMatches for Box { fn from_arg_matches(matches: &ArgMatches) -> Self { Box::new(::from_arg_matches(matches)) } fn update_from_arg_matches(&mut self, matches: &ArgMatches) { ::update_from_arg_matches(self, matches); } } impl Subcommand for Box { fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option { ::from_subcommand(subcommand).map(Box::new) } fn update_from_subcommand(&mut self, subcommand: Option<(&str, &ArgMatches)>) { ::update_from_subcommand(self, subcommand); } fn augment_subcommands(app: App<'_>) -> App<'_> { ::augment_subcommands(app) } fn augment_subcommands_for_update(app: App<'_>) -> App<'_> { ::augment_subcommands_for_update(app) } }