1 #[cfg(debug_assertions)]
2 use 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 ...>`
32 pub 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
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 
341 impl 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.
takes_values(&self) -> bool346     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 
default_value(&self) -> Option<&'static std::ffi::OsStr>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 
default_missing_value(&self) -> Option<&'static std::ffi::OsStr>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 
default_value_parser(&self) -> Option<super::ValueParser>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)]
value_type_id(&self) -> Option<AnyValueId>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 
418 pub(crate) type CountType = u8;
419