]>
Commit | Line | Data |
---|---|---|
04454e1e FG |
1 | // Std |
2 | use std::{ | |
3 | borrow::Cow, | |
4 | ffi::{OsStr, OsString}, | |
5 | fmt::{Debug, Display}, | |
6 | iter::{Cloned, Flatten, Map}, | |
7 | slice::Iter, | |
8 | str::FromStr, | |
9 | }; | |
10 | ||
11 | // Third Party | |
12 | use indexmap::IndexMap; | |
13 | ||
14 | // Internal | |
15 | use crate::parse::MatchedArg; | |
16 | use crate::parse::ValueSource; | |
17 | use crate::util::{Id, Key}; | |
18 | use crate::{Error, INVALID_UTF8}; | |
19 | ||
20 | /// Container for parse results. | |
21 | /// | |
22 | /// Used to get information about the arguments that were supplied to the program at runtime by | |
23 | /// the user. New instances of this struct are obtained by using the [`Command::get_matches`] family of | |
24 | /// methods. | |
25 | /// | |
26 | /// # Examples | |
27 | /// | |
28 | /// ```no_run | |
29 | /// # use clap::{Command, Arg}; | |
30 | /// let matches = Command::new("MyApp") | |
31 | /// .arg(Arg::new("out") | |
32 | /// .long("output") | |
33 | /// .required(true) | |
34 | /// .takes_value(true)) | |
35 | /// .arg(Arg::new("debug") | |
36 | /// .short('d') | |
37 | /// .multiple_occurrences(true)) | |
38 | /// .arg(Arg::new("cfg") | |
39 | /// .short('c') | |
40 | /// .takes_value(true)) | |
41 | /// .get_matches(); // builds the instance of ArgMatches | |
42 | /// | |
43 | /// // to get information about the "cfg" argument we created, such as the value supplied we use | |
44 | /// // various ArgMatches methods, such as ArgMatches::value_of | |
45 | /// if let Some(c) = matches.value_of("cfg") { | |
46 | /// println!("Value for -c: {}", c); | |
47 | /// } | |
48 | /// | |
49 | /// // The ArgMatches::value_of method returns an Option because the user may not have supplied | |
50 | /// // that argument at runtime. But if we specified that the argument was "required" as we did | |
51 | /// // with the "out" argument, we can safely unwrap because `clap` verifies that was actually | |
52 | /// // used at runtime. | |
53 | /// println!("Value for --output: {}", matches.value_of("out").unwrap()); | |
54 | /// | |
55 | /// // You can check the presence of an argument | |
56 | /// if matches.is_present("out") { | |
57 | /// // Another way to check if an argument was present, or if it occurred multiple times is to | |
58 | /// // use occurrences_of() which returns 0 if an argument isn't found at runtime, or the | |
59 | /// // number of times that it occurred, if it was. To allow an argument to appear more than | |
60 | /// // once, you must use the .multiple_occurrences(true) method, otherwise it will only return 1 or 0. | |
61 | /// if matches.occurrences_of("debug") > 2 { | |
62 | /// println!("Debug mode is REALLY on, don't be crazy"); | |
63 | /// } else { | |
64 | /// println!("Debug mode kind of on"); | |
65 | /// } | |
66 | /// } | |
67 | /// ``` | |
68 | /// [`Command::get_matches`]: crate::Command::get_matches() | |
69 | #[derive(Debug, Clone, Default, PartialEq, Eq)] | |
70 | pub struct ArgMatches { | |
71 | #[cfg(debug_assertions)] | |
72 | pub(crate) valid_args: Vec<Id>, | |
73 | #[cfg(debug_assertions)] | |
74 | pub(crate) valid_subcommands: Vec<Id>, | |
75 | #[cfg(debug_assertions)] | |
76 | pub(crate) disable_asserts: bool, | |
77 | pub(crate) args: IndexMap<Id, MatchedArg>, | |
78 | pub(crate) subcommand: Option<Box<SubCommand>>, | |
79 | } | |
80 | ||
81 | impl ArgMatches { | |
82 | /// Check if any args were present on the command line | |
83 | /// | |
84 | /// # Examples | |
85 | /// | |
86 | /// ```rust | |
87 | /// # use clap::{Command, Arg}; | |
88 | /// let mut cmd = Command::new("myapp") | |
89 | /// .arg(Arg::new("output") | |
90 | /// .takes_value(true)); | |
91 | /// | |
92 | /// let m = cmd | |
93 | /// .try_get_matches_from_mut(vec!["myapp", "something"]) | |
94 | /// .unwrap(); | |
95 | /// assert!(m.args_present()); | |
96 | /// | |
97 | /// let m = cmd | |
98 | /// .try_get_matches_from_mut(vec!["myapp"]) | |
99 | /// .unwrap(); | |
100 | /// assert!(! m.args_present()); | |
101 | pub fn args_present(&self) -> bool { | |
102 | !self.args.is_empty() | |
103 | } | |
104 | ||
105 | /// Gets the value of a specific option or positional argument. | |
106 | /// | |
107 | /// i.e. an argument that [takes an additional value][crate::Arg::takes_value] at runtime. | |
108 | /// | |
109 | /// Returns `None` if the option wasn't present. | |
110 | /// | |
111 | /// *NOTE:* Prefer [`ArgMatches::values_of`] if getting a value for an option or positional | |
112 | /// argument that allows multiples as `ArgMatches::value_of` will only return the *first* | |
113 | /// value. | |
114 | /// | |
115 | /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set. | |
116 | /// [`occurrences_of`] can be used to check if a value is present at runtime. | |
117 | /// | |
118 | /// # Panics | |
119 | /// | |
120 | /// If the value is invalid UTF-8. See | |
121 | /// [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
122 | /// | |
123 | /// If `id` is is not a valid argument or group name. | |
124 | /// | |
125 | /// # Examples | |
126 | /// | |
127 | /// ```rust | |
128 | /// # use clap::{Command, Arg}; | |
129 | /// let m = Command::new("myapp") | |
130 | /// .arg(Arg::new("output") | |
131 | /// .takes_value(true)) | |
132 | /// .get_matches_from(vec!["myapp", "something"]); | |
133 | /// | |
134 | /// assert_eq!(m.value_of("output"), Some("something")); | |
135 | /// ``` | |
136 | /// [option]: crate::Arg::takes_value() | |
137 | /// [positional]: crate::Arg::index() | |
138 | /// [`ArgMatches::values_of`]: ArgMatches::values_of() | |
139 | /// [`default_value`]: crate::Arg::default_value() | |
140 | /// [`occurrences_of`]: crate::ArgMatches::occurrences_of() | |
141 | #[cfg_attr(debug_assertions, track_caller)] | |
142 | pub fn value_of<T: Key>(&self, id: T) -> Option<&str> { | |
143 | let id = Id::from(id); | |
144 | let arg = self.get_arg(&id)?; | |
145 | assert_utf8_validation(arg, &id); | |
146 | let v = arg.first()?; | |
147 | Some(v.to_str().expect(INVALID_UTF8)) | |
148 | } | |
149 | ||
150 | /// Gets the lossy value of a specific option or positional argument. | |
151 | /// | |
152 | /// i.e. an argument that [takes an additional value][crate::Arg::takes_value] at runtime. | |
153 | /// | |
154 | /// A lossy value is one which contains invalid UTF-8, those invalid points will be replaced | |
155 | /// with `\u{FFFD}` | |
156 | /// | |
157 | /// Returns `None` if the option wasn't present. | |
158 | /// | |
159 | /// *NOTE:* Recommend having set [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
160 | /// | |
161 | /// *NOTE:* Prefer [`ArgMatches::values_of_lossy`] if getting a value for an option or positional | |
162 | /// argument that allows multiples as `ArgMatches::value_of_lossy` will only return the *first* | |
163 | /// value. | |
164 | /// | |
165 | /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set. | |
166 | /// [`occurrences_of`] can be used to check if a value is present at runtime. | |
167 | /// | |
168 | /// # Panics | |
169 | /// | |
170 | /// If `id` is is not a valid argument or group name. | |
171 | /// | |
172 | /// # Examples | |
173 | /// | |
174 | #[cfg_attr(not(unix), doc = " ```ignore")] | |
175 | #[cfg_attr(unix, doc = " ```")] | |
176 | /// # use clap::{Command, arg}; | |
177 | /// use std::ffi::OsString; | |
178 | /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; | |
179 | /// | |
180 | /// let m = Command::new("utf8") | |
181 | /// .arg(arg!(<arg> "some arg") | |
182 | /// .allow_invalid_utf8(true)) | |
183 | /// .get_matches_from(vec![OsString::from("myprog"), | |
184 | /// // "Hi {0xe9}!" | |
185 | /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); | |
186 | /// assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!"); | |
187 | /// ``` | |
188 | /// [`default_value`]: crate::Arg::default_value() | |
189 | /// [`occurrences_of`]: ArgMatches::occurrences_of() | |
190 | /// [`Arg::values_of_lossy`]: ArgMatches::values_of_lossy() | |
191 | #[cfg_attr(debug_assertions, track_caller)] | |
192 | pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> { | |
193 | let id = Id::from(id); | |
194 | let arg = self.get_arg(&id)?; | |
195 | assert_no_utf8_validation(arg, &id); | |
196 | let v = arg.first()?; | |
197 | Some(v.to_string_lossy()) | |
198 | } | |
199 | ||
200 | /// Get the `OsStr` value of a specific option or positional argument. | |
201 | /// | |
202 | /// i.e. an argument that [takes an additional value][crate::Arg::takes_value] at runtime. | |
203 | /// | |
204 | /// An `OsStr` on Unix-like systems is any series of bytes, regardless of whether or not they | |
205 | /// contain valid UTF-8. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid | |
206 | /// filename on a Unix system as an argument value may contain invalid UTF-8. | |
207 | /// | |
208 | /// Returns `None` if the option wasn't present. | |
209 | /// | |
210 | /// *NOTE:* Recommend having set [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
211 | /// | |
212 | /// *NOTE:* Prefer [`ArgMatches::values_of_os`] if getting a value for an option or positional | |
213 | /// argument that allows multiples as `ArgMatches::value_of_os` will only return the *first* | |
214 | /// value. | |
215 | /// | |
216 | /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set. | |
217 | /// [`occurrences_of`] can be used to check if a value is present at runtime. | |
218 | /// | |
219 | /// # Panics | |
220 | /// | |
221 | /// If `id` is is not a valid argument or group name. | |
222 | /// | |
223 | /// # Examples | |
224 | /// | |
225 | #[cfg_attr(not(unix), doc = " ```ignore")] | |
226 | #[cfg_attr(unix, doc = " ```")] | |
227 | /// # use clap::{Command, arg}; | |
228 | /// use std::ffi::OsString; | |
229 | /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; | |
230 | /// | |
231 | /// let m = Command::new("utf8") | |
232 | /// .arg(arg!(<arg> "some arg") | |
233 | /// .allow_invalid_utf8(true)) | |
234 | /// .get_matches_from(vec![OsString::from("myprog"), | |
235 | /// // "Hi {0xe9}!" | |
236 | /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); | |
237 | /// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']); | |
238 | /// ``` | |
239 | /// [`default_value`]: crate::Arg::default_value() | |
240 | /// [`occurrences_of`]: ArgMatches::occurrences_of() | |
241 | /// [`ArgMatches::values_of_os`]: ArgMatches::values_of_os() | |
242 | #[cfg_attr(debug_assertions, track_caller)] | |
243 | pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> { | |
244 | let id = Id::from(id); | |
245 | let arg = self.get_arg(&id)?; | |
246 | assert_no_utf8_validation(arg, &id); | |
247 | let v = arg.first()?; | |
248 | Some(v.as_os_str()) | |
249 | } | |
250 | ||
251 | /// Get an [`Iterator`] over [values] of a specific option or positional argument. | |
252 | /// | |
253 | /// i.e. an argument that takes multiple values at runtime. | |
254 | /// | |
255 | /// Returns `None` if the option wasn't present. | |
256 | /// | |
257 | /// # Panics | |
258 | /// | |
259 | /// If the value is invalid UTF-8. See | |
260 | /// [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
261 | /// | |
262 | /// If `id` is is not a valid argument or group name. | |
263 | /// | |
264 | /// # Examples | |
265 | /// | |
266 | /// ```rust | |
267 | /// # use clap::{Command, Arg}; | |
268 | /// let m = Command::new("myprog") | |
269 | /// .arg(Arg::new("output") | |
270 | /// .multiple_occurrences(true) | |
271 | /// .short('o') | |
272 | /// .takes_value(true)) | |
273 | /// .get_matches_from(vec![ | |
274 | /// "myprog", "-o", "val1", "-o", "val2", "-o", "val3" | |
275 | /// ]); | |
276 | /// let vals: Vec<&str> = m.values_of("output").unwrap().collect(); | |
277 | /// assert_eq!(vals, ["val1", "val2", "val3"]); | |
278 | /// ``` | |
279 | /// [values]: Values | |
280 | /// [`Iterator`]: std::iter::Iterator | |
281 | #[cfg_attr(debug_assertions, track_caller)] | |
282 | pub fn values_of<T: Key>(&self, id: T) -> Option<Values> { | |
283 | let id = Id::from(id); | |
284 | let arg = self.get_arg(&id)?; | |
285 | assert_utf8_validation(arg, &id); | |
286 | fn to_str_slice(o: &OsString) -> &str { | |
287 | o.to_str().expect(INVALID_UTF8) | |
288 | } | |
289 | let v = Values { | |
290 | iter: arg.vals_flatten().map(to_str_slice), | |
291 | len: arg.num_vals(), | |
292 | }; | |
293 | Some(v) | |
294 | } | |
295 | ||
296 | /// Placeholder documentation. | |
297 | #[cfg(feature = "unstable-grouped")] | |
298 | #[cfg_attr(debug_assertions, track_caller)] | |
299 | pub fn grouped_values_of<T: Key>(&self, id: T) -> Option<GroupedValues> { | |
300 | let id = Id::from(id); | |
301 | let arg = self.get_arg(&id)?; | |
302 | assert_utf8_validation(arg, &id); | |
303 | let v = GroupedValues { | |
304 | iter: arg | |
305 | .vals() | |
306 | .map(|g| g.iter().map(|x| x.to_str().expect(INVALID_UTF8)).collect()), | |
307 | len: arg.vals().len(), | |
308 | }; | |
309 | Some(v) | |
310 | } | |
311 | ||
312 | /// Get the lossy values of a specific option or positional argument. | |
313 | /// | |
314 | /// i.e. an argument that takes multiple values at runtime. | |
315 | /// | |
316 | /// A lossy value is one which contains invalid UTF-8, those invalid points will be replaced | |
317 | /// with `\u{FFFD}` | |
318 | /// | |
319 | /// Returns `None` if the option wasn't present. | |
320 | /// | |
321 | /// *NOTE:* Recommend having set [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
322 | /// | |
323 | /// # Panics | |
324 | /// | |
325 | /// If `id` is is not a valid argument or group name. | |
326 | /// | |
327 | /// # Examples | |
328 | /// | |
329 | #[cfg_attr(not(unix), doc = " ```ignore")] | |
330 | #[cfg_attr(unix, doc = " ```")] | |
331 | /// # use clap::{Command, arg}; | |
332 | /// use std::ffi::OsString; | |
333 | /// use std::os::unix::ffi::OsStringExt; | |
334 | /// | |
335 | /// let m = Command::new("utf8") | |
336 | /// .arg(arg!(<arg> ... "some arg") | |
337 | /// .allow_invalid_utf8(true)) | |
338 | /// .get_matches_from(vec![OsString::from("myprog"), | |
339 | /// // "Hi" | |
340 | /// OsString::from_vec(vec![b'H', b'i']), | |
341 | /// // "{0xe9}!" | |
342 | /// OsString::from_vec(vec![0xe9, b'!'])]); | |
343 | /// let mut itr = m.values_of_lossy("arg").unwrap().into_iter(); | |
344 | /// assert_eq!(&itr.next().unwrap()[..], "Hi"); | |
345 | /// assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!"); | |
346 | /// assert_eq!(itr.next(), None); | |
347 | /// ``` | |
348 | #[cfg_attr(debug_assertions, track_caller)] | |
349 | pub fn values_of_lossy<T: Key>(&self, id: T) -> Option<Vec<String>> { | |
350 | let id = Id::from(id); | |
351 | let arg = self.get_arg(&id)?; | |
352 | assert_no_utf8_validation(arg, &id); | |
353 | let v = arg | |
354 | .vals_flatten() | |
355 | .map(|v| v.to_string_lossy().into_owned()) | |
356 | .collect(); | |
357 | Some(v) | |
358 | } | |
359 | ||
360 | /// Get an [`Iterator`] over [`OsStr`] [values] of a specific option or positional argument. | |
361 | /// | |
362 | /// i.e. an argument that takes multiple values at runtime. | |
363 | /// | |
364 | /// An `OsStr` on Unix-like systems is any series of bytes, regardless of whether or not they | |
365 | /// contain valid UTF-8. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid | |
366 | /// filename on a Unix system as an argument value may contain invalid UTF-8. | |
367 | /// | |
368 | /// Returns `None` if the option wasn't present. | |
369 | /// | |
370 | /// *NOTE:* Recommend having set [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
371 | /// | |
372 | /// # Panics | |
373 | /// | |
374 | /// If `id` is is not a valid argument or group name. | |
375 | /// | |
376 | /// # Examples | |
377 | /// | |
378 | #[cfg_attr(not(unix), doc = " ```ignore")] | |
379 | #[cfg_attr(unix, doc = " ```")] | |
380 | /// # use clap::{Command, arg}; | |
381 | /// use std::ffi::{OsStr,OsString}; | |
382 | /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; | |
383 | /// | |
384 | /// let m = Command::new("utf8") | |
385 | /// .arg(arg!(<arg> ... "some arg") | |
386 | /// .allow_invalid_utf8(true)) | |
387 | /// .get_matches_from(vec![OsString::from("myprog"), | |
388 | /// // "Hi" | |
389 | /// OsString::from_vec(vec![b'H', b'i']), | |
390 | /// // "{0xe9}!" | |
391 | /// OsString::from_vec(vec![0xe9, b'!'])]); | |
392 | /// | |
393 | /// let mut itr = m.values_of_os("arg").unwrap().into_iter(); | |
394 | /// assert_eq!(itr.next(), Some(OsStr::new("Hi"))); | |
395 | /// assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!']))); | |
396 | /// assert_eq!(itr.next(), None); | |
397 | /// ``` | |
398 | /// [`Iterator`]: std::iter::Iterator | |
399 | /// [`OsSt`]: std::ffi::OsStr | |
400 | /// [values]: OsValues | |
401 | /// [`String`]: std::string::String | |
402 | #[cfg_attr(debug_assertions, track_caller)] | |
403 | pub fn values_of_os<T: Key>(&self, id: T) -> Option<OsValues> { | |
404 | let id = Id::from(id); | |
405 | let arg = self.get_arg(&id)?; | |
406 | assert_no_utf8_validation(arg, &id); | |
407 | fn to_str_slice(o: &OsString) -> &OsStr { | |
408 | o | |
409 | } | |
410 | let v = OsValues { | |
411 | iter: arg.vals_flatten().map(to_str_slice), | |
412 | len: arg.num_vals(), | |
413 | }; | |
414 | Some(v) | |
415 | } | |
416 | ||
417 | /// Parse the value (with [`FromStr`]) of a specific option or positional argument. | |
418 | /// | |
419 | /// There are two types of errors, parse failures and those where the argument wasn't present | |
420 | /// (such as a non-required argument). Check [`ErrorKind`] to distinguish them. | |
421 | /// | |
422 | /// *NOTE:* If getting a value for an option or positional argument that allows multiples, | |
423 | /// prefer [`ArgMatches::values_of_t`] as this method will only return the *first* | |
424 | /// value. | |
425 | /// | |
426 | /// # Panics | |
427 | /// | |
428 | /// If the value is invalid UTF-8. See | |
429 | /// [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
430 | /// | |
431 | /// If `id` is is not a valid argument or group name. | |
432 | /// | |
433 | /// # Examples | |
434 | /// | |
435 | /// ``` | |
436 | /// # use clap::{Command, arg}; | |
437 | /// let matches = Command::new("myapp") | |
438 | /// .arg(arg!([length] "Set the length to use as a pos whole num i.e. 20")) | |
439 | /// .get_matches_from(&["test", "12"]); | |
440 | /// | |
441 | /// // Specify the type explicitly (or use turbofish) | |
442 | /// let len: u32 = matches.value_of_t("length").unwrap_or_else(|e| e.exit()); | |
443 | /// assert_eq!(len, 12); | |
444 | /// | |
445 | /// // You can often leave the type for rustc to figure out | |
446 | /// let also_len = matches.value_of_t("length").unwrap_or_else(|e| e.exit()); | |
447 | /// // Something that expects u32 | |
448 | /// let _: u32 = also_len; | |
449 | /// ``` | |
450 | /// | |
451 | /// [`FromStr]: std::str::FromStr | |
452 | /// [`ArgMatches::values_of_t`]: ArgMatches::values_of_t() | |
453 | /// [`ErrorKind`]: crate::ErrorKind | |
454 | pub fn value_of_t<R>(&self, name: &str) -> Result<R, Error> | |
455 | where | |
456 | R: FromStr, | |
457 | <R as FromStr>::Err: Display, | |
458 | { | |
459 | let v = self | |
460 | .value_of(name) | |
461 | .ok_or_else(|| Error::argument_not_found_auto(name.to_string()))?; | |
462 | v.parse::<R>().map_err(|e| { | |
463 | let message = format!( | |
464 | "The argument '{}' isn't a valid value for '{}': {}", | |
465 | v, name, e | |
466 | ); | |
467 | ||
468 | Error::value_validation(name.to_string(), v.to_string(), message.into()) | |
469 | }) | |
470 | } | |
471 | ||
472 | /// Parse the value (with [`FromStr`]) of a specific option or positional argument. | |
473 | /// | |
474 | /// If either the value is not present or parsing failed, exits the program. | |
475 | /// | |
476 | /// # Panics | |
477 | /// | |
478 | /// If the value is invalid UTF-8. See | |
479 | /// [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
480 | /// | |
481 | /// If `id` is is not a valid argument or group name. | |
482 | /// | |
483 | /// # Examples | |
484 | /// | |
485 | /// ``` | |
486 | /// # use clap::{Command, arg}; | |
487 | /// let matches = Command::new("myapp") | |
488 | /// .arg(arg!([length] "Set the length to use as a pos whole num i.e. 20")) | |
489 | /// .get_matches_from(&["test", "12"]); | |
490 | /// | |
491 | /// // Specify the type explicitly (or use turbofish) | |
492 | /// let len: u32 = matches.value_of_t_or_exit("length"); | |
493 | /// assert_eq!(len, 12); | |
494 | /// | |
495 | /// // You can often leave the type for rustc to figure out | |
496 | /// let also_len = matches.value_of_t_or_exit("length"); | |
497 | /// // Something that expects u32 | |
498 | /// let _: u32 = also_len; | |
499 | /// ``` | |
500 | /// | |
501 | /// [`FromStr][std::str::FromStr] | |
502 | pub fn value_of_t_or_exit<R>(&self, name: &str) -> R | |
503 | where | |
504 | R: FromStr, | |
505 | <R as FromStr>::Err: Display, | |
506 | { | |
507 | self.value_of_t(name).unwrap_or_else(|e| e.exit()) | |
508 | } | |
509 | ||
510 | /// Parse the values (with [`FromStr`]) of a specific option or positional argument. | |
511 | /// | |
512 | /// There are two types of errors, parse failures and those where the argument wasn't present | |
513 | /// (such as a non-required argument). Check [`ErrorKind`] to distinguish them. | |
514 | /// | |
515 | /// *NOTE:* If getting a value for an option or positional argument that allows multiples, | |
516 | /// prefer [`ArgMatches::values_of_t`] as this method will only return the *first* | |
517 | /// value. | |
518 | /// | |
519 | /// # Panics | |
520 | /// | |
521 | /// If the value is invalid UTF-8. See | |
522 | /// [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
523 | /// | |
524 | /// If `id` is is not a valid argument or group name. | |
525 | /// | |
526 | /// # Examples | |
527 | /// | |
528 | /// ``` | |
529 | /// # use clap::{Command, arg}; | |
530 | /// let matches = Command::new("myapp") | |
531 | /// .arg(arg!([length] ... "A sequence of integers because integers are neat!")) | |
532 | /// .get_matches_from(&["test", "12", "77", "40"]); | |
533 | /// | |
534 | /// // Specify the type explicitly (or use turbofish) | |
535 | /// let len: Vec<u32> = matches.values_of_t("length").unwrap_or_else(|e| e.exit()); | |
536 | /// assert_eq!(len, vec![12, 77, 40]); | |
537 | /// | |
538 | /// // You can often leave the type for rustc to figure out | |
539 | /// let also_len = matches.values_of_t("length").unwrap_or_else(|e| e.exit()); | |
540 | /// // Something that expects Vec<u32> | |
541 | /// let _: Vec<u32> = also_len; | |
542 | /// ``` | |
543 | /// [`ErrorKind`]: crate::ErrorKind | |
544 | pub fn values_of_t<R>(&self, name: &str) -> Result<Vec<R>, Error> | |
545 | where | |
546 | R: FromStr, | |
547 | <R as FromStr>::Err: Display, | |
548 | { | |
549 | let v = self | |
550 | .values_of(name) | |
551 | .ok_or_else(|| Error::argument_not_found_auto(name.to_string()))?; | |
552 | v.map(|v| { | |
553 | v.parse::<R>().map_err(|e| { | |
554 | let message = format!("The argument '{}' isn't a valid value: {}", v, e); | |
555 | ||
556 | Error::value_validation(name.to_string(), v.to_string(), message.into()) | |
557 | }) | |
558 | }) | |
559 | .collect() | |
560 | } | |
561 | ||
562 | /// Parse the values (with [`FromStr`]) of a specific option or positional argument. | |
563 | /// | |
564 | /// If parsing (of any value) has failed, exits the program. | |
565 | /// | |
566 | /// # Panics | |
567 | /// | |
568 | /// If the value is invalid UTF-8. See | |
569 | /// [`Arg::allow_invalid_utf8`][crate::Arg::allow_invalid_utf8]. | |
570 | /// | |
571 | /// If `id` is is not a valid argument or group name. | |
572 | /// | |
573 | /// # Examples | |
574 | /// | |
575 | /// ``` | |
576 | /// # use clap::{Command, arg}; | |
577 | /// let matches = Command::new("myapp") | |
578 | /// .arg(arg!([length] ... "A sequence of integers because integers are neat!")) | |
579 | /// .get_matches_from(&["test", "12", "77", "40"]); | |
580 | /// | |
581 | /// // Specify the type explicitly (or use turbofish) | |
582 | /// let len: Vec<u32> = matches.values_of_t_or_exit("length"); | |
583 | /// assert_eq!(len, vec![12, 77, 40]); | |
584 | /// | |
585 | /// // You can often leave the type for rustc to figure out | |
586 | /// let also_len = matches.values_of_t_or_exit("length"); | |
587 | /// // Something that expects Vec<u32> | |
588 | /// let _: Vec<u32> = also_len; | |
589 | /// ``` | |
590 | pub fn values_of_t_or_exit<R>(&self, name: &str) -> Vec<R> | |
591 | where | |
592 | R: FromStr, | |
593 | <R as FromStr>::Err: Display, | |
594 | { | |
595 | self.values_of_t(name).unwrap_or_else(|e| e.exit()) | |
596 | } | |
597 | ||
598 | /// Check if an argument was present at runtime. | |
599 | /// | |
600 | /// *NOTE:* This will always return `true` if [`default_value`] has been set. | |
601 | /// [`occurrences_of`] can be used to check if a value is present at runtime. | |
602 | /// | |
603 | /// # Panics | |
604 | /// | |
605 | /// If `id` is is not a valid argument or group name. | |
606 | /// | |
607 | /// # Examples | |
608 | /// | |
609 | /// ```rust | |
610 | /// # use clap::{Command, Arg}; | |
611 | /// let m = Command::new("myprog") | |
612 | /// .arg(Arg::new("debug") | |
613 | /// .short('d')) | |
614 | /// .get_matches_from(vec![ | |
615 | /// "myprog", "-d" | |
616 | /// ]); | |
617 | /// | |
618 | /// assert!(m.is_present("debug")); | |
619 | /// ``` | |
620 | /// | |
621 | /// [`default_value`]: crate::Arg::default_value() | |
622 | /// [`occurrences_of`]: ArgMatches::occurrences_of() | |
623 | pub fn is_present<T: Key>(&self, id: T) -> bool { | |
624 | let id = Id::from(id); | |
625 | ||
626 | #[cfg(debug_assertions)] | |
627 | self.get_arg(&id); | |
628 | ||
629 | self.args.contains_key(&id) | |
630 | } | |
631 | ||
632 | /// Report where argument value came from | |
633 | /// | |
634 | /// # Panics | |
635 | /// | |
636 | /// If `id` is is not a valid argument or group name. | |
637 | /// | |
638 | /// # Examples | |
639 | /// | |
640 | /// ```rust | |
641 | /// # use clap::{Command, Arg, ValueSource}; | |
642 | /// let m = Command::new("myprog") | |
643 | /// .arg(Arg::new("debug") | |
644 | /// .short('d')) | |
645 | /// .get_matches_from(vec![ | |
646 | /// "myprog", "-d" | |
647 | /// ]); | |
648 | /// | |
649 | /// assert_eq!(m.value_source("debug"), Some(ValueSource::CommandLine)); | |
650 | /// ``` | |
651 | /// | |
652 | /// [`default_value`]: crate::Arg::default_value() | |
653 | /// [`occurrences_of`]: ArgMatches::occurrences_of() | |
654 | pub fn value_source<T: Key>(&self, id: T) -> Option<ValueSource> { | |
655 | let id = Id::from(id); | |
656 | ||
657 | let value = self.get_arg(&id); | |
658 | ||
659 | value.and_then(MatchedArg::source) | |
660 | } | |
661 | ||
662 | /// The number of times an argument was used at runtime. | |
663 | /// | |
664 | /// If an argument isn't present it will return `0`. | |
665 | /// | |
666 | /// **NOTE:** This returns the number of times the argument was used, *not* the number of | |
667 | /// values. For example, `-o val1 val2 val3 -o val4` would return `2` (2 occurrences, but 4 | |
668 | /// values). See [Arg::multiple_occurrences][crate::Arg::multiple_occurrences]. | |
669 | /// | |
670 | /// # Panics | |
671 | /// | |
672 | /// If `id` is is not a valid argument or group name. | |
673 | /// | |
674 | /// # Examples | |
675 | /// | |
676 | /// ```rust | |
677 | /// # use clap::{Command, Arg}; | |
678 | /// let m = Command::new("myprog") | |
679 | /// .arg(Arg::new("debug") | |
680 | /// .short('d') | |
681 | /// .multiple_occurrences(true)) | |
682 | /// .get_matches_from(vec![ | |
683 | /// "myprog", "-d", "-d", "-d" | |
684 | /// ]); | |
685 | /// | |
686 | /// assert_eq!(m.occurrences_of("debug"), 3); | |
687 | /// ``` | |
688 | /// | |
689 | /// This next example shows that counts actual uses of the argument, not just `-`'s | |
690 | /// | |
691 | /// ```rust | |
692 | /// # use clap::{Command, Arg}; | |
693 | /// let m = Command::new("myprog") | |
694 | /// .arg(Arg::new("debug") | |
695 | /// .short('d') | |
696 | /// .multiple_occurrences(true)) | |
697 | /// .arg(Arg::new("flag") | |
698 | /// .short('f')) | |
699 | /// .get_matches_from(vec![ | |
700 | /// "myprog", "-ddfd" | |
701 | /// ]); | |
702 | /// | |
703 | /// assert_eq!(m.occurrences_of("debug"), 3); | |
704 | /// assert_eq!(m.occurrences_of("flag"), 1); | |
705 | /// ``` | |
706 | pub fn occurrences_of<T: Key>(&self, id: T) -> u64 { | |
707 | self.get_arg(&Id::from(id)) | |
708 | .map_or(0, |a| a.get_occurrences()) | |
709 | } | |
710 | ||
711 | /// The first index of that an argument showed up. | |
712 | /// | |
713 | /// Indices are similar to argv indices, but are not exactly 1:1. | |
714 | /// | |
715 | /// For flags (i.e. those arguments which don't have an associated value), indices refer | |
716 | /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices | |
717 | /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the | |
718 | /// index for `val` would be recorded. This is by design. | |
719 | /// | |
720 | /// Besides the flag/option discrepancy, the primary difference between an argv index and clap | |
721 | /// index, is that clap continues counting once all arguments have properly separated, whereas | |
722 | /// an argv index does not. | |
723 | /// | |
724 | /// The examples should clear this up. | |
725 | /// | |
726 | /// *NOTE:* If an argument is allowed multiple times, this method will only give the *first* | |
727 | /// index. See [`ArgMatches::indices_of`]. | |
728 | /// | |
729 | /// # Panics | |
730 | /// | |
731 | /// If `id` is is not a valid argument or group name. | |
732 | /// | |
733 | /// # Examples | |
734 | /// | |
735 | /// The argv indices are listed in the comments below. See how they correspond to the clap | |
736 | /// indices. Note that if it's not listed in a clap index, this is because it's not saved in | |
737 | /// in an `ArgMatches` struct for querying. | |
738 | /// | |
739 | /// ```rust | |
740 | /// # use clap::{Command, Arg}; | |
741 | /// let m = Command::new("myapp") | |
742 | /// .arg(Arg::new("flag") | |
743 | /// .short('f')) | |
744 | /// .arg(Arg::new("option") | |
745 | /// .short('o') | |
746 | /// .takes_value(true)) | |
747 | /// .get_matches_from(vec!["myapp", "-f", "-o", "val"]); | |
748 | /// // ARGV indices: ^0 ^1 ^2 ^3 | |
749 | /// // clap indices: ^1 ^3 | |
750 | /// | |
751 | /// assert_eq!(m.index_of("flag"), Some(1)); | |
752 | /// assert_eq!(m.index_of("option"), Some(3)); | |
753 | /// ``` | |
754 | /// | |
755 | /// Now notice, if we use one of the other styles of options: | |
756 | /// | |
757 | /// ```rust | |
758 | /// # use clap::{Command, Arg}; | |
759 | /// let m = Command::new("myapp") | |
760 | /// .arg(Arg::new("flag") | |
761 | /// .short('f')) | |
762 | /// .arg(Arg::new("option") | |
763 | /// .short('o') | |
764 | /// .takes_value(true)) | |
765 | /// .get_matches_from(vec!["myapp", "-f", "-o=val"]); | |
766 | /// // ARGV indices: ^0 ^1 ^2 | |
767 | /// // clap indices: ^1 ^3 | |
768 | /// | |
769 | /// assert_eq!(m.index_of("flag"), Some(1)); | |
770 | /// assert_eq!(m.index_of("option"), Some(3)); | |
771 | /// ``` | |
772 | /// | |
773 | /// Things become much more complicated, or clear if we look at a more complex combination of | |
774 | /// flags. Let's also throw in the final option style for good measure. | |
775 | /// | |
776 | /// ```rust | |
777 | /// # use clap::{Command, Arg}; | |
778 | /// let m = Command::new("myapp") | |
779 | /// .arg(Arg::new("flag") | |
780 | /// .short('f')) | |
781 | /// .arg(Arg::new("flag2") | |
782 | /// .short('F')) | |
783 | /// .arg(Arg::new("flag3") | |
784 | /// .short('z')) | |
785 | /// .arg(Arg::new("option") | |
786 | /// .short('o') | |
787 | /// .takes_value(true)) | |
788 | /// .get_matches_from(vec!["myapp", "-fzF", "-oval"]); | |
789 | /// // ARGV indices: ^0 ^1 ^2 | |
790 | /// // clap indices: ^1,2,3 ^5 | |
791 | /// // | |
792 | /// // clap sees the above as 'myapp -f -z -F -o val' | |
793 | /// // ^0 ^1 ^2 ^3 ^4 ^5 | |
794 | /// assert_eq!(m.index_of("flag"), Some(1)); | |
795 | /// assert_eq!(m.index_of("flag2"), Some(3)); | |
796 | /// assert_eq!(m.index_of("flag3"), Some(2)); | |
797 | /// assert_eq!(m.index_of("option"), Some(5)); | |
798 | /// ``` | |
799 | /// | |
800 | /// One final combination of flags/options to see how they combine: | |
801 | /// | |
802 | /// ```rust | |
803 | /// # use clap::{Command, Arg}; | |
804 | /// let m = Command::new("myapp") | |
805 | /// .arg(Arg::new("flag") | |
806 | /// .short('f')) | |
807 | /// .arg(Arg::new("flag2") | |
808 | /// .short('F')) | |
809 | /// .arg(Arg::new("flag3") | |
810 | /// .short('z')) | |
811 | /// .arg(Arg::new("option") | |
812 | /// .short('o') | |
813 | /// .takes_value(true)) | |
814 | /// .get_matches_from(vec!["myapp", "-fzFoval"]); | |
815 | /// // ARGV indices: ^0 ^1 | |
816 | /// // clap indices: ^1,2,3^5 | |
817 | /// // | |
818 | /// // clap sees the above as 'myapp -f -z -F -o val' | |
819 | /// // ^0 ^1 ^2 ^3 ^4 ^5 | |
820 | /// assert_eq!(m.index_of("flag"), Some(1)); | |
821 | /// assert_eq!(m.index_of("flag2"), Some(3)); | |
822 | /// assert_eq!(m.index_of("flag3"), Some(2)); | |
823 | /// assert_eq!(m.index_of("option"), Some(5)); | |
824 | /// ``` | |
825 | /// | |
826 | /// The last part to mention is when values are sent in multiple groups with a [delimiter]. | |
827 | /// | |
828 | /// ```rust | |
829 | /// # use clap::{Command, Arg}; | |
830 | /// let m = Command::new("myapp") | |
831 | /// .arg(Arg::new("option") | |
832 | /// .short('o') | |
833 | /// .use_value_delimiter(true) | |
834 | /// .multiple_values(true)) | |
835 | /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); | |
836 | /// // ARGV indices: ^0 ^1 | |
837 | /// // clap indices: ^2 ^3 ^4 | |
838 | /// // | |
839 | /// // clap sees the above as 'myapp -o val1 val2 val3' | |
840 | /// // ^0 ^1 ^2 ^3 ^4 | |
841 | /// assert_eq!(m.index_of("option"), Some(2)); | |
842 | /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]); | |
843 | /// ``` | |
844 | /// [delimiter]: crate::Arg::value_delimiter() | |
845 | pub fn index_of<T: Key>(&self, id: T) -> Option<usize> { | |
846 | let arg = self.get_arg(&Id::from(id))?; | |
847 | let i = arg.get_index(0)?; | |
848 | Some(i) | |
849 | } | |
850 | ||
851 | /// All indices an argument appeared at when parsing. | |
852 | /// | |
853 | /// Indices are similar to argv indices, but are not exactly 1:1. | |
854 | /// | |
855 | /// For flags (i.e. those arguments which don't have an associated value), indices refer | |
856 | /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices | |
857 | /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the | |
858 | /// index for `val` would be recorded. This is by design. | |
859 | /// | |
860 | /// *NOTE:* For more information about how clap indices compared to argv indices, see | |
861 | /// [`ArgMatches::index_of`] | |
862 | /// | |
863 | /// # Panics | |
864 | /// | |
865 | /// If `id` is is not a valid argument or group name. | |
866 | /// | |
867 | /// # Examples | |
868 | /// | |
869 | /// ```rust | |
870 | /// # use clap::{Command, Arg}; | |
871 | /// let m = Command::new("myapp") | |
872 | /// .arg(Arg::new("option") | |
873 | /// .short('o') | |
874 | /// .use_value_delimiter(true) | |
875 | /// .multiple_values(true)) | |
876 | /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); | |
877 | /// // ARGV indices: ^0 ^1 | |
878 | /// // clap indices: ^2 ^3 ^4 | |
879 | /// // | |
880 | /// // clap sees the above as 'myapp -o val1 val2 val3' | |
881 | /// // ^0 ^1 ^2 ^3 ^4 | |
882 | /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]); | |
883 | /// ``` | |
884 | /// | |
885 | /// Another quick example is when flags and options are used together | |
886 | /// | |
887 | /// ```rust | |
888 | /// # use clap::{Command, Arg}; | |
889 | /// let m = Command::new("myapp") | |
890 | /// .arg(Arg::new("option") | |
891 | /// .short('o') | |
892 | /// .takes_value(true) | |
893 | /// .multiple_occurrences(true)) | |
894 | /// .arg(Arg::new("flag") | |
895 | /// .short('f') | |
896 | /// .multiple_occurrences(true)) | |
897 | /// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]); | |
898 | /// // ARGV indices: ^0 ^1 ^2 ^3 ^4 ^5 ^6 | |
899 | /// // clap indices: ^2 ^3 ^5 ^6 | |
900 | /// | |
901 | /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]); | |
902 | /// assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]); | |
903 | /// ``` | |
904 | /// | |
905 | /// One final example, which is an odd case; if we *don't* use value delimiter as we did with | |
906 | /// the first example above instead of `val1`, `val2` and `val3` all being distinc values, they | |
907 | /// would all be a single value of `val1,val2,val3`, in which case they'd only receive a single | |
908 | /// index. | |
909 | /// | |
910 | /// ```rust | |
911 | /// # use clap::{Command, Arg}; | |
912 | /// let m = Command::new("myapp") | |
913 | /// .arg(Arg::new("option") | |
914 | /// .short('o') | |
915 | /// .takes_value(true) | |
916 | /// .multiple_values(true)) | |
917 | /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); | |
918 | /// // ARGV indices: ^0 ^1 | |
919 | /// // clap indices: ^2 | |
920 | /// // | |
921 | /// // clap sees the above as 'myapp -o "val1,val2,val3"' | |
922 | /// // ^0 ^1 ^2 | |
923 | /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]); | |
924 | /// ``` | |
925 | /// [`ArgMatches::index_of`]: ArgMatches::index_of() | |
926 | /// [delimiter]: Arg::value_delimiter() | |
927 | pub fn indices_of<T: Key>(&self, id: T) -> Option<Indices<'_>> { | |
928 | let arg = self.get_arg(&Id::from(id))?; | |
929 | let i = Indices { | |
930 | iter: arg.indices(), | |
931 | len: arg.num_vals(), | |
932 | }; | |
933 | Some(i) | |
934 | } | |
935 | ||
936 | /// The name and `ArgMatches` of the current [subcommand]. | |
937 | /// | |
938 | /// Subcommand values are put in a child [`ArgMatches`] | |
939 | /// | |
940 | /// Returns `None` if the subcommand wasn't present at runtime, | |
941 | /// | |
942 | /// # Examples | |
943 | /// | |
944 | /// ```no_run | |
945 | /// # use clap::{Command, Arg, }; | |
946 | /// let app_m = Command::new("git") | |
947 | /// .subcommand(Command::new("clone")) | |
948 | /// .subcommand(Command::new("push")) | |
949 | /// .subcommand(Command::new("commit")) | |
950 | /// .get_matches(); | |
951 | /// | |
952 | /// match app_m.subcommand() { | |
953 | /// Some(("clone", sub_m)) => {}, // clone was used | |
954 | /// Some(("push", sub_m)) => {}, // push was used | |
955 | /// Some(("commit", sub_m)) => {}, // commit was used | |
956 | /// _ => {}, // Either no subcommand or one not tested for... | |
957 | /// } | |
958 | /// ``` | |
959 | /// | |
960 | /// Another useful scenario is when you want to support third party, or external, subcommands. | |
961 | /// In these cases you can't know the subcommand name ahead of time, so use a variable instead | |
962 | /// with pattern matching! | |
963 | /// | |
964 | /// ```rust | |
965 | /// # use clap::Command; | |
966 | /// // Assume there is an external subcommand named "subcmd" | |
967 | /// let app_m = Command::new("myprog") | |
968 | /// .allow_external_subcommands(true) | |
969 | /// .get_matches_from(vec![ | |
970 | /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" | |
971 | /// ]); | |
972 | /// | |
973 | /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty | |
974 | /// // string argument name | |
975 | /// match app_m.subcommand() { | |
976 | /// Some((external, sub_m)) => { | |
977 | /// let ext_args: Vec<&str> = sub_m.values_of("").unwrap().collect(); | |
978 | /// assert_eq!(external, "subcmd"); | |
979 | /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); | |
980 | /// }, | |
981 | /// _ => {}, | |
982 | /// } | |
983 | /// ``` | |
984 | /// [subcommand]: crate::Command::subcommand | |
985 | #[inline] | |
986 | pub fn subcommand(&self) -> Option<(&str, &ArgMatches)> { | |
987 | self.subcommand.as_ref().map(|sc| (&*sc.name, &sc.matches)) | |
988 | } | |
989 | ||
990 | /// The `ArgMatches` for the current [subcommand]. | |
991 | /// | |
992 | /// Subcommand values are put in a child [`ArgMatches`] | |
993 | /// | |
994 | /// Returns `None` if the subcommand wasn't present at runtime, | |
995 | /// | |
996 | /// # Panics | |
997 | /// | |
998 | /// If `id` is is not a valid subcommand. | |
999 | /// | |
1000 | /// # Examples | |
1001 | /// | |
1002 | /// ```rust | |
1003 | /// # use clap::{Command, Arg, }; | |
1004 | /// let app_m = Command::new("myprog") | |
1005 | /// .arg(Arg::new("debug") | |
1006 | /// .short('d')) | |
1007 | /// .subcommand(Command::new("test") | |
1008 | /// .arg(Arg::new("opt") | |
1009 | /// .long("option") | |
1010 | /// .takes_value(true))) | |
1011 | /// .get_matches_from(vec![ | |
1012 | /// "myprog", "-d", "test", "--option", "val" | |
1013 | /// ]); | |
1014 | /// | |
1015 | /// // Both parent commands, and child subcommands can have arguments present at the same times | |
1016 | /// assert!(app_m.is_present("debug")); | |
1017 | /// | |
1018 | /// // Get the subcommand's ArgMatches instance | |
1019 | /// if let Some(sub_m) = app_m.subcommand_matches("test") { | |
1020 | /// // Use the struct like normal | |
1021 | /// assert_eq!(sub_m.value_of("opt"), Some("val")); | |
1022 | /// } | |
1023 | /// ``` | |
1024 | /// | |
1025 | /// [subcommand]: crate::Command::subcommand | |
1026 | /// [`Command`]: crate::Command | |
1027 | pub fn subcommand_matches<T: Key>(&self, id: T) -> Option<&ArgMatches> { | |
1028 | self.get_subcommand(&id.into()).map(|sc| &sc.matches) | |
1029 | } | |
1030 | ||
1031 | /// The name of the current [subcommand]. | |
1032 | /// | |
1033 | /// Returns `None` if the subcommand wasn't present at runtime, | |
1034 | /// | |
1035 | /// # Examples | |
1036 | /// | |
1037 | /// ```no_run | |
1038 | /// # use clap::{Command, Arg, }; | |
1039 | /// let app_m = Command::new("git") | |
1040 | /// .subcommand(Command::new("clone")) | |
1041 | /// .subcommand(Command::new("push")) | |
1042 | /// .subcommand(Command::new("commit")) | |
1043 | /// .get_matches(); | |
1044 | /// | |
1045 | /// match app_m.subcommand_name() { | |
1046 | /// Some("clone") => {}, // clone was used | |
1047 | /// Some("push") => {}, // push was used | |
1048 | /// Some("commit") => {}, // commit was used | |
1049 | /// _ => {}, // Either no subcommand or one not tested for... | |
1050 | /// } | |
1051 | /// ``` | |
1052 | /// [subcommand]: crate::Command::subcommand | |
1053 | /// [`Command`]: crate::Command | |
1054 | #[inline] | |
1055 | pub fn subcommand_name(&self) -> Option<&str> { | |
1056 | self.subcommand.as_ref().map(|sc| &*sc.name) | |
1057 | } | |
1058 | ||
1059 | /// Check if an arg can be queried | |
1060 | /// | |
1061 | /// By default, `ArgMatches` functions assert on undefined `Id`s to help catch programmer | |
1062 | /// mistakes. In some context, this doesn't work, so users can use this function to check | |
1063 | /// before they do a query on `ArgMatches`. | |
1064 | #[inline] | |
1065 | #[doc(hidden)] | |
1066 | pub fn is_valid_arg(&self, _id: impl Key) -> bool { | |
1067 | #[cfg(debug_assertions)] | |
1068 | { | |
1069 | let id = Id::from(_id); | |
1070 | self.disable_asserts || id == Id::empty_hash() || self.valid_args.contains(&id) | |
1071 | } | |
1072 | #[cfg(not(debug_assertions))] | |
1073 | { | |
1074 | true | |
1075 | } | |
1076 | } | |
1077 | ||
1078 | /// Check if a subcommand can be queried | |
1079 | /// | |
1080 | /// By default, `ArgMatches` functions assert on undefined `Id`s to help catch programmer | |
1081 | /// mistakes. In some context, this doesn't work, so users can use this function to check | |
1082 | /// before they do a query on `ArgMatches`. | |
1083 | #[inline] | |
1084 | #[doc(hidden)] | |
1085 | pub fn is_valid_subcommand(&self, _id: impl Key) -> bool { | |
1086 | #[cfg(debug_assertions)] | |
1087 | { | |
1088 | let id = Id::from(_id); | |
1089 | self.disable_asserts || id == Id::empty_hash() || self.valid_subcommands.contains(&id) | |
1090 | } | |
1091 | #[cfg(not(debug_assertions))] | |
1092 | { | |
1093 | true | |
1094 | } | |
1095 | } | |
1096 | } | |
1097 | ||
1098 | // Private methods | |
1099 | impl ArgMatches { | |
1100 | #[inline] | |
1101 | #[cfg_attr(debug_assertions, track_caller)] | |
1102 | fn get_arg(&self, arg: &Id) -> Option<&MatchedArg> { | |
1103 | #[cfg(debug_assertions)] | |
1104 | { | |
1105 | if self.disable_asserts || *arg == Id::empty_hash() || self.valid_args.contains(arg) { | |
1106 | } else if self.valid_subcommands.contains(arg) { | |
1107 | panic!( | |
1108 | "Subcommand `{:?}` used where an argument or group name was expected.", | |
1109 | arg | |
1110 | ); | |
1111 | } else { | |
1112 | panic!( | |
1113 | "`{:?}` is not a name of an argument or a group.\n\ | |
1114 | Make sure you're using the name of the argument itself \ | |
1115 | and not the name of short or long flags.", | |
1116 | arg | |
1117 | ); | |
1118 | } | |
1119 | } | |
1120 | ||
1121 | self.args.get(arg) | |
1122 | } | |
1123 | ||
1124 | #[inline] | |
1125 | #[cfg_attr(debug_assertions, track_caller)] | |
1126 | fn get_subcommand(&self, id: &Id) -> Option<&SubCommand> { | |
1127 | #[cfg(debug_assertions)] | |
1128 | { | |
1129 | if self.disable_asserts | |
1130 | || *id == Id::empty_hash() | |
1131 | || self.valid_subcommands.contains(id) | |
1132 | { | |
1133 | } else if self.valid_args.contains(id) { | |
1134 | panic!( | |
1135 | "Argument or group `{:?}` used where a subcommand name was expected.", | |
1136 | id | |
1137 | ); | |
1138 | } else { | |
1139 | panic!("`{:?}` is not a name of a subcommand.", id); | |
1140 | } | |
1141 | } | |
1142 | ||
1143 | if let Some(ref sc) = self.subcommand { | |
1144 | if sc.id == *id { | |
1145 | return Some(sc); | |
1146 | } | |
1147 | } | |
1148 | ||
1149 | None | |
1150 | } | |
1151 | } | |
1152 | ||
1153 | #[derive(Debug, Clone, PartialEq, Eq)] | |
1154 | pub(crate) struct SubCommand { | |
1155 | pub(crate) id: Id, | |
1156 | pub(crate) name: String, | |
1157 | pub(crate) matches: ArgMatches, | |
1158 | } | |
1159 | ||
1160 | // The following were taken and adapted from vec_map source | |
1161 | // repo: https://github.com/contain-rs/vec-map | |
1162 | // commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33 | |
1163 | // license: MIT - Copyright (c) 2015 The Rust Project Developers | |
1164 | ||
1165 | /// Iterate over multiple values for an argument via [`ArgMatches::values_of`]. | |
1166 | /// | |
1167 | /// # Examples | |
1168 | /// | |
1169 | /// ```rust | |
1170 | /// # use clap::{Command, Arg}; | |
1171 | /// let m = Command::new("myapp") | |
1172 | /// .arg(Arg::new("output") | |
1173 | /// .short('o') | |
1174 | /// .multiple_occurrences(true) | |
1175 | /// .takes_value(true)) | |
1176 | /// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]); | |
1177 | /// | |
1178 | /// let mut values = m.values_of("output").unwrap(); | |
1179 | /// | |
1180 | /// assert_eq!(values.next(), Some("val1")); | |
1181 | /// assert_eq!(values.next(), Some("val2")); | |
1182 | /// assert_eq!(values.next(), None); | |
1183 | /// ``` | |
1184 | /// [`ArgMatches::values_of`]: ArgMatches::values_of() | |
1185 | #[derive(Clone)] | |
1186 | #[allow(missing_debug_implementations)] | |
1187 | pub struct Values<'a> { | |
1188 | #[allow(clippy::type_complexity)] | |
1189 | iter: Map<Flatten<Iter<'a, Vec<OsString>>>, for<'r> fn(&'r OsString) -> &'r str>, | |
1190 | len: usize, | |
1191 | } | |
1192 | ||
1193 | impl<'a> Iterator for Values<'a> { | |
1194 | type Item = &'a str; | |
1195 | ||
1196 | fn next(&mut self) -> Option<&'a str> { | |
1197 | self.iter.next() | |
1198 | } | |
1199 | fn size_hint(&self) -> (usize, Option<usize>) { | |
1200 | (self.len, Some(self.len)) | |
1201 | } | |
1202 | } | |
1203 | ||
1204 | impl<'a> DoubleEndedIterator for Values<'a> { | |
1205 | fn next_back(&mut self) -> Option<&'a str> { | |
1206 | self.iter.next_back() | |
1207 | } | |
1208 | } | |
1209 | ||
1210 | impl<'a> ExactSizeIterator for Values<'a> {} | |
1211 | ||
1212 | /// Creates an empty iterator. | |
1213 | impl<'a> Default for Values<'a> { | |
1214 | fn default() -> Self { | |
1215 | static EMPTY: [Vec<OsString>; 0] = []; | |
1216 | Values { | |
1217 | iter: EMPTY[..].iter().flatten().map(|_| unreachable!()), | |
1218 | len: 0, | |
1219 | } | |
1220 | } | |
1221 | } | |
1222 | ||
1223 | #[derive(Clone)] | |
1224 | #[allow(missing_debug_implementations)] | |
1225 | pub struct GroupedValues<'a> { | |
1226 | #[allow(clippy::type_complexity)] | |
1227 | iter: Map<Iter<'a, Vec<OsString>>, fn(&Vec<OsString>) -> Vec<&str>>, | |
1228 | len: usize, | |
1229 | } | |
1230 | ||
1231 | impl<'a> Iterator for GroupedValues<'a> { | |
1232 | type Item = Vec<&'a str>; | |
1233 | ||
1234 | fn next(&mut self) -> Option<Self::Item> { | |
1235 | self.iter.next() | |
1236 | } | |
1237 | fn size_hint(&self) -> (usize, Option<usize>) { | |
1238 | (self.len, Some(self.len)) | |
1239 | } | |
1240 | } | |
1241 | ||
1242 | impl<'a> DoubleEndedIterator for GroupedValues<'a> { | |
1243 | fn next_back(&mut self) -> Option<Self::Item> { | |
1244 | self.iter.next_back() | |
1245 | } | |
1246 | } | |
1247 | ||
1248 | impl<'a> ExactSizeIterator for GroupedValues<'a> {} | |
1249 | ||
1250 | /// Creates an empty iterator. Used for `unwrap_or_default()`. | |
1251 | impl<'a> Default for GroupedValues<'a> { | |
1252 | fn default() -> Self { | |
1253 | static EMPTY: [Vec<OsString>; 0] = []; | |
1254 | GroupedValues { | |
1255 | iter: EMPTY[..].iter().map(|_| unreachable!()), | |
1256 | len: 0, | |
1257 | } | |
1258 | } | |
1259 | } | |
1260 | ||
1261 | /// Iterate over multiple values for an argument via [`ArgMatches::values_of_os`]. | |
1262 | /// | |
1263 | /// # Examples | |
1264 | /// | |
1265 | #[cfg_attr(not(unix), doc = " ```ignore")] | |
1266 | #[cfg_attr(unix, doc = " ```")] | |
1267 | /// # use clap::{Command, arg}; | |
1268 | /// use std::ffi::OsString; | |
1269 | /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; | |
1270 | /// | |
1271 | /// let m = Command::new("utf8") | |
1272 | /// .arg(arg!(<arg> "some arg") | |
1273 | /// .allow_invalid_utf8(true)) | |
1274 | /// .get_matches_from(vec![OsString::from("myprog"), | |
1275 | /// // "Hi {0xe9}!" | |
1276 | /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); | |
1277 | /// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']); | |
1278 | /// ``` | |
1279 | /// [`ArgMatches::values_of_os`]: ArgMatches::values_of_os() | |
1280 | #[derive(Clone)] | |
1281 | #[allow(missing_debug_implementations)] | |
1282 | pub struct OsValues<'a> { | |
1283 | #[allow(clippy::type_complexity)] | |
1284 | iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>, | |
1285 | len: usize, | |
1286 | } | |
1287 | ||
1288 | impl<'a> Iterator for OsValues<'a> { | |
1289 | type Item = &'a OsStr; | |
1290 | ||
1291 | fn next(&mut self) -> Option<&'a OsStr> { | |
1292 | self.iter.next() | |
1293 | } | |
1294 | fn size_hint(&self) -> (usize, Option<usize>) { | |
1295 | (self.len, Some(self.len)) | |
1296 | } | |
1297 | } | |
1298 | ||
1299 | impl<'a> DoubleEndedIterator for OsValues<'a> { | |
1300 | fn next_back(&mut self) -> Option<&'a OsStr> { | |
1301 | self.iter.next_back() | |
1302 | } | |
1303 | } | |
1304 | ||
1305 | impl<'a> ExactSizeIterator for OsValues<'a> {} | |
1306 | ||
1307 | /// Creates an empty iterator. | |
1308 | impl Default for OsValues<'_> { | |
1309 | fn default() -> Self { | |
1310 | static EMPTY: [Vec<OsString>; 0] = []; | |
1311 | OsValues { | |
1312 | iter: EMPTY[..].iter().flatten().map(|_| unreachable!()), | |
1313 | len: 0, | |
1314 | } | |
1315 | } | |
1316 | } | |
1317 | ||
1318 | /// Iterate over indices for where an argument appeared when parsing, via [`ArgMatches::indices_of`] | |
1319 | /// | |
1320 | /// # Examples | |
1321 | /// | |
1322 | /// ```rust | |
1323 | /// # use clap::{Command, Arg}; | |
1324 | /// let m = Command::new("myapp") | |
1325 | /// .arg(Arg::new("output") | |
1326 | /// .short('o') | |
1327 | /// .multiple_values(true) | |
1328 | /// .takes_value(true)) | |
1329 | /// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]); | |
1330 | /// | |
1331 | /// let mut indices = m.indices_of("output").unwrap(); | |
1332 | /// | |
1333 | /// assert_eq!(indices.next(), Some(2)); | |
1334 | /// assert_eq!(indices.next(), Some(3)); | |
1335 | /// assert_eq!(indices.next(), None); | |
1336 | /// ``` | |
1337 | /// [`ArgMatches::indices_of`]: ArgMatches::indices_of() | |
1338 | #[derive(Clone)] | |
1339 | #[allow(missing_debug_implementations)] | |
1340 | pub struct Indices<'a> { | |
1341 | iter: Cloned<Iter<'a, usize>>, | |
1342 | len: usize, | |
1343 | } | |
1344 | ||
1345 | impl<'a> Iterator for Indices<'a> { | |
1346 | type Item = usize; | |
1347 | ||
1348 | fn next(&mut self) -> Option<usize> { | |
1349 | self.iter.next() | |
1350 | } | |
1351 | fn size_hint(&self) -> (usize, Option<usize>) { | |
1352 | (self.len, Some(self.len)) | |
1353 | } | |
1354 | } | |
1355 | ||
1356 | impl<'a> DoubleEndedIterator for Indices<'a> { | |
1357 | fn next_back(&mut self) -> Option<usize> { | |
1358 | self.iter.next_back() | |
1359 | } | |
1360 | } | |
1361 | ||
1362 | impl<'a> ExactSizeIterator for Indices<'a> {} | |
1363 | ||
1364 | /// Creates an empty iterator. | |
1365 | impl<'a> Default for Indices<'a> { | |
1366 | fn default() -> Self { | |
1367 | static EMPTY: [usize; 0] = []; | |
1368 | // This is never called because the iterator is empty: | |
1369 | Indices { | |
1370 | iter: EMPTY[..].iter().cloned(), | |
1371 | len: 0, | |
1372 | } | |
1373 | } | |
1374 | } | |
1375 | ||
1376 | #[cfg_attr(debug_assertions, track_caller)] | |
1377 | #[inline] | |
1378 | fn assert_utf8_validation(arg: &MatchedArg, id: &Id) { | |
1379 | debug_assert!( | |
1380 | matches!(arg.is_invalid_utf8_allowed(), None | Some(false)), | |
1381 | "Must use `_os` lookups with `Arg::allow_invalid_utf8` at `{:?}`", | |
1382 | id | |
1383 | ); | |
1384 | } | |
1385 | ||
1386 | #[cfg_attr(debug_assertions, track_caller)] | |
1387 | #[inline] | |
1388 | fn assert_no_utf8_validation(arg: &MatchedArg, id: &Id) { | |
1389 | debug_assert!( | |
1390 | matches!(arg.is_invalid_utf8_allowed(), None | Some(true)), | |
1391 | "Must use `Arg::allow_invalid_utf8` with `_os` lookups at `{:?}`", | |
1392 | id | |
1393 | ); | |
1394 | } | |
1395 | ||
1396 | #[cfg(test)] | |
1397 | mod tests { | |
1398 | use super::*; | |
1399 | ||
1400 | #[test] | |
1401 | fn test_default_values() { | |
1402 | let mut values: Values = Values::default(); | |
1403 | assert_eq!(values.next(), None); | |
1404 | } | |
1405 | ||
1406 | #[test] | |
1407 | fn test_default_values_with_shorter_lifetime() { | |
1408 | let matches = ArgMatches::default(); | |
1409 | let mut values = matches.values_of("").unwrap_or_default(); | |
1410 | assert_eq!(values.next(), None); | |
1411 | } | |
1412 | ||
1413 | #[test] | |
1414 | fn test_default_osvalues() { | |
1415 | let mut values: OsValues = OsValues::default(); | |
1416 | assert_eq!(values.next(), None); | |
1417 | } | |
1418 | ||
1419 | #[test] | |
1420 | fn test_default_osvalues_with_shorter_lifetime() { | |
1421 | let matches = ArgMatches::default(); | |
1422 | let mut values = matches.values_of_os("").unwrap_or_default(); | |
1423 | assert_eq!(values.next(), None); | |
1424 | } | |
1425 | ||
1426 | #[test] | |
1427 | fn test_default_indices() { | |
1428 | let mut indices: Indices = Indices::default(); | |
1429 | assert_eq!(indices.next(), None); | |
1430 | } | |
1431 | ||
1432 | #[test] | |
1433 | fn test_default_indices_with_shorter_lifetime() { | |
1434 | let matches = ArgMatches::default(); | |
1435 | let mut indices = matches.indices_of("").unwrap_or_default(); | |
1436 | assert_eq!(indices.next(), None); | |
1437 | } | |
1438 | ||
1439 | #[test] | |
1440 | fn values_exact_size() { | |
1441 | let l = crate::Command::new("test") | |
1442 | .arg( | |
1443 | crate::Arg::new("POTATO") | |
1444 | .takes_value(true) | |
1445 | .multiple_values(true) | |
1446 | .required(true), | |
1447 | ) | |
1448 | .try_get_matches_from(["test", "one"]) | |
1449 | .unwrap() | |
1450 | .values_of("POTATO") | |
1451 | .expect("present") | |
1452 | .len(); | |
1453 | assert_eq!(l, 1); | |
1454 | } | |
1455 | ||
1456 | #[test] | |
1457 | fn os_values_exact_size() { | |
1458 | let l = crate::Command::new("test") | |
1459 | .arg( | |
1460 | crate::Arg::new("POTATO") | |
1461 | .takes_value(true) | |
1462 | .multiple_values(true) | |
1463 | .allow_invalid_utf8(true) | |
1464 | .required(true), | |
1465 | ) | |
1466 | .try_get_matches_from(["test", "one"]) | |
1467 | .unwrap() | |
1468 | .values_of_os("POTATO") | |
1469 | .expect("present") | |
1470 | .len(); | |
1471 | assert_eq!(l, 1); | |
1472 | } | |
1473 | ||
1474 | #[test] | |
1475 | fn indices_exact_size() { | |
1476 | let l = crate::Command::new("test") | |
1477 | .arg( | |
1478 | crate::Arg::new("POTATO") | |
1479 | .takes_value(true) | |
1480 | .multiple_values(true) | |
1481 | .required(true), | |
1482 | ) | |
1483 | .try_get_matches_from(["test", "one"]) | |
1484 | .unwrap() | |
1485 | .indices_of("POTATO") | |
1486 | .expect("present") | |
1487 | .len(); | |
1488 | assert_eq!(l, 1); | |
1489 | } | |
1490 | } |