• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ...>`
27 pub 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 
275 impl 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.
takes_values(&self) -> bool280     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 
default_value(&self) -> Option<&'static std::ffi::OsStr>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 
default_missing_value(&self) -> Option<&'static std::ffi::OsStr>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 
default_value_parser(&self) -> Option<super::ValueParser>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)]
value_type_id(&self) -> Option<crate::parser::AnyValueId>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 
344 pub(crate) type CountType = u8;
345