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