blob: 98bb0121b6eb6c2bebc12a9efd5068c19ef064a6 [file] [log] [blame]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +02001//! This module contains traits that are usable with the `#[derive(...)].`
2//! macros in [`clap_derive`].
3
Andrew Walbran6b927442022-11-30 12:13:59 +00004use crate::builder::PossibleValue;
5use crate::{ArgMatches, Command, Error};
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +02006
7use std::ffi::OsString;
8
9/// Parse command-line arguments into `Self`.
10///
11/// The primary one-stop-shop trait used to create an instance of a `clap`
12/// [`Command`], conduct the parsing, and turn the resulting [`ArgMatches`] back
13/// into concrete instance of the user struct.
14///
15/// This trait is primarily a convenience on top of [`FromArgMatches`] +
16/// [`CommandFactory`] which uses those two underlying traits to build the two
17/// fundamental functions `parse` which uses the `std::env::args_os` iterator,
18/// and `parse_from` which allows the consumer to supply the iterator (along
19/// with fallible options for each).
20///
21/// See also [`Subcommand`] and [`Args`].
22///
23/// See the [derive reference](crate::_derive) for attributes and best practices.
24///
25/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
26///
27/// # Examples
28///
29/// The following example creates a `Context` struct that would be used
30/// throughout the application representing the normalized values coming from
31/// the CLI.
32///
33#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
34#[cfg_attr(feature = "derive", doc = " ```")]
35/// /// My super CLI
36/// #[derive(clap::Parser)]
Andrew Walbran6b927442022-11-30 12:13:59 +000037/// #[command(name = "demo")]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +020038/// struct Context {
39/// /// More verbose output
Andrew Walbran6b927442022-11-30 12:13:59 +000040/// #[arg(long)]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +020041/// verbose: bool,
42/// /// An optional name
Andrew Walbran6b927442022-11-30 12:13:59 +000043/// #[arg(short, long)]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +020044/// name: Option<String>,
45/// }
46/// ```
47///
48/// The equivalent [`Command`] struct + `From` implementation:
49///
50/// ```rust
51/// # use clap::{Command, Arg, ArgMatches, ArgAction};
52/// Command::new("demo")
53/// .about("My super CLI")
54/// .arg(Arg::new("verbose")
55/// .long("verbose")
56/// .action(ArgAction::SetTrue)
57/// .help("More verbose output"))
58/// .arg(Arg::new("name")
59/// .long("name")
60/// .short('n')
61/// .help("An optional name")
Andrew Walbran6b927442022-11-30 12:13:59 +000062/// .action(ArgAction::Set));
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +020063///
64/// struct Context {
65/// verbose: bool,
66/// name: Option<String>,
67/// }
68///
69/// impl From<ArgMatches> for Context {
70/// fn from(m: ArgMatches) -> Self {
71/// Context {
Jeff Vander Stoepf0f58372023-03-02 19:06:38 +010072/// verbose: m.get_flag("verbose"),
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +020073/// name: m.get_one::<String>("name").cloned(),
74/// }
75/// }
76/// }
77/// ```
78///
79pub trait Parser: FromArgMatches + CommandFactory + Sized {
80 /// Parse from `std::env::args_os()`, exit on error
81 fn parse() -> Self {
82 let mut matches = <Self as CommandFactory>::command().get_matches();
83 let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
84 .map_err(format_error::<Self>);
85 match res {
86 Ok(s) => s,
87 Err(e) => {
88 // Since this is more of a development-time error, we aren't doing as fancy of a quit
89 // as `get_matches`
90 e.exit()
91 }
92 }
93 }
94
95 /// Parse from `std::env::args_os()`, return Err on error.
96 fn try_parse() -> Result<Self, Error> {
Andrew Walbran6b927442022-11-30 12:13:59 +000097 let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches());
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +020098 <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
99 }
100
101 /// Parse from iterator, exit on error
102 fn parse_from<I, T>(itr: I) -> Self
103 where
104 I: IntoIterator<Item = T>,
105 T: Into<OsString> + Clone,
106 {
107 let mut matches = <Self as CommandFactory>::command().get_matches_from(itr);
108 let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
109 .map_err(format_error::<Self>);
110 match res {
111 Ok(s) => s,
112 Err(e) => {
113 // Since this is more of a development-time error, we aren't doing as fancy of a quit
114 // as `get_matches_from`
115 e.exit()
116 }
117 }
118 }
119
120 /// Parse from iterator, return Err on error.
121 fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
122 where
123 I: IntoIterator<Item = T>,
124 T: Into<OsString> + Clone,
125 {
Andrew Walbran6b927442022-11-30 12:13:59 +0000126 let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches_from(itr));
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200127 <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
128 }
129
130 /// Update from iterator, exit on error
131 fn update_from<I, T>(&mut self, itr: I)
132 where
133 I: IntoIterator<Item = T>,
134 T: Into<OsString> + Clone,
135 {
136 let mut matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr);
137 let res = <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
138 .map_err(format_error::<Self>);
139 if let Err(e) = res {
140 // Since this is more of a development-time error, we aren't doing as fancy of a quit
141 // as `get_matches_from`
142 e.exit()
143 }
144 }
145
146 /// Update from iterator, return Err on error.
147 fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
148 where
149 I: IntoIterator<Item = T>,
150 T: Into<OsString> + Clone,
151 {
152 let mut matches =
Andrew Walbran6b927442022-11-30 12:13:59 +0000153 ok!(<Self as CommandFactory>::command_for_update().try_get_matches_from(itr));
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200154 <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
155 .map_err(format_error::<Self>)
156 }
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200157}
158
159/// Create a [`Command`] relevant for a user-defined container.
160///
161/// Derived as part of [`Parser`].
162pub trait CommandFactory: Sized {
163 /// Build a [`Command`] that can instantiate `Self`.
164 ///
165 /// See [`FromArgMatches::from_arg_matches_mut`] for instantiating `Self`.
Andrew Walbran6b927442022-11-30 12:13:59 +0000166 fn command() -> Command;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200167 /// Build a [`Command`] that can update `self`.
168 ///
169 /// See [`FromArgMatches::update_from_arg_matches_mut`] for updating `self`.
Andrew Walbran6b927442022-11-30 12:13:59 +0000170 fn command_for_update() -> Command;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200171}
172
173/// Converts an instance of [`ArgMatches`] to a user-defined container.
174///
175/// Derived as part of [`Parser`], [`Args`], and [`Subcommand`].
176pub trait FromArgMatches: Sized {
177 /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
178 ///
179 /// Motivation: If our application had two CLI options, `--name
180 /// <STRING>` and the flag `--debug`, we may create a struct as follows:
181 ///
182 #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
183 #[cfg_attr(feature = "derive", doc = " ```no_run")]
184 /// struct Context {
185 /// name: String,
186 /// debug: bool
187 /// }
188 /// ```
189 ///
190 /// We then need to convert the `ArgMatches` that `clap` generated into our struct.
191 /// `from_arg_matches` serves as the equivalent of:
192 ///
193 #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
194 #[cfg_attr(feature = "derive", doc = " ```no_run")]
195 /// # use clap::ArgMatches;
196 /// # struct Context {
197 /// # name: String,
198 /// # debug: bool
199 /// # }
200 /// impl From<ArgMatches> for Context {
201 /// fn from(m: ArgMatches) -> Self {
202 /// Context {
203 /// name: m.get_one::<String>("name").unwrap().clone(),
Jeff Vander Stoepf0f58372023-03-02 19:06:38 +0100204 /// debug: m.get_flag("debug"),
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200205 /// }
206 /// }
207 /// }
208 /// ```
209 fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error>;
210
211 /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
212 ///
213 /// Motivation: If our application had two CLI options, `--name
214 /// <STRING>` and the flag `--debug`, we may create a struct as follows:
215 ///
216 #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
217 #[cfg_attr(feature = "derive", doc = " ```no_run")]
218 /// struct Context {
219 /// name: String,
220 /// debug: bool
221 /// }
222 /// ```
223 ///
224 /// We then need to convert the `ArgMatches` that `clap` generated into our struct.
225 /// `from_arg_matches_mut` serves as the equivalent of:
226 ///
227 #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
228 #[cfg_attr(feature = "derive", doc = " ```no_run")]
229 /// # use clap::ArgMatches;
230 /// # struct Context {
231 /// # name: String,
232 /// # debug: bool
233 /// # }
234 /// impl From<ArgMatches> for Context {
235 /// fn from(m: ArgMatches) -> Self {
236 /// Context {
237 /// name: m.get_one::<String>("name").unwrap().to_string(),
Jeff Vander Stoepf0f58372023-03-02 19:06:38 +0100238 /// debug: m.get_flag("debug"),
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200239 /// }
240 /// }
241 /// }
242 /// ```
243 fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
244 Self::from_arg_matches(matches)
245 }
246
247 /// Assign values from `ArgMatches` to `self`.
248 fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>;
249
250 /// Assign values from `ArgMatches` to `self`.
251 fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
252 self.update_from_arg_matches(matches)
253 }
254}
255
256/// Parse a set of arguments into a user-defined container.
257///
258/// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`.
259/// with:
Andrew Walbran6b927442022-11-30 12:13:59 +0000260/// - `#[command(flatten)] args: ChildArgs`: Attribute can only be used with struct fields that impl
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200261/// `Args`.
262/// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`.
263///
264/// See the [derive reference](crate::_derive) for attributes and best practices.
265///
266/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
267///
268/// # Example
269///
270#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
271#[cfg_attr(feature = "derive", doc = " ```")]
272/// #[derive(clap::Parser)]
273/// struct Args {
Andrew Walbran6b927442022-11-30 12:13:59 +0000274/// #[command(flatten)]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200275/// logging: LogArgs,
276/// }
277///
278/// #[derive(clap::Args)]
279/// struct LogArgs {
Andrew Walbran6b927442022-11-30 12:13:59 +0000280/// #[arg(long, short = 'v', action = clap::ArgAction::Count)]
Jeff Vander Stoepf0f58372023-03-02 19:06:38 +0100281/// verbose: u8,
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200282/// }
283/// ```
284pub trait Args: FromArgMatches + Sized {
Andrew Walbran6b927442022-11-30 12:13:59 +0000285 /// Report the [`ArgGroup::id`][crate::ArgGroup::id] for this set of arguments
286 fn group_id() -> Option<crate::Id> {
287 None
288 }
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200289 /// Append to [`Command`] so it can instantiate `Self`.
290 ///
291 /// See also [`CommandFactory`].
Andrew Walbran6b927442022-11-30 12:13:59 +0000292 fn augment_args(cmd: Command) -> Command;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200293 /// Append to [`Command`] so it can update `self`.
294 ///
Andrew Walbran6b927442022-11-30 12:13:59 +0000295 /// This is used to implement `#[command(flatten)]`
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200296 ///
297 /// See also [`CommandFactory`].
Andrew Walbran6b927442022-11-30 12:13:59 +0000298 fn augment_args_for_update(cmd: Command) -> Command;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200299}
300
301/// Parse a sub-command into a user-defined enum.
302///
303/// Implementing this trait lets a parent container delegate subcommand behavior to `Self`.
304/// with:
Andrew Walbran6b927442022-11-30 12:13:59 +0000305/// - `#[command(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200306/// variants that impl `Subcommand`.
Andrew Walbran6b927442022-11-30 12:13:59 +0000307/// - `#[command(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200308/// `Subcommand`.
309///
310/// See the [derive reference](crate::_derive) for attributes and best practices.
311///
312/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
313///
314/// # Example
315///
316#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
317#[cfg_attr(feature = "derive", doc = " ```")]
318/// #[derive(clap::Parser)]
319/// struct Args {
Andrew Walbran6b927442022-11-30 12:13:59 +0000320/// #[command(subcommand)]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200321/// action: Action,
322/// }
323///
324/// #[derive(clap::Subcommand)]
325/// enum Action {
326/// Add,
327/// Remove,
328/// }
329/// ```
330pub trait Subcommand: FromArgMatches + Sized {
331 /// Append to [`Command`] so it can instantiate `Self`.
332 ///
333 /// See also [`CommandFactory`].
Andrew Walbran6b927442022-11-30 12:13:59 +0000334 fn augment_subcommands(cmd: Command) -> Command;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200335 /// Append to [`Command`] so it can update `self`.
336 ///
Andrew Walbran6b927442022-11-30 12:13:59 +0000337 /// This is used to implement `#[command(flatten)]`
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200338 ///
339 /// See also [`CommandFactory`].
Andrew Walbran6b927442022-11-30 12:13:59 +0000340 fn augment_subcommands_for_update(cmd: Command) -> Command;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200341 /// Test whether `Self` can parse a specific subcommand
342 fn has_subcommand(name: &str) -> bool;
343}
344
345/// Parse arguments into enums.
346///
347/// When deriving [`Parser`], a field whose type implements `ValueEnum` can have the attribute
Andrew Walbran6b927442022-11-30 12:13:59 +0000348/// `#[arg(value_enum)]` which will
349/// - Call [`EnumValueParser`][crate::builder::EnumValueParser]
350/// - Allowing using the `#[arg(default_value_t)]` attribute without implementing `Display`.
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200351///
352/// See the [derive reference](crate::_derive) for attributes and best practices.
353///
354/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
355///
356/// # Example
357///
358#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
359#[cfg_attr(feature = "derive", doc = " ```")]
360/// #[derive(clap::Parser)]
361/// struct Args {
Andrew Walbran6b927442022-11-30 12:13:59 +0000362/// #[arg(value_enum)]
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200363/// level: Level,
364/// }
365///
366/// #[derive(clap::ValueEnum, Clone)]
367/// enum Level {
368/// Debug,
369/// Info,
370/// Warning,
371/// Error,
372/// }
373/// ```
374pub trait ValueEnum: Sized + Clone {
375 /// All possible argument values, in display order.
376 fn value_variants<'a>() -> &'a [Self];
377
378 /// Parse an argument into `Self`.
379 fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
380 Self::value_variants()
381 .iter()
382 .find(|v| {
383 v.to_possible_value()
384 .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value")
385 .matches(input, ignore_case)
386 })
387 .cloned()
Jeff Vander Stoepf0f58372023-03-02 19:06:38 +0100388 .ok_or_else(|| format!("invalid variant: {input}"))
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200389 }
390
391 /// The canonical argument value.
392 ///
393 /// The value is `None` for skipped variants.
Andrew Walbran6b927442022-11-30 12:13:59 +0000394 fn to_possible_value(&self) -> Option<PossibleValue>;
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200395}
396
397impl<T: Parser> Parser for Box<T> {
398 fn parse() -> Self {
399 Box::new(<T as Parser>::parse())
400 }
401
402 fn try_parse() -> Result<Self, Error> {
403 <T as Parser>::try_parse().map(Box::new)
404 }
405
406 fn parse_from<I, It>(itr: I) -> Self
407 where
408 I: IntoIterator<Item = It>,
409 It: Into<OsString> + Clone,
410 {
411 Box::new(<T as Parser>::parse_from(itr))
412 }
413
414 fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
415 where
416 I: IntoIterator<Item = It>,
417 It: Into<OsString> + Clone,
418 {
419 <T as Parser>::try_parse_from(itr).map(Box::new)
420 }
421}
422
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200423impl<T: CommandFactory> CommandFactory for Box<T> {
Andrew Walbran6b927442022-11-30 12:13:59 +0000424 fn command<'help>() -> Command {
425 <T as CommandFactory>::command()
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200426 }
Andrew Walbran6b927442022-11-30 12:13:59 +0000427 fn command_for_update<'help>() -> Command {
428 <T as CommandFactory>::command_for_update()
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200429 }
430}
431
432impl<T: FromArgMatches> FromArgMatches for Box<T> {
433 fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
434 <T as FromArgMatches>::from_arg_matches(matches).map(Box::new)
435 }
436 fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
437 <T as FromArgMatches>::from_arg_matches_mut(matches).map(Box::new)
438 }
439 fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
440 <T as FromArgMatches>::update_from_arg_matches(self, matches)
441 }
442 fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
443 <T as FromArgMatches>::update_from_arg_matches_mut(self, matches)
444 }
445}
446
447impl<T: Args> Args for Box<T> {
Andrew Walbran6b927442022-11-30 12:13:59 +0000448 fn augment_args(cmd: Command) -> Command {
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200449 <T as Args>::augment_args(cmd)
450 }
Andrew Walbran6b927442022-11-30 12:13:59 +0000451 fn augment_args_for_update(cmd: Command) -> Command {
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200452 <T as Args>::augment_args_for_update(cmd)
453 }
454}
455
456impl<T: Subcommand> Subcommand for Box<T> {
Andrew Walbran6b927442022-11-30 12:13:59 +0000457 fn augment_subcommands(cmd: Command) -> Command {
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200458 <T as Subcommand>::augment_subcommands(cmd)
459 }
Andrew Walbran6b927442022-11-30 12:13:59 +0000460 fn augment_subcommands_for_update(cmd: Command) -> Command {
Jeff Vander Stoepa5cb0c82022-07-28 04:45:32 +0200461 <T as Subcommand>::augment_subcommands_for_update(cmd)
462 }
463 fn has_subcommand(name: &str) -> bool {
464 <T as Subcommand>::has_subcommand(name)
465 }
466}
467
468fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error {
469 let mut cmd = I::command();
470 err.format(&mut cmd)
471}