clap_builder/builder/
action.rs

1#[cfg(debug_assertions)]
2use crate::util::AnyValueId;
3
4/// Behavior of arguments when they are encountered while parsing
5///
6/// # Examples
7///
8/// ```rust
9/// # #[cfg(feature = "help")] {
10/// # use clap_builder as clap;
11/// # use clap::Command;
12/// # use clap::Arg;
13/// let cmd = Command::new("mycmd")
14///     .arg(
15///         Arg::new("special-help")
16///             .short('?')
17///             .action(clap::ArgAction::Help)
18///     );
19///
20/// // Existing help still exists
21/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
22/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
23///
24/// // New help available
25/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
26/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
27/// # }
28/// ```
29#[derive(Clone, Debug)]
30#[non_exhaustive]
31#[allow(missing_copy_implementations)] // In the future, we may accept `Box<dyn ...>`
32pub enum ArgAction {
33    /// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
34    ///
35    /// <div class="warning">
36    ///
37    /// **NOTE:** If the argument has previously been seen, it will result in a
38    /// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
39    /// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
40    ///
41    /// </div>
42    ///
43    /// # Examples
44    ///
45    /// ```rust
46    /// # use clap_builder as clap;
47    /// # use clap::Command;
48    /// # use clap::Arg;
49    /// let cmd = Command::new("mycmd")
50    ///     .arg(
51    ///         Arg::new("flag")
52    ///             .long("flag")
53    ///             .action(clap::ArgAction::Set)
54    ///     );
55    ///
56    /// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value"]).unwrap();
57    /// assert!(matches.contains_id("flag"));
58    /// assert_eq!(
59    ///     matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
60    ///     vec!["value"]
61    /// );
62    /// ```
63    Set,
64    /// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
65    ///
66    /// # Examples
67    ///
68    /// ```rust
69    /// # use clap_builder as clap;
70    /// # use clap::Command;
71    /// # use clap::Arg;
72    /// let cmd = Command::new("mycmd")
73    ///     .arg(
74    ///         Arg::new("flag")
75    ///             .long("flag")
76    ///             .action(clap::ArgAction::Append)
77    ///     );
78    ///
79    /// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value1", "--flag", "value2"]).unwrap();
80    /// assert!(matches.contains_id("flag"));
81    /// assert_eq!(
82    ///     matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
83    ///     vec!["value1", "value2"]
84    /// );
85    /// ```
86    Append,
87    /// When encountered, act as if `"true"` was encountered on the command-line
88    ///
89    /// If no [`default_value`][super::Arg::default_value] is set, it will be `false`.
90    ///
91    /// No value is allowed. To optionally accept a value, see
92    /// [`Arg::default_missing_value`][super::Arg::default_missing_value]
93    ///
94    /// <div class="warning">
95    ///
96    /// **NOTE:** If the argument has previously been seen, it will result in a
97    /// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
98    /// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
99    ///
100    /// </div>
101    ///
102    /// # Examples
103    ///
104    /// ```rust
105    /// # use clap_builder as clap;
106    /// # use clap::Command;
107    /// # use clap::Arg;
108    /// let cmd = Command::new("mycmd")
109    ///     .arg(
110    ///         Arg::new("flag")
111    ///             .long("flag")
112    ///             .action(clap::ArgAction::SetTrue)
113    ///     );
114    ///
115    /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
116    /// assert!(matches.contains_id("flag"));
117    /// assert_eq!(
118    ///     matches.get_flag("flag"),
119    ///     true
120    /// );
121    ///
122    /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
123    /// assert!(matches.contains_id("flag"));
124    /// assert_eq!(
125    ///     matches.get_flag("flag"),
126    ///     false
127    /// );
128    /// ```
129    ///
130    /// You can use [`TypedValueParser::map`][crate::builder::TypedValueParser::map] to have the
131    /// flag control an application-specific type:
132    /// ```rust
133    /// # use clap_builder as clap;
134    /// # use clap::Command;
135    /// # use clap::Arg;
136    /// # use clap::builder::TypedValueParser as _;
137    /// # use clap::builder::BoolishValueParser;
138    /// let cmd = Command::new("mycmd")
139    ///     .arg(
140    ///         Arg::new("flag")
141    ///             .long("flag")
142    ///             .action(clap::ArgAction::SetTrue)
143    ///             .value_parser(
144    ///                 BoolishValueParser::new()
145    ///                 .map(|b| -> usize {
146    ///                     if b { 10 } else { 5 }
147    ///                 })
148    ///             )
149    ///     );
150    ///
151    /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
152    /// assert!(matches.contains_id("flag"));
153    /// assert_eq!(
154    ///     matches.get_one::<usize>("flag").copied(),
155    ///     Some(10)
156    /// );
157    ///
158    /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
159    /// assert!(matches.contains_id("flag"));
160    /// assert_eq!(
161    ///     matches.get_one::<usize>("flag").copied(),
162    ///     Some(5)
163    /// );
164    /// ```
165    SetTrue,
166    /// When encountered, act as if `"false"` was encountered on the command-line
167    ///
168    /// If no [`default_value`][super::Arg::default_value] is set, it will be `true`.
169    ///
170    /// No value is allowed. To optionally accept a value, see
171    /// [`Arg::default_missing_value`][super::Arg::default_missing_value]
172    ///
173    /// <div class="warning">
174    ///
175    /// **NOTE:** If the argument has previously been seen, it will result in a
176    /// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
177    /// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
178    ///
179    /// </div>
180    ///
181    /// # Examples
182    ///
183    /// ```rust
184    /// # use clap_builder as clap;
185    /// # use clap::Command;
186    /// # use clap::Arg;
187    /// let cmd = Command::new("mycmd")
188    ///     .arg(
189    ///         Arg::new("flag")
190    ///             .long("flag")
191    ///             .action(clap::ArgAction::SetFalse)
192    ///     );
193    ///
194    /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
195    /// assert!(matches.contains_id("flag"));
196    /// assert_eq!(
197    ///     matches.get_flag("flag"),
198    ///     false
199    /// );
200    ///
201    /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
202    /// assert!(matches.contains_id("flag"));
203    /// assert_eq!(
204    ///     matches.get_flag("flag"),
205    ///     true
206    /// );
207    /// ```
208    SetFalse,
209    /// When encountered, increment a `u8` counter starting from `0`.
210    ///
211    /// If no [`default_value`][super::Arg::default_value] is set, it will be `0`.
212    ///
213    /// No value is allowed. To optionally accept a value, see
214    /// [`Arg::default_missing_value`][super::Arg::default_missing_value]
215    ///
216    /// # Examples
217    ///
218    /// ```rust
219    /// # use clap_builder as clap;
220    /// # use clap::Command;
221    /// # use clap::Arg;
222    /// let cmd = Command::new("mycmd")
223    ///     .arg(
224    ///         Arg::new("flag")
225    ///             .long("flag")
226    ///             .action(clap::ArgAction::Count)
227    ///     );
228    ///
229    /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
230    /// assert!(matches.contains_id("flag"));
231    /// assert_eq!(
232    ///     matches.get_count("flag"),
233    ///     2
234    /// );
235    ///
236    /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
237    /// assert!(matches.contains_id("flag"));
238    /// assert_eq!(
239    ///     matches.get_count("flag"),
240    ///     0
241    /// );
242    /// ```
243    Count,
244    /// When encountered, display [`Command::print_help`][super::Command::print_help]
245    ///
246    /// Depending on the flag, [`Command::print_long_help`][super::Command::print_long_help] may be shown
247    ///
248    /// # Examples
249    ///
250    /// ```rust
251    /// # #[cfg(feature = "help")] {
252    /// # use clap_builder as clap;
253    /// # use clap::Command;
254    /// # use clap::Arg;
255    /// let cmd = Command::new("mycmd")
256    ///     .arg(
257    ///         Arg::new("special-help")
258    ///             .short('?')
259    ///             .action(clap::ArgAction::Help)
260    ///     );
261    ///
262    /// // Existing help still exists
263    /// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
264    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
265    ///
266    /// // New help available
267    /// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
268    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
269    /// # }
270    /// ```
271    Help,
272    /// When encountered, display [`Command::print_help`][super::Command::print_help]
273    ///
274    /// # Examples
275    ///
276    /// ```rust
277    /// # #[cfg(feature = "help")] {
278    /// # use clap_builder as clap;
279    /// # use clap::Command;
280    /// # use clap::Arg;
281    /// let cmd = Command::new("mycmd")
282    ///     .arg(
283    ///         Arg::new("special-help")
284    ///             .short('?')
285    ///             .action(clap::ArgAction::HelpShort)
286    ///     );
287    ///
288    /// // Existing help still exists
289    /// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
290    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
291    ///
292    /// // New help available
293    /// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
294    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
295    /// # }
296    /// ```
297    HelpShort,
298    /// When encountered, display [`Command::print_long_help`][super::Command::print_long_help]
299    ///
300    /// # Examples
301    ///
302    /// ```rust
303    /// # #[cfg(feature = "help")] {
304    /// # use clap_builder as clap;
305    /// # use clap::Command;
306    /// # use clap::Arg;
307    /// let cmd = Command::new("mycmd")
308    ///     .arg(
309    ///         Arg::new("special-help")
310    ///             .short('?')
311    ///             .action(clap::ArgAction::HelpLong)
312    ///     );
313    ///
314    /// // Existing help still exists
315    /// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
316    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
317    ///
318    /// // New help available
319    /// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
320    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
321    /// # }
322    /// ```
323    HelpLong,
324    /// When encountered, display [`Command::version`][super::Command::version]
325    ///
326    /// Depending on the flag, [`Command::long_version`][super::Command::long_version] may be shown
327    ///
328    /// # Examples
329    ///
330    /// ```rust
331    /// # use clap_builder as clap;
332    /// # use clap::Command;
333    /// # use clap::Arg;
334    /// let cmd = Command::new("mycmd")
335    ///     .version("1.0.0")
336    ///     .arg(
337    ///         Arg::new("special-version")
338    ///             .long("special-version")
339    ///             .action(clap::ArgAction::Version)
340    ///     );
341    ///
342    /// // Existing help still exists
343    /// let err = cmd.clone().try_get_matches_from(["mycmd", "--version"]).unwrap_err();
344    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
345    ///
346    /// // New help available
347    /// let err = cmd.try_get_matches_from(["mycmd", "--special-version"]).unwrap_err();
348    /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
349    /// ```
350    Version,
351}
352
353impl ArgAction {
354    /// Returns whether this action accepts values on the command-line
355    ///
356    /// [`default_values`][super::Arg::default_values] and [`env`][super::Arg::env] may still be
357    /// processed.
358    pub fn takes_values(&self) -> bool {
359        match self {
360            Self::Set => true,
361            Self::Append => true,
362            Self::SetTrue => false,
363            Self::SetFalse => false,
364            Self::Count => false,
365            Self::Help => false,
366            Self::HelpShort => false,
367            Self::HelpLong => false,
368            Self::Version => false,
369        }
370    }
371
372    pub(crate) fn default_value(&self) -> Option<&'static std::ffi::OsStr> {
373        match self {
374            Self::Set => None,
375            Self::Append => None,
376            Self::SetTrue => Some(std::ffi::OsStr::new("false")),
377            Self::SetFalse => Some(std::ffi::OsStr::new("true")),
378            Self::Count => Some(std::ffi::OsStr::new("0")),
379            Self::Help => None,
380            Self::HelpShort => None,
381            Self::HelpLong => None,
382            Self::Version => None,
383        }
384    }
385
386    pub(crate) fn default_missing_value(&self) -> Option<&'static std::ffi::OsStr> {
387        match self {
388            Self::Set => None,
389            Self::Append => None,
390            Self::SetTrue => Some(std::ffi::OsStr::new("true")),
391            Self::SetFalse => Some(std::ffi::OsStr::new("false")),
392            Self::Count => None,
393            Self::Help => None,
394            Self::HelpShort => None,
395            Self::HelpLong => None,
396            Self::Version => None,
397        }
398    }
399
400    pub(crate) fn default_value_parser(&self) -> Option<super::ValueParser> {
401        match self {
402            Self::Set => None,
403            Self::Append => None,
404            Self::SetTrue => Some(super::ValueParser::bool()),
405            Self::SetFalse => Some(super::ValueParser::bool()),
406            Self::Count => Some(crate::value_parser!(u8).into()),
407            Self::Help => None,
408            Self::HelpShort => None,
409            Self::HelpLong => None,
410            Self::Version => None,
411        }
412    }
413
414    #[cfg(debug_assertions)]
415    pub(crate) fn value_type_id(&self) -> Option<AnyValueId> {
416        match self {
417            Self::Set => None,
418            Self::Append => None,
419            Self::SetTrue => None,
420            Self::SetFalse => None,
421            Self::Count => Some(AnyValueId::of::<CountType>()),
422            Self::Help => None,
423            Self::HelpShort => None,
424            Self::HelpLong => None,
425            Self::Version => None,
426        }
427    }
428}
429
430pub(crate) type CountType = u8;