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