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