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