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