summaryrefslogtreecommitdiffstats
path: root/vendor/clap-3.2.20/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap-3.2.20/src/parser')
-rw-r--r--vendor/clap-3.2.20/src/parser/arg_matcher.rs280
-rw-r--r--vendor/clap-3.2.20/src/parser/error.rs67
-rw-r--r--vendor/clap-3.2.20/src/parser/features/mod.rs1
-rw-r--r--vendor/clap-3.2.20/src/parser/features/suggestions.rs105
-rw-r--r--vendor/clap-3.2.20/src/parser/matches/any_value.rs112
-rw-r--r--vendor/clap-3.2.20/src/parser/matches/arg_matches.rs1896
-rw-r--r--vendor/clap-3.2.20/src/parser/matches/matched_arg.rs240
-rw-r--r--vendor/clap-3.2.20/src/parser/matches/mod.rs17
-rw-r--r--vendor/clap-3.2.20/src/parser/matches/value_source.rs11
-rw-r--r--vendor/clap-3.2.20/src/parser/mod.rs27
-rw-r--r--vendor/clap-3.2.20/src/parser/parser.rs1729
-rw-r--r--vendor/clap-3.2.20/src/parser/validator.rs692
12 files changed, 5177 insertions, 0 deletions
diff --git a/vendor/clap-3.2.20/src/parser/arg_matcher.rs b/vendor/clap-3.2.20/src/parser/arg_matcher.rs
new file mode 100644
index 000000000..22087e722
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/arg_matcher.rs
@@ -0,0 +1,280 @@
+// Std
+use std::collections::HashMap;
+use std::ffi::OsString;
+use std::mem;
+use std::ops::Deref;
+
+// Internal
+use crate::builder::{Arg, ArgPredicate, Command};
+use crate::parser::AnyValue;
+use crate::parser::Identifier;
+use crate::parser::PendingArg;
+use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
+use crate::util::Id;
+use crate::INTERNAL_ERROR_MSG;
+
+#[derive(Debug, Default)]
+pub(crate) struct ArgMatcher {
+ matches: ArgMatches,
+ pending: Option<PendingArg>,
+}
+
+impl ArgMatcher {
+ pub(crate) fn new(_cmd: &Command) -> Self {
+ ArgMatcher {
+ matches: ArgMatches {
+ #[cfg(debug_assertions)]
+ valid_args: {
+ let args = _cmd.get_arguments().map(|a| a.id.clone());
+ let groups = _cmd.get_groups().map(|g| g.id.clone());
+ args.chain(groups).collect()
+ },
+ #[cfg(debug_assertions)]
+ valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
+ // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
+ // since users can't detect it and avoid the asserts.
+ //
+ // See clap-rs/clap#3263
+ #[cfg(debug_assertions)]
+ #[cfg(not(feature = "unstable-v4"))]
+ disable_asserts: _cmd.is_allow_external_subcommands_set(),
+ #[cfg(debug_assertions)]
+ #[cfg(feature = "unstable-v4")]
+ disable_asserts: false,
+ ..Default::default()
+ },
+ pending: None,
+ }
+ }
+
+ pub(crate) fn into_inner(self) -> ArgMatches {
+ self.matches
+ }
+
+ pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
+ debug!(
+ "ArgMatcher::get_global_values: global_arg_vec={:?}",
+ global_arg_vec
+ );
+ let mut vals_map = HashMap::new();
+ self.fill_in_global_values(global_arg_vec, &mut vals_map);
+ }
+
+ fn fill_in_global_values(
+ &mut self,
+ global_arg_vec: &[Id],
+ vals_map: &mut HashMap<Id, MatchedArg>,
+ ) {
+ for global_arg in global_arg_vec {
+ if let Some(ma) = self.get(global_arg) {
+ // We have to check if the parent's global arg wasn't used but still exists
+ // such as from a default value.
+ //
+ // For example, `myprog subcommand --global-arg=value` where `--global-arg` defines
+ // a default value of `other` myprog would have an existing MatchedArg for
+ // `--global-arg` where the value is `other`
+ let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
+ if parent_ma.source() > ma.source() {
+ parent_ma
+ } else {
+ ma
+ }
+ } else {
+ ma
+ }
+ .clone();
+ vals_map.insert(global_arg.clone(), to_update);
+ }
+ }
+ if let Some(ref mut sc) = self.matches.subcommand {
+ let mut am = ArgMatcher {
+ matches: mem::take(&mut sc.matches),
+ pending: None,
+ };
+ am.fill_in_global_values(global_arg_vec, vals_map);
+ mem::swap(&mut am.matches, &mut sc.matches);
+ }
+
+ for (name, matched_arg) in vals_map.iter_mut() {
+ self.matches.args.insert(name.clone(), matched_arg.clone());
+ }
+ }
+
+ pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
+ self.matches.args.get(arg)
+ }
+
+ pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
+ self.matches.args.get_mut(arg)
+ }
+
+ pub(crate) fn remove(&mut self, arg: &Id) {
+ self.matches.args.swap_remove(arg);
+ }
+
+ pub(crate) fn contains(&self, arg: &Id) -> bool {
+ self.matches.args.contains_key(arg)
+ }
+
+ pub(crate) fn arg_ids(&self) -> indexmap::map::Keys<Id, MatchedArg> {
+ self.matches.args.keys()
+ }
+
+ pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
+ self.matches.args.entry(arg.clone())
+ }
+
+ pub(crate) fn subcommand(&mut self, sc: SubCommand) {
+ self.matches.subcommand = Some(Box::new(sc));
+ }
+
+ pub(crate) fn subcommand_name(&self) -> Option<&str> {
+ self.matches.subcommand_name()
+ }
+
+ pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
+ self.matches.args.iter()
+ }
+
+ pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
+ self.get(arg).map_or(false, |a| a.check_explicit(predicate))
+ }
+
+ pub(crate) fn start_custom_arg(&mut self, arg: &Arg, source: ValueSource) {
+ let id = &arg.id;
+ debug!(
+ "ArgMatcher::start_custom_arg: id={:?}, source={:?}",
+ id, source
+ );
+ let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
+ debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
+ ma.set_source(source);
+ ma.new_val_group();
+ }
+
+ pub(crate) fn start_custom_group(&mut self, id: &Id, source: ValueSource) {
+ debug!(
+ "ArgMatcher::start_custom_arg: id={:?}, source={:?}",
+ id, source
+ );
+ let ma = self.entry(id).or_insert(MatchedArg::new_group());
+ debug_assert_eq!(ma.type_id(), None);
+ ma.set_source(source);
+ ma.new_val_group();
+ }
+
+ pub(crate) fn start_occurrence_of_arg(&mut self, arg: &Arg) {
+ let id = &arg.id;
+ debug!("ArgMatcher::start_occurrence_of_arg: id={:?}", id);
+ let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
+ debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
+ ma.set_source(ValueSource::CommandLine);
+ #[allow(deprecated)]
+ ma.inc_occurrences();
+ ma.new_val_group();
+ }
+
+ pub(crate) fn start_occurrence_of_group(&mut self, id: &Id) {
+ debug!("ArgMatcher::start_occurrence_of_group: id={:?}", id);
+ let ma = self.entry(id).or_insert(MatchedArg::new_group());
+ debug_assert_eq!(ma.type_id(), None);
+ ma.set_source(ValueSource::CommandLine);
+ #[allow(deprecated)]
+ ma.inc_occurrences();
+ ma.new_val_group();
+ }
+
+ pub(crate) fn start_occurrence_of_external(&mut self, cmd: &crate::Command) {
+ let id = &Id::empty_hash();
+ debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,);
+ let ma = self.entry(id).or_insert(MatchedArg::new_external(cmd));
+ debug_assert_eq!(
+ ma.type_id(),
+ Some(
+ cmd.get_external_subcommand_value_parser()
+ .expect(INTERNAL_ERROR_MSG)
+ .type_id()
+ )
+ );
+ ma.set_source(ValueSource::CommandLine);
+ #[allow(deprecated)]
+ ma.inc_occurrences();
+ ma.new_val_group();
+ }
+
+ pub(crate) fn add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString) {
+ let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
+ ma.append_val(val, raw_val);
+ }
+
+ pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize) {
+ let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
+ ma.push_index(idx);
+ }
+
+ pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
+ let num_resolved = self.get(&o.id).map(|ma| ma.num_vals()).unwrap_or(0);
+ let num_pending = self
+ .pending
+ .as_ref()
+ .and_then(|p| (p.id == o.id).then(|| p.raw_vals.len()))
+ .unwrap_or(0);
+ let current_num = num_resolved + num_pending;
+ debug!(
+ "ArgMatcher::needs_more_vals: o={}, resolved={}, pending={}",
+ o.name, num_resolved, num_pending
+ );
+ if current_num == 0 {
+ true
+ } else if let Some(num) = o.num_vals {
+ debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
+ #[allow(deprecated)]
+ if o.is_multiple_occurrences_set() {
+ (current_num % num) != 0
+ } else {
+ num != current_num
+ }
+ } else if let Some(num) = o.max_vals {
+ debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
+ current_num < num
+ } else if o.min_vals.is_some() {
+ debug!("ArgMatcher::needs_more_vals: min_vals...true");
+ true
+ } else {
+ o.is_multiple_values_set()
+ }
+ }
+
+ pub(crate) fn pending_arg_id(&self) -> Option<&Id> {
+ self.pending.as_ref().map(|p| &p.id)
+ }
+
+ pub(crate) fn pending_values_mut(
+ &mut self,
+ id: &Id,
+ ident: Option<Identifier>,
+ ) -> &mut Vec<OsString> {
+ let pending = self.pending.get_or_insert_with(|| PendingArg {
+ id: id.clone(),
+ ident,
+ raw_vals: Default::default(),
+ });
+ debug_assert_eq!(pending.id, *id, "{}", INTERNAL_ERROR_MSG);
+ if ident.is_some() {
+ debug_assert_eq!(pending.ident, ident, "{}", INTERNAL_ERROR_MSG);
+ }
+ &mut pending.raw_vals
+ }
+
+ pub(crate) fn take_pending(&mut self) -> Option<PendingArg> {
+ self.pending.take()
+ }
+}
+
+impl Deref for ArgMatcher {
+ type Target = ArgMatches;
+
+ fn deref(&self) -> &Self::Target {
+ &self.matches
+ }
+}
diff --git a/vendor/clap-3.2.20/src/parser/error.rs b/vendor/clap-3.2.20/src/parser/error.rs
new file mode 100644
index 000000000..caeba4b8f
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/error.rs
@@ -0,0 +1,67 @@
+use crate::util::Id;
+
+/// Violation of [`ArgMatches`][crate::ArgMatches] assumptions
+#[derive(Clone, Debug)]
+#[allow(missing_copy_implementations)] // We might add non-Copy types in the future
+#[non_exhaustive]
+pub enum MatchesError {
+ /// Failed to downcast `AnyValue` to the specified type
+ #[non_exhaustive]
+ Downcast {
+ /// Type for value stored in [`ArgMatches`][crate::ArgMatches]
+ actual: super::AnyValueId,
+ /// The target type to downcast to
+ expected: super::AnyValueId,
+ },
+ /// Argument not defined in [`Command`][crate::Command]
+ #[non_exhaustive]
+ UnknownArgument {
+ // Missing `id` but blocked on a public id type which will hopefully come with `unstable-v4`
+ },
+}
+
+impl MatchesError {
+ #[track_caller]
+ pub(crate) fn unwrap<T>(id: &Id, r: Result<T, MatchesError>) -> T {
+ let err = match r {
+ Ok(t) => {
+ return t;
+ }
+ Err(err) => err,
+ };
+ panic!(
+ "Mismatch between definition and access of `{:?}`. {}",
+ id, err
+ )
+ }
+}
+
+impl std::error::Error for MatchesError {}
+
+impl std::fmt::Display for MatchesError {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self {
+ Self::Downcast { actual, expected } => {
+ writeln!(
+ f,
+ "Could not downcast to {:?}, need to downcast to {:?}",
+ expected, actual
+ )
+ }
+ Self::UnknownArgument {} => {
+ writeln!(f, "Unknown argument or group id. Make sure you are using the argument id and not the short or long flags")
+ }
+ }
+ }
+}
+
+#[test]
+fn check_auto_traits() {
+ static_assertions::assert_impl_all!(
+ MatchesError: Send,
+ Sync,
+ std::panic::RefUnwindSafe,
+ std::panic::UnwindSafe,
+ Unpin
+ );
+}
diff --git a/vendor/clap-3.2.20/src/parser/features/mod.rs b/vendor/clap-3.2.20/src/parser/features/mod.rs
new file mode 100644
index 000000000..bdeb766ec
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/features/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod suggestions;
diff --git a/vendor/clap-3.2.20/src/parser/features/suggestions.rs b/vendor/clap-3.2.20/src/parser/features/suggestions.rs
new file mode 100644
index 000000000..9e46f3c9e
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/features/suggestions.rs
@@ -0,0 +1,105 @@
+#[cfg(feature = "suggestions")]
+use std::cmp::Ordering;
+
+// Internal
+use crate::builder::Command;
+
+/// Produces multiple strings from a given list of possible values which are similar
+/// to the passed in value `v` within a certain confidence by least confidence.
+/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
+/// `Some("foo")`, whereas "blark" would yield `None`.
+#[cfg(feature = "suggestions")]
+pub(crate) fn did_you_mean<T, I>(v: &str, possible_values: I) -> Vec<String>
+where
+ T: AsRef<str>,
+ I: IntoIterator<Item = T>,
+{
+ let mut candidates: Vec<(f64, String)> = possible_values
+ .into_iter()
+ .map(|pv| (strsim::jaro_winkler(v, pv.as_ref()), pv.as_ref().to_owned()))
+ .filter(|(confidence, _)| *confidence > 0.8)
+ .collect();
+ candidates.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
+ candidates.into_iter().map(|(_, pv)| pv).collect()
+}
+
+#[cfg(not(feature = "suggestions"))]
+pub(crate) fn did_you_mean<T, I>(_: &str, _: I) -> Vec<String>
+where
+ T: AsRef<str>,
+ I: IntoIterator<Item = T>,
+{
+ Vec::new()
+}
+
+/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
+pub(crate) fn did_you_mean_flag<'a, 'help, I, T>(
+ arg: &str,
+ remaining_args: &[&str],
+ longs: I,
+ subcommands: impl IntoIterator<Item = &'a mut Command<'help>>,
+) -> Option<(String, Option<String>)>
+where
+ 'help: 'a,
+ T: AsRef<str>,
+ I: IntoIterator<Item = T>,
+{
+ use crate::mkeymap::KeyType;
+
+ match did_you_mean(arg, longs).pop() {
+ Some(candidate) => Some((candidate, None)),
+ None => subcommands
+ .into_iter()
+ .filter_map(|subcommand| {
+ subcommand._build_self();
+
+ let longs = subcommand.get_keymap().keys().filter_map(|a| {
+ if let KeyType::Long(v) = a {
+ Some(v.to_string_lossy().into_owned())
+ } else {
+ None
+ }
+ });
+
+ let subcommand_name = subcommand.get_name();
+
+ let candidate = did_you_mean(arg, longs).pop()?;
+ let score = remaining_args.iter().position(|x| *x == subcommand_name)?;
+ Some((score, (candidate, Some(subcommand_name.to_string()))))
+ })
+ .min_by_key(|(x, _)| *x)
+ .map(|(_, suggestion)| suggestion),
+ }
+}
+
+#[cfg(all(test, features = "suggestions"))]
+mod test {
+ use super::*;
+
+ #[test]
+ fn possible_values_match() {
+ let p_vals = ["test", "possible", "values"];
+ assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test"));
+ }
+
+ #[test]
+ fn possible_values_match() {
+ let p_vals = ["test", "temp"];
+ assert_eq!(did_you_mean("te", p_vals.iter()), Some("test"));
+ }
+
+ #[test]
+ fn possible_values_nomatch() {
+ let p_vals = ["test", "possible", "values"];
+ assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none());
+ }
+
+ #[test]
+ fn flag() {
+ let p_vals = ["test", "possible", "values"];
+ assert_eq!(
+ did_you_mean_flag("tst", p_vals.iter(), []),
+ Some(("test", None))
+ );
+ }
+}
diff --git a/vendor/clap-3.2.20/src/parser/matches/any_value.rs b/vendor/clap-3.2.20/src/parser/matches/any_value.rs
new file mode 100644
index 000000000..a9277e75f
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/matches/any_value.rs
@@ -0,0 +1,112 @@
+#[derive(Clone)]
+pub(crate) struct AnyValue {
+ inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>,
+ // While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track
+ // the type_name in debug builds.
+ id: AnyValueId,
+}
+
+impl AnyValue {
+ pub(crate) fn new<V: std::any::Any + Clone + Send + Sync + 'static>(inner: V) -> Self {
+ let id = AnyValueId::of::<V>();
+ let inner = std::sync::Arc::new(inner);
+ Self { inner, id }
+ }
+
+ pub(crate) fn downcast_ref<T: std::any::Any + Clone + Send + Sync + 'static>(
+ &self,
+ ) -> Option<&T> {
+ self.inner.downcast_ref::<T>()
+ }
+
+ pub(crate) fn downcast_into<T: std::any::Any + Clone + Send + Sync>(self) -> Result<T, Self> {
+ let id = self.id;
+ let value =
+ std::sync::Arc::downcast::<T>(self.inner).map_err(|inner| Self { inner, id })?;
+ let value = std::sync::Arc::try_unwrap(value).unwrap_or_else(|arc| (*arc).clone());
+ Ok(value)
+ }
+
+ pub(crate) fn type_id(&self) -> AnyValueId {
+ self.id
+ }
+}
+
+impl std::fmt::Debug for AnyValue {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ f.debug_struct("AnyValue").field("inner", &self.id).finish()
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct AnyValueId {
+ type_id: std::any::TypeId,
+ #[cfg(debug_assertions)]
+ type_name: &'static str,
+}
+
+impl AnyValueId {
+ pub(crate) fn of<A: ?Sized + 'static>() -> Self {
+ Self {
+ type_id: std::any::TypeId::of::<A>(),
+ #[cfg(debug_assertions)]
+ type_name: std::any::type_name::<A>(),
+ }
+ }
+}
+
+impl PartialEq for AnyValueId {
+ fn eq(&self, other: &Self) -> bool {
+ self.type_id == other.type_id
+ }
+}
+
+impl Eq for AnyValueId {}
+
+impl PartialOrd for AnyValueId {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ self.type_id.partial_cmp(&other.type_id)
+ }
+}
+
+impl Ord for AnyValueId {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.type_id.cmp(&other.type_id)
+ }
+}
+
+impl std::hash::Hash for AnyValueId {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.type_id.hash(state);
+ }
+}
+
+impl std::fmt::Debug for AnyValueId {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ #[cfg(not(debug_assertions))]
+ {
+ self.type_id.fmt(f)
+ }
+ #[cfg(debug_assertions)]
+ {
+ f.debug_struct(self.type_name).finish()
+ }
+ }
+}
+
+impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId {
+ fn from(_: &'a A) -> Self {
+ Self::of::<A>()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[test]
+ #[cfg(debug_assertions)]
+ fn debug_impl() {
+ use super::*;
+
+ assert_eq!(format!("{:?}", AnyValue::new(5)), "AnyValue { inner: i32 }");
+ }
+}
diff --git a/vendor/clap-3.2.20/src/parser/matches/arg_matches.rs b/vendor/clap-3.2.20/src/parser/matches/arg_matches.rs
new file mode 100644
index 000000000..2585c0219
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/matches/arg_matches.rs
@@ -0,0 +1,1896 @@
+// Std
+use std::any::Any;
+use std::borrow::Cow;
+use std::ffi::{OsStr, OsString};
+use std::fmt::{Debug, Display};
+use std::iter::{Cloned, Flatten, Map};
+use std::slice::Iter;
+use std::str::FromStr;
+
+// Third Party
+use indexmap::IndexMap;
+
+// Internal
+use crate::parser::AnyValue;
+use crate::parser::AnyValueId;
+use crate::parser::MatchedArg;
+use crate::parser::MatchesError;
+use crate::parser::ValueSource;
+use crate::util::{Id, Key};
+use crate::Error;
+use crate::INTERNAL_ERROR_MSG;
+
+/// Container for parse results.
+///
+/// Used to get information about the arguments that were supplied to the program at runtime by
+/// the user. New instances of this struct are obtained by using the [`Command::get_matches`] family of
+/// methods.
+///
+/// # Examples
+///
+/// ```no_run
+/// # use clap::{Command, Arg, ValueSource};
+/// let matches = Command::new("MyApp")
+/// .arg(Arg::new("out")
+/// .long("output")
+/// .required(true)
+/// .takes_value(true)
+/// .default_value("-"))
+/// .arg(Arg::new("cfg")
+/// .short('c')
+/// .takes_value(true))
+/// .get_matches(); // builds the instance of ArgMatches
+///
+/// // to get information about the "cfg" argument we created, such as the value supplied we use
+/// // various ArgMatches methods, such as [ArgMatches::get_one]
+/// if let Some(c) = matches.get_one::<String>("cfg") {
+/// println!("Value for -c: {}", c);
+/// }
+///
+/// // The ArgMatches::get_one method returns an Option because the user may not have supplied
+/// // that argument at runtime. But if we specified that the argument was "required" as we did
+/// // with the "out" argument, we can safely unwrap because `clap` verifies that was actually
+/// // used at runtime.
+/// println!("Value for --output: {}", matches.get_one::<String>("out").unwrap());
+///
+/// // You can check the presence of an argument's values
+/// if matches.contains_id("out") {
+/// // However, if you want to know where the value came from
+/// if matches.value_source("out").expect("checked contains_id") == ValueSource::CommandLine {
+/// println!("`out` set by user");
+/// } else {
+/// println!("`out` is defaulted");
+/// }
+/// }
+/// ```
+/// [`Command::get_matches`]: crate::Command::get_matches()
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
+pub struct ArgMatches {
+ #[cfg(debug_assertions)]
+ pub(crate) valid_args: Vec<Id>,
+ #[cfg(debug_assertions)]
+ pub(crate) valid_subcommands: Vec<Id>,
+ #[cfg(debug_assertions)]
+ pub(crate) disable_asserts: bool,
+ pub(crate) args: IndexMap<Id, MatchedArg>,
+ pub(crate) subcommand: Option<Box<SubCommand>>,
+}
+
+/// # Arguments
+impl ArgMatches {
+ /// Gets the value of a specific option or positional argument.
+ ///
+ /// i.e. an argument that [takes an additional value][crate::Arg::takes_value] at runtime.
+ ///
+ /// Returns an error if the wrong type was used.
+ ///
+ /// Returns `None` if the option wasn't present.
+ ///
+ /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set.
+ /// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
+ ///
+ /// # Panic
+ ///
+ /// If the argument definition and access mismatch. To handle this case programmatically, see
+ /// [`ArgMatches::try_get_one`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, value_parser};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("port")
+ /// .value_parser(value_parser!(usize))
+ /// .takes_value(true)
+ /// .required(true))
+ /// .get_matches_from(vec!["myapp", "2020"]);
+ ///
+ /// let port: usize = *m
+ /// .get_one("port")
+ /// .expect("`port`is required");
+ /// assert_eq!(port, 2020);
+ /// ```
+ /// [option]: crate::Arg::takes_value()
+ /// [positional]: crate::Arg::index()
+ /// [`default_value`]: crate::Arg::default_value()
+ #[track_caller]
+ pub fn get_one<T: Any + Clone + Send + Sync + 'static>(&self, id: &str) -> Option<&T> {
+ let internal_id = Id::from(id);
+ MatchesError::unwrap(&internal_id, self.try_get_one(id))
+ }
+
+ /// Gets the value of a specific [`ArgAction::Count`][crate::ArgAction::Count] flag
+ ///
+ /// # Panic
+ ///
+ /// If the argument's action is not [`ArgAction::Count`][crate::ArgAction::Count]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Command;
+ /// # use clap::Arg;
+ /// let cmd = Command::new("mycmd")
+ /// .arg(
+ /// Arg::new("flag")
+ /// .long("flag")
+ /// .action(clap::ArgAction::Count)
+ /// );
+ ///
+ /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
+ /// assert_eq!(
+ /// matches.get_count("flag"),
+ /// 2
+ /// );
+ /// ```
+ #[track_caller]
+ pub fn get_count(&self, id: &str) -> u8 {
+ *self
+ .get_one::<u8>(id)
+ .expect("ArgAction::Count is defaulted")
+ }
+
+ /// Gets the value of a specific [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse] flag
+ ///
+ /// # Panic
+ ///
+ /// If the argument's action is not [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Command;
+ /// # use clap::Arg;
+ /// let cmd = Command::new("mycmd")
+ /// .arg(
+ /// Arg::new("flag")
+ /// .long("flag")
+ /// .action(clap::ArgAction::SetTrue)
+ /// );
+ ///
+ /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
+ /// assert!(matches.contains_id("flag"));
+ /// assert_eq!(
+ /// matches.get_flag("flag"),
+ /// true
+ /// );
+ /// ```
+ #[track_caller]
+ pub fn get_flag(&self, id: &str) -> bool {
+ *self
+ .get_one::<bool>(id)
+ .expect("ArgAction::SetTrue / ArgAction::SetFalse is defaulted")
+ }
+
+ /// Iterate over values of a specific option or positional argument.
+ ///
+ /// i.e. an argument that takes multiple values at runtime.
+ ///
+ /// Returns an error if the wrong type was used.
+ ///
+ /// Returns `None` if the option wasn't present.
+ ///
+ /// # Panic
+ ///
+ /// If the argument definition and access mismatch. To handle this case programmatically, see
+ /// [`ArgMatches::try_get_many`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, value_parser, ArgAction};
+ /// let m = Command::new("myprog")
+ /// .arg(Arg::new("ports")
+ /// .action(ArgAction::Append)
+ /// .value_parser(value_parser!(usize))
+ /// .short('p')
+ /// .takes_value(true)
+ /// .required(true))
+ /// .get_matches_from(vec![
+ /// "myprog", "-p", "22", "-p", "80", "-p", "2020"
+ /// ]);
+ /// let vals: Vec<usize> = m.get_many("ports")
+ /// .expect("`port`is required")
+ /// .copied()
+ /// .collect();
+ /// assert_eq!(vals, [22, 80, 2020]);
+ /// ```
+ #[track_caller]
+ pub fn get_many<T: Any + Clone + Send + Sync + 'static>(
+ &self,
+ id: &str,
+ ) -> Option<ValuesRef<T>> {
+ let internal_id = Id::from(id);
+ MatchesError::unwrap(&internal_id, self.try_get_many(id))
+ }
+
+ /// Iterate over the original argument values.
+ ///
+ /// An `OsStr` on Unix-like systems is any series of bytes, regardless of whether or not they
+ /// contain valid UTF-8. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid
+ /// filename on a Unix system as an argument value may contain invalid UTF-8.
+ ///
+ /// Returns `None` if the option wasn't present.
+ ///
+ /// # Panic
+ ///
+ /// If the argument definition and access mismatch. To handle this case programmatically, see
+ /// [`ArgMatches::try_get_raw`].
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{Command, arg, value_parser};
+ /// # use std::ffi::{OsStr,OsString};
+ /// # use std::os::unix::ffi::{OsStrExt,OsStringExt};
+ /// use std::path::PathBuf;
+ ///
+ /// let m = Command::new("utf8")
+ /// .arg(arg!(<arg> ... "some arg").value_parser(value_parser!(PathBuf)))
+ /// .get_matches_from(vec![OsString::from("myprog"),
+ /// // "Hi"
+ /// OsString::from_vec(vec![b'H', b'i']),
+ /// // "{0xe9}!"
+ /// OsString::from_vec(vec![0xe9, b'!'])]);
+ ///
+ /// let mut itr = m.get_raw("arg")
+ /// .expect("`port`is required")
+ /// .into_iter();
+ /// assert_eq!(itr.next(), Some(OsStr::new("Hi")));
+ /// assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!'])));
+ /// assert_eq!(itr.next(), None);
+ /// ```
+ /// [`Iterator`]: std::iter::Iterator
+ /// [`OsSt`]: std::ffi::OsStr
+ /// [values]: OsValues
+ /// [`String`]: std::string::String
+ #[track_caller]
+ pub fn get_raw(&self, id: &str) -> Option<RawValues<'_>> {
+ let internal_id = Id::from(id);
+ MatchesError::unwrap(&internal_id, self.try_get_raw(id))
+ }
+
+ /// Returns the value of a specific option or positional argument.
+ ///
+ /// i.e. an argument that [takes an additional value][crate::Arg::takes_value] at runtime.
+ ///
+ /// Returns an error if the wrong type was used. No item will have been removed.
+ ///
+ /// Returns `None` if the option wasn't present.
+ ///
+ /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set.
+ /// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
+ ///
+ /// # Panic
+ ///
+ /// If the argument definition and access mismatch. To handle this case programmatically, see
+ /// [`ArgMatches::try_remove_one`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, value_parser};
+ /// let mut m = Command::new("myprog")
+ /// .arg(Arg::new("file")
+ /// .required(true)
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "myprog", "file.txt",
+ /// ]);
+ /// let vals: String = m.remove_one("file")
+ /// .expect("`file`is required");
+ /// assert_eq!(vals, "file.txt");
+ /// ```
+ /// [option]: crate::Arg::takes_value()
+ /// [positional]: crate::Arg::index()
+ /// [`default_value`]: crate::Arg::default_value()
+ #[track_caller]
+ pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(&mut self, id: &str) -> Option<T> {
+ let internal_id = Id::from(id);
+ MatchesError::unwrap(&internal_id, self.try_remove_one(id))
+ }
+
+ /// Return values of a specific option or positional argument.
+ ///
+ /// i.e. an argument that takes multiple values at runtime.
+ ///
+ /// Returns an error if the wrong type was used. No item will have been removed.
+ ///
+ /// Returns `None` if the option wasn't present.
+ ///
+ /// # Panic
+ ///
+ /// If the argument definition and access mismatch. To handle this case programmatically, see
+ /// [`ArgMatches::try_remove_many`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, value_parser, ArgAction};
+ /// let mut m = Command::new("myprog")
+ /// .arg(Arg::new("file")
+ /// .action(ArgAction::Append)
+ /// .multiple_values(true)
+ /// .required(true)
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "myprog", "file1.txt", "file2.txt", "file3.txt", "file4.txt",
+ /// ]);
+ /// let vals: Vec<String> = m.remove_many("file")
+ /// .expect("`file`is required")
+ /// .collect();
+ /// assert_eq!(vals, ["file1.txt", "file2.txt", "file3.txt", "file4.txt"]);
+ /// ```
+ #[track_caller]
+ pub fn remove_many<T: Any + Clone + Send + Sync + 'static>(
+ &mut self,
+ id: &str,
+ ) -> Option<Values2<T>> {
+ let internal_id = Id::from(id);
+ MatchesError::unwrap(&internal_id, self.try_remove_many(id))
+ }
+
+ /// Check if values are present for the argument or group id
+ ///
+ /// *NOTE:* This will always return `true` if [`default_value`] has been set.
+ /// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
+ ///
+ /// # Panics
+ ///
+ /// If `id` is is not a valid argument or group name. To handle this case programmatically, see
+ /// [`ArgMatches::try_contains_id`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myprog")
+ /// .arg(Arg::new("debug")
+ /// .short('d'))
+ /// .get_matches_from(vec![
+ /// "myprog", "-d"
+ /// ]);
+ ///
+ /// assert!(m.contains_id("debug"));
+ /// ```
+ ///
+ /// [`default_value`]: crate::Arg::default_value()
+ pub fn contains_id(&self, id: &str) -> bool {
+ let internal_id = Id::from(id);
+ MatchesError::unwrap(&internal_id, self.try_contains_id(id))
+ }
+
+ /// Check if any args were present on the command line
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let mut cmd = Command::new("myapp")
+ /// .arg(Arg::new("output")
+ /// .takes_value(true));
+ ///
+ /// let m = cmd
+ /// .try_get_matches_from_mut(vec!["myapp", "something"])
+ /// .unwrap();
+ /// assert!(m.args_present());
+ ///
+ /// let m = cmd
+ /// .try_get_matches_from_mut(vec!["myapp"])
+ /// .unwrap();
+ /// assert!(! m.args_present());
+ pub fn args_present(&self) -> bool {
+ !self.args.is_empty()
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_one()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = unwrap_string_arg(&id, arg.first()?);
+ Some(v)
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_one()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> {
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = unwrap_os_string_arg(&id, arg.first()?);
+ Some(v.to_string_lossy())
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_one()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> {
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = unwrap_os_string_arg(&id, arg.first()?);
+ Some(v)
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_many()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn values_of<T: Key>(&self, id: T) -> Option<Values> {
+ #![allow(deprecated)]
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = Values {
+ iter: arg.vals_flatten().map(unwrap_string),
+ len: arg.num_vals(),
+ };
+ Some(v)
+ }
+
+ /// Get an [`Iterator`] over groups of values of a specific option.
+ ///
+ /// specifically grouped by the occurrences of the options.
+ ///
+ /// Each group is a `Vec<&str>` containing the arguments passed to a single occurrence
+ /// of the option.
+ ///
+ /// If the option doesn't support multiple occurrences, or there was only a single occurrence,
+ /// the iterator will only contain a single item.
+ ///
+ /// Returns `None` if the option wasn't present.
+ ///
+ /// # Panics
+ ///
+ /// If the value is invalid UTF-8.
+ ///
+ /// If `id` is not a valid argument or group id.
+ ///
+ /// # Examples
+ /// ```rust
+ /// # use clap::{Command,Arg, ArgAction};
+ /// let m = Command::new("myprog")
+ /// .arg(Arg::new("exec")
+ /// .short('x')
+ /// .min_values(1)
+ /// .action(ArgAction::Append)
+ /// .value_terminator(";"))
+ /// .get_matches_from(vec![
+ /// "myprog", "-x", "echo", "hi", ";", "-x", "echo", "bye"]);
+ /// let vals: Vec<Vec<&str>> = m.grouped_values_of("exec").unwrap().collect();
+ /// assert_eq!(vals, [["echo", "hi"], ["echo", "bye"]]);
+ /// ```
+ /// [`Iterator`]: std::iter::Iterator
+ #[cfg(feature = "unstable-grouped")]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn grouped_values_of<T: Key>(&self, id: T) -> Option<GroupedValues> {
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = GroupedValues {
+ iter: arg.vals().map(|g| g.iter().map(unwrap_string).collect()),
+ len: arg.vals().len(),
+ };
+ Some(v)
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_many()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn values_of_lossy<T: Key>(&self, id: T) -> Option<Vec<String>> {
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = arg
+ .vals_flatten()
+ .map(|v| unwrap_os_string_arg(&id, v).to_string_lossy().into_owned())
+ .collect();
+ Some(v)
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_many()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn values_of_os<T: Key>(&self, id: T) -> Option<OsValues> {
+ #![allow(deprecated)]
+ let id = Id::from(id);
+ let arg = self.get_arg(&id)?;
+ let v = OsValues {
+ iter: arg.vals_flatten().map(unwrap_os_string),
+ len: arg.num_vals(),
+ };
+ Some(v)
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_one()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn value_of_t<R>(&self, name: &str) -> Result<R, Error>
+ where
+ R: FromStr,
+ <R as FromStr>::Err: Display,
+ {
+ #![allow(deprecated)]
+ let v = self
+ .value_of(name)
+ .ok_or_else(|| Error::argument_not_found_auto(name.to_string()))?;
+ v.parse::<R>().map_err(|e| {
+ let message = format!(
+ "The argument '{}' isn't a valid value for '{}': {}",
+ v, name, e
+ );
+
+ Error::value_validation(name.to_string(), v.to_string(), message.into())
+ })
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_one()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn value_of_t_or_exit<R>(&self, name: &str) -> R
+ where
+ R: FromStr,
+ <R as FromStr>::Err: Display,
+ {
+ #![allow(deprecated)]
+ self.value_of_t(name).unwrap_or_else(|e| e.exit())
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_many()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn values_of_t<R>(&self, name: &str) -> Result<Vec<R>, Error>
+ where
+ R: FromStr,
+ <R as FromStr>::Err: Display,
+ {
+ #![allow(deprecated)]
+ let v = self
+ .values_of(name)
+ .ok_or_else(|| Error::argument_not_found_auto(name.to_string()))?;
+ v.map(|v| {
+ v.parse::<R>().map_err(|e| {
+ let message = format!("The argument '{}' isn't a valid value: {}", v, e);
+
+ Error::value_validation(name.to_string(), v.to_string(), message.into())
+ })
+ })
+ .collect()
+ }
+
+ /// Deprecated, replaced with [`ArgMatches::get_many()`]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn values_of_t_or_exit<R>(&self, name: &str) -> Vec<R>
+ where
+ R: FromStr,
+ <R as FromStr>::Err: Display,
+ {
+ #![allow(deprecated)]
+ self.values_of_t(name).unwrap_or_else(|e| e.exit())
+ }
+
+ /// Deprecated, replaced with [`ArgAction::SetTrue`][crate::ArgAction] or
+ /// [`ArgMatches::contains_id`].
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(
+ since = "3.2.0",
+ note = "Replaced with either `ArgAction::SetTrue` or `ArgMatches::contains_id(...)`"
+ )
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn is_present<T: Key>(&self, id: T) -> bool {
+ let id = Id::from(id);
+
+ #[cfg(debug_assertions)]
+ self.get_arg(&id);
+
+ self.args.contains_key(&id)
+ }
+
+ /// Report where argument value came from
+ ///
+ /// # Panics
+ ///
+ /// If `id` is is not a valid argument or group id.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, ValueSource};
+ /// let m = Command::new("myprog")
+ /// .arg(Arg::new("debug")
+ /// .short('d'))
+ /// .get_matches_from(vec![
+ /// "myprog", "-d"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_source("debug"), Some(ValueSource::CommandLine));
+ /// ```
+ ///
+ /// [`default_value`]: crate::Arg::default_value()
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn value_source<T: Key>(&self, id: T) -> Option<ValueSource> {
+ let id = Id::from(id);
+
+ let value = self.get_arg(&id);
+
+ value.and_then(MatchedArg::source)
+ }
+
+ /// Deprecated, replaced with [`ArgAction::Count`][crate::ArgAction],
+ /// [`ArgMatches::get_many`]`.len()`, or [`ArgMatches::value_source`].
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(
+ since = "3.2.0",
+ note = "Replaced with either `ArgAction::Count`, `ArgMatches::get_many(...).len()`, or `ArgMatches::value_source`"
+ )
+ )]
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
+ #![allow(deprecated)]
+ self.get_arg(&Id::from(id))
+ .map_or(0, |a| a.get_occurrences())
+ }
+
+ /// The first index of that an argument showed up.
+ ///
+ /// Indices are similar to argv indices, but are not exactly 1:1.
+ ///
+ /// For flags (i.e. those arguments which don't have an associated value), indices refer
+ /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices
+ /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the
+ /// index for `val` would be recorded. This is by design.
+ ///
+ /// Besides the flag/option discrepancy, the primary difference between an argv index and clap
+ /// index, is that clap continues counting once all arguments have properly separated, whereas
+ /// an argv index does not.
+ ///
+ /// The examples should clear this up.
+ ///
+ /// *NOTE:* If an argument is allowed multiple times, this method will only give the *first*
+ /// index. See [`ArgMatches::indices_of`].
+ ///
+ /// # Panics
+ ///
+ /// If `id` is is not a valid argument or group id.
+ ///
+ /// # Examples
+ ///
+ /// The argv indices are listed in the comments below. See how they correspond to the clap
+ /// indices. Note that if it's not listed in a clap index, this is because it's not saved in
+ /// in an `ArgMatches` struct for querying.
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("flag")
+ /// .short('f'))
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-f", "-o", "val"]);
+ /// // ARGV indices: ^0 ^1 ^2 ^3
+ /// // clap indices: ^1 ^3
+ ///
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("option"), Some(3));
+ /// ```
+ ///
+ /// Now notice, if we use one of the other styles of options:
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("flag")
+ /// .short('f'))
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-f", "-o=val"]);
+ /// // ARGV indices: ^0 ^1 ^2
+ /// // clap indices: ^1 ^3
+ ///
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("option"), Some(3));
+ /// ```
+ ///
+ /// Things become much more complicated, or clear if we look at a more complex combination of
+ /// flags. Let's also throw in the final option style for good measure.
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("flag")
+ /// .short('f'))
+ /// .arg(Arg::new("flag2")
+ /// .short('F'))
+ /// .arg(Arg::new("flag3")
+ /// .short('z'))
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-fzF", "-oval"]);
+ /// // ARGV indices: ^0 ^1 ^2
+ /// // clap indices: ^1,2,3 ^5
+ /// //
+ /// // clap sees the above as 'myapp -f -z -F -o val'
+ /// // ^0 ^1 ^2 ^3 ^4 ^5
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("flag2"), Some(3));
+ /// assert_eq!(m.index_of("flag3"), Some(2));
+ /// assert_eq!(m.index_of("option"), Some(5));
+ /// ```
+ ///
+ /// One final combination of flags/options to see how they combine:
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("flag")
+ /// .short('f'))
+ /// .arg(Arg::new("flag2")
+ /// .short('F'))
+ /// .arg(Arg::new("flag3")
+ /// .short('z'))
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-fzFoval"]);
+ /// // ARGV indices: ^0 ^1
+ /// // clap indices: ^1,2,3^5
+ /// //
+ /// // clap sees the above as 'myapp -f -z -F -o val'
+ /// // ^0 ^1 ^2 ^3 ^4 ^5
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("flag2"), Some(3));
+ /// assert_eq!(m.index_of("flag3"), Some(2));
+ /// assert_eq!(m.index_of("option"), Some(5));
+ /// ```
+ ///
+ /// The last part to mention is when values are sent in multiple groups with a [delimiter].
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .use_value_delimiter(true)
+ /// .multiple_values(true))
+ /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ /// // ARGV indices: ^0 ^1
+ /// // clap indices: ^2 ^3 ^4
+ /// //
+ /// // clap sees the above as 'myapp -o val1 val2 val3'
+ /// // ^0 ^1 ^2 ^3 ^4
+ /// assert_eq!(m.index_of("option"), Some(2));
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
+ /// ```
+ /// [delimiter]: crate::Arg::value_delimiter()
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn index_of<T: Key>(&self, id: T) -> Option<usize> {
+ let arg = self.get_arg(&Id::from(id))?;
+ let i = arg.get_index(0)?;
+ Some(i)
+ }
+
+ /// All indices an argument appeared at when parsing.
+ ///
+ /// Indices are similar to argv indices, but are not exactly 1:1.
+ ///
+ /// For flags (i.e. those arguments which don't have an associated value), indices refer
+ /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices
+ /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the
+ /// index for `val` would be recorded. This is by design.
+ ///
+ /// *NOTE:* For more information about how clap indices compared to argv indices, see
+ /// [`ArgMatches::index_of`]
+ ///
+ /// # Panics
+ ///
+ /// If `id` is is not a valid argument or group id.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .use_value_delimiter(true)
+ /// .multiple_values(true))
+ /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ /// // ARGV indices: ^0 ^1
+ /// // clap indices: ^2 ^3 ^4
+ /// //
+ /// // clap sees the above as 'myapp -o val1 val2 val3'
+ /// // ^0 ^1 ^2 ^3 ^4
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
+ /// ```
+ ///
+ /// Another quick example is when flags and options are used together
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, ArgAction};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .takes_value(true)
+ /// .action(ArgAction::Append))
+ /// .arg(Arg::new("flag")
+ /// .short('f')
+ /// .action(ArgAction::Count))
+ /// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
+ /// // ARGV indices: ^0 ^1 ^2 ^3 ^4 ^5 ^6
+ /// // clap indices: ^2 ^3 ^5 ^6
+ ///
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
+ /// assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[6]);
+ /// ```
+ ///
+ /// One final example, which is an odd case; if we *don't* use value delimiter as we did with
+ /// the first example above instead of `val1`, `val2` and `val3` all being distinc values, they
+ /// would all be a single value of `val1,val2,val3`, in which case they'd only receive a single
+ /// index.
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg};
+ /// let m = Command::new("myapp")
+ /// .arg(Arg::new("option")
+ /// .short('o')
+ /// .takes_value(true)
+ /// .multiple_values(true))
+ /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ /// // ARGV indices: ^0 ^1
+ /// // clap indices: ^2
+ /// //
+ /// // clap sees the above as 'myapp -o "val1,val2,val3"'
+ /// // ^0 ^1 ^2
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
+ /// ```
+ /// [`ArgMatches::index_of`]: ArgMatches::index_of()
+ /// [delimiter]: Arg::value_delimiter()
+ #[cfg_attr(debug_assertions, track_caller)]
+ pub fn indices_of<T: Key>(&self, id: T) -> Option<Indices<'_>> {
+ let arg = self.get_arg(&Id::from(id))?;
+ let i = Indices {
+ iter: arg.indices(),
+ len: arg.num_vals(),
+ };
+ Some(i)
+ }
+
+ #[inline]
+ #[doc(hidden)]
+ #[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::try_get_one()`")
+ )]
+ pub fn is_valid_arg(&self, _id: impl Key) -> bool {
+ #[cfg(debug_assertions)]
+ {
+ let id = Id::from(_id);
+ self.disable_asserts || id == Id::empty_hash() || self.valid_args.contains(&id)
+ }
+ #[cfg(not(debug_assertions))]
+ {
+ true
+ }
+ }
+}
+
+/// # Subcommands
+impl ArgMatches {
+ /// The name and `ArgMatches` of the current [subcommand].
+ ///
+ /// Subcommand values are put in a child [`ArgMatches`]
+ ///
+ /// Returns `None` if the subcommand wasn't present at runtime,
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{Command, Arg, };
+ /// let app_m = Command::new("git")
+ /// .subcommand(Command::new("clone"))
+ /// .subcommand(Command::new("push"))
+ /// .subcommand(Command::new("commit"))
+ /// .get_matches();
+ ///
+ /// match app_m.subcommand() {
+ /// Some(("clone", sub_m)) => {}, // clone was used
+ /// Some(("push", sub_m)) => {}, // push was used
+ /// Some(("commit", sub_m)) => {}, // commit was used
+ /// _ => {}, // Either no subcommand or one not tested for...
+ /// }
+ /// ```
+ ///
+ /// Another useful scenario is when you want to support third party, or external, subcommands.
+ /// In these cases you can't know the subcommand name ahead of time, so use a variable instead
+ /// with pattern matching!
+ ///
+ /// ```rust
+ /// # use clap::Command;
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let app_m = Command::new("myprog")
+ /// .allow_external_subcommands(true)
+ /// .get_matches_from(vec![
+ /// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
+ /// ]);
+ ///
+ /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty
+ /// // string argument name
+ /// match app_m.subcommand() {
+ /// Some((external, sub_m)) => {
+ /// let ext_args: Vec<&str> = sub_m.get_many::<String>("")
+ /// .unwrap().map(|s| s.as_str()).collect();
+ /// assert_eq!(external, "subcmd");
+ /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
+ /// },
+ /// _ => {},
+ /// }
+ /// ```
+ /// [subcommand]: crate::Command::subcommand
+ #[inline]
+ pub fn subcommand(&self) -> Option<(&str, &ArgMatches)> {
+ self.subcommand.as_ref().map(|sc| (&*sc.name, &sc.matches))
+ }
+
+ /// Return the name and `ArgMatches` of the current [subcommand].
+ ///
+ /// Subcommand values are put in a child [`ArgMatches`]
+ ///
+ /// Returns `None` if the subcommand wasn't present at runtime,
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{Command, Arg, };
+ /// let mut app_m = Command::new("git")
+ /// .subcommand(Command::new("clone"))
+ /// .subcommand(Command::new("push"))
+ /// .subcommand(Command::new("commit"))
+ /// .subcommand_required(true)
+ /// .get_matches();
+ ///
+ /// let (name, sub_m) = app_m.remove_subcommand().expect("required");
+ /// match (name.as_str(), sub_m) {
+ /// ("clone", sub_m) => {}, // clone was used
+ /// ("push", sub_m) => {}, // push was used
+ /// ("commit", sub_m) => {}, // commit was used
+ /// (name, _) => unimplemented!("{}", name),
+ /// }
+ /// ```
+ ///
+ /// Another useful scenario is when you want to support third party, or external, subcommands.
+ /// In these cases you can't know the subcommand name ahead of time, so use a variable instead
+ /// with pattern matching!
+ ///
+ /// ```rust
+ /// # use clap::Command;
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let mut app_m = Command::new("myprog")
+ /// .allow_external_subcommands(true)
+ /// .get_matches_from(vec![
+ /// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
+ /// ]);
+ ///
+ /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty
+ /// // string argument name
+ /// match app_m.remove_subcommand() {
+ /// Some((external, mut sub_m)) => {
+ /// let ext_args: Vec<String> = sub_m.remove_many("")
+ /// .expect("`file`is required")
+ /// .collect();
+ /// assert_eq!(external, "subcmd");
+ /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
+ /// },
+ /// _ => {},
+ /// }
+ /// ```
+ /// [subcommand]: crate::Command::subcommand
+ pub fn remove_subcommand(&mut self) -> Option<(String, ArgMatches)> {
+ self.subcommand.take().map(|sc| (sc.name, sc.matches))
+ }
+
+ /// The `ArgMatches` for the current [subcommand].
+ ///
+ /// Subcommand values are put in a child [`ArgMatches`]
+ ///
+ /// Returns `None` if the subcommand wasn't present at runtime,
+ ///
+ /// # Panics
+ ///
+ /// If `id` is is not a valid subcommand.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Command, Arg, ArgAction};
+ /// let app_m = Command::new("myprog")
+ /// .arg(Arg::new("debug")
+ /// .short('d')
+ /// .action(ArgAction::SetTrue)
+ /// )
+ /// .subcommand(Command::new("test")
+ /// .arg(Arg::new("opt")
+ /// .long("option")
+ /// .takes_value(true)))
+ /// .get_matches_from(vec![
+ /// "myprog", "-d", "test", "--option", "val"
+ /// ]);
+ ///
+ /// // Both parent commands, and child subcommands can have arguments present at the same times
+ /// assert!(*app_m.get_one::<bool>("debug").expect("defaulted by clap"));
+ ///
+ /// // Get the subcommand's ArgMatches instance
+ /// if let Some(sub_m) = app_m.subcommand_matches("test") {
+ /// // Use the struct like normal
+ /// assert_eq!(sub_m.get_one::<String>("opt").map(|s| s.as_str()), Some("val"));
+ /// }
+ /// ```
+ ///
+ /// [subcommand]: crate::Command::subcommand
+ /// [`Command`]: crate::Command
+ pub fn subcommand_matches<T: Key>(&self, id: T) -> Option<&ArgMatches> {
+ self.get_subcommand(&id.into()).map(|sc| &sc.matches)
+ }
+
+ /// The name of the current [subcommand].
+ ///
+ /// Returns `None` if the subcommand wasn't present at runtime,
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{Command, Arg, };
+ /// let app_m = Command::new("git")
+ /// .subcommand(Command::new("clone"))
+ /// .subcommand(Command::new("push"))
+ /// .subcommand(Command::new("commit"))
+ /// .get_matches();
+ ///
+ /// match app_m.subcommand_name() {
+ /// Some("clone") => {}, // clone was used
+ /// Some("push") => {}, // push was used
+ /// Some("commit") => {}, // commit was used
+ /// _ => {}, // Either no subcommand or one not tested for...
+ /// }
+ /// ```
+ /// [subcommand]: crate::Command::subcommand
+ /// [`Command`]: crate::Command
+ #[inline]
+ pub fn subcommand_name(&self) -> Option<&str> {
+ self.subcommand.as_ref().map(|sc| &*sc.name)
+ }
+
+ /// Check if a subcommand can be queried
+ ///
+ /// By default, `ArgMatches` functions assert on undefined `Id`s to help catch programmer
+ /// mistakes. In some context, this doesn't work, so users can use this function to check
+ /// before they do a query on `ArgMatches`.
+ #[inline]
+ #[doc(hidden)]
+ pub fn is_valid_subcommand(&self, _id: impl Key) -> bool {
+ #[cfg(debug_assertions)]
+ {
+ let id = Id::from(_id);
+ self.disable_asserts || id == Id::empty_hash() || self.valid_subcommands.contains(&id)
+ }
+ #[cfg(not(debug_assertions))]
+ {
+ true
+ }
+ }
+}
+
+/// # Advanced
+impl ArgMatches {
+ /// Non-panicking version of [`ArgMatches::get_one`]
+ pub fn try_get_one<T: Any + Clone + Send + Sync + 'static>(
+ &self,
+ id: &str,
+ ) -> Result<Option<&T>, MatchesError> {
+ let id = Id::from(id);
+ let arg = self.try_get_arg_t::<T>(&id)?;
+ let value = match arg.and_then(|a| a.first()) {
+ Some(value) => value,
+ None => {
+ return Ok(None);
+ }
+ };
+ Ok(value
+ .downcast_ref::<T>()
+ .map(Some)
+ .expect(INTERNAL_ERROR_MSG)) // enforced by `try_get_arg_t`
+ }
+
+ /// Non-panicking version of [`ArgMatches::get_many`]
+ pub fn try_get_many<T: Any + Clone + Send + Sync + 'static>(
+ &self,
+ id: &str,
+ ) -> Result<Option<ValuesRef<T>>, MatchesError> {
+ let id = Id::from(id);
+ let arg = match self.try_get_arg_t::<T>(&id)? {
+ Some(arg) => arg,
+ None => return Ok(None),
+ };
+ let len = arg.num_vals();
+ let values = arg.vals_flatten();
+ let values = ValuesRef {
+ // enforced by `try_get_arg_t`
+ iter: values.map(|v| v.downcast_ref::<T>().expect(INTERNAL_ERROR_MSG)),
+ len,
+ };
+ Ok(Some(values))
+ }
+
+ /// Non-panicking version of [`ArgMatches::get_raw`]
+ pub fn try_get_raw(&self, id: &str) -> Result<Option<RawValues<'_>>, MatchesError> {
+ let id = Id::from(id);
+ let arg = match self.try_get_arg(&id)? {
+ Some(arg) => arg,
+ None => return Ok(None),
+ };
+ let len = arg.num_vals();
+ let values = arg.raw_vals_flatten();
+ let values = RawValues {
+ iter: values.map(OsString::as_os_str),
+ len,
+ };
+ Ok(Some(values))
+ }
+
+ /// Non-panicking version of [`ArgMatches::remove_one`]
+ pub fn try_remove_one<T: Any + Clone + Send + Sync + 'static>(
+ &mut self,
+ id: &str,
+ ) -> Result<Option<T>, MatchesError> {
+ let id = Id::from(id);
+ match self.try_remove_arg_t::<T>(&id)? {
+ Some(values) => Ok(values
+ .into_vals_flatten()
+ // enforced by `try_get_arg_t`
+ .map(|v| v.downcast_into::<T>().expect(INTERNAL_ERROR_MSG))
+ .next()),
+ None => Ok(None),
+ }
+ }
+
+ /// Non-panicking version of [`ArgMatches::remove_many`]
+ pub fn try_remove_many<T: Any + Clone + Send + Sync + 'static>(
+ &mut self,
+ id: &str,
+ ) -> Result<Option<Values2<T>>, MatchesError> {
+ let id = Id::from(id);
+ let arg = match self.try_remove_arg_t::<T>(&id)? {
+ Some(arg) => arg,
+ None => return Ok(None),
+ };
+ let len = arg.num_vals();
+ let values = arg.into_vals_flatten();
+ let values = Values2 {
+ // enforced by `try_get_arg_t`
+ iter: values.map(|v| v.downcast_into::<T>().expect(INTERNAL_ERROR_MSG)),
+ len,
+ };
+ Ok(Some(values))
+ }
+
+ /// Non-panicking version of [`ArgMatches::contains_id`]
+ pub fn try_contains_id(&self, id: &str) -> Result<bool, MatchesError> {
+ let id = Id::from(id);
+
+ self.verify_arg(&id)?;
+
+ let presence = self.args.contains_key(&id);
+ Ok(presence)
+ }
+}
+
+// Private methods
+impl ArgMatches {
+ #[inline]
+ fn try_get_arg(&self, arg: &Id) -> Result<Option<&MatchedArg>, MatchesError> {
+ self.verify_arg(arg)?;
+ Ok(self.args.get(arg))
+ }
+
+ #[inline]
+ fn try_get_arg_t<T: Any + Send + Sync + 'static>(
+ &self,
+ arg: &Id,
+ ) -> Result<Option<&MatchedArg>, MatchesError> {
+ let arg = match self.try_get_arg(arg)? {
+ Some(arg) => arg,
+ None => {
+ return Ok(None);
+ }
+ };
+ self.verify_arg_t::<T>(arg)?;
+ Ok(Some(arg))
+ }
+
+ #[inline]
+ fn try_remove_arg_t<T: Any + Send + Sync + 'static>(
+ &mut self,
+ arg: &Id,
+ ) -> Result<Option<MatchedArg>, MatchesError> {
+ self.verify_arg(arg)?;
+ let matched = match self.args.remove(arg) {
+ Some(matched) => matched,
+ None => {
+ return Ok(None);
+ }
+ };
+
+ let expected = AnyValueId::of::<T>();
+ let actual = matched.infer_type_id(expected);
+ if actual == expected {
+ Ok(Some(matched))
+ } else {
+ self.args.insert(arg.clone(), matched);
+ Err(MatchesError::Downcast { actual, expected })
+ }
+ }
+
+ fn verify_arg_t<T: Any + Send + Sync + 'static>(
+ &self,
+ arg: &MatchedArg,
+ ) -> Result<(), MatchesError> {
+ let expected = AnyValueId::of::<T>();
+ let actual = arg.infer_type_id(expected);
+ if expected == actual {
+ Ok(())
+ } else {
+ Err(MatchesError::Downcast { actual, expected })
+ }
+ }
+
+ #[inline]
+ fn verify_arg(&self, _arg: &Id) -> Result<(), MatchesError> {
+ #[cfg(debug_assertions)]
+ {
+ if self.disable_asserts || *_arg == Id::empty_hash() || self.valid_args.contains(_arg) {
+ } else if self.valid_subcommands.contains(_arg) {
+ debug!(
+ "Subcommand `{:?}` used where an argument or group name was expected.",
+ _arg
+ );
+ return Err(MatchesError::UnknownArgument {});
+ } else {
+ debug!(
+ "`{:?}` is not an id of an argument or a group.\n\
+ Make sure you're using the name of the argument itself \
+ and not the name of short or long flags.",
+ _arg
+ );
+ return Err(MatchesError::UnknownArgument {});
+ }
+ }
+ Ok(())
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn get_arg(&self, arg: &Id) -> Option<&MatchedArg> {
+ #[cfg(debug_assertions)]
+ {
+ if self.disable_asserts || *arg == Id::empty_hash() || self.valid_args.contains(arg) {
+ } else if self.valid_subcommands.contains(arg) {
+ panic!(
+ "Subcommand `{:?}` used where an argument or group name was expected.",
+ arg
+ );
+ } else {
+ panic!(
+ "`{:?}` is not an id of an argument or a group.\n\
+ Make sure you're using the name of the argument itself \
+ and not the name of short or long flags.",
+ arg
+ );
+ }
+ }
+
+ self.args.get(arg)
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn get_subcommand(&self, id: &Id) -> Option<&SubCommand> {
+ #[cfg(debug_assertions)]
+ {
+ if self.disable_asserts
+ || *id == Id::empty_hash()
+ || self.valid_subcommands.contains(id)
+ {
+ } else if self.valid_args.contains(id) {
+ panic!(
+ "Argument or group `{:?}` used where a subcommand name was expected.",
+ id
+ );
+ } else {
+ panic!("`{:?}` is not a name of a subcommand.", id);
+ }
+ }
+
+ if let Some(ref sc) = self.subcommand {
+ if sc.id == *id {
+ return Some(sc);
+ }
+ }
+
+ None
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct SubCommand {
+ pub(crate) id: Id,
+ pub(crate) name: String,
+ pub(crate) matches: ArgMatches,
+}
+
+/// Iterate over multiple values for an argument via [`ArgMatches::remove_many`].
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::{Command, Arg, ArgAction};
+/// let mut m = Command::new("myapp")
+/// .arg(Arg::new("output")
+/// .short('o')
+/// .action(ArgAction::Append)
+/// .takes_value(true))
+/// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]);
+///
+/// let mut values = m.remove_many::<String>("output")
+/// .unwrap();
+///
+/// assert_eq!(values.next(), Some(String::from("val1")));
+/// assert_eq!(values.next(), Some(String::from("val2")));
+/// assert_eq!(values.next(), None);
+/// ```
+#[derive(Clone, Debug)]
+pub struct Values2<T> {
+ #[allow(clippy::type_complexity)]
+ iter: Map<Flatten<std::vec::IntoIter<Vec<AnyValue>>>, fn(AnyValue) -> T>,
+ len: usize,
+}
+
+impl<T> Iterator for Values2<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+impl<T> DoubleEndedIterator for Values2<T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.iter.next_back()
+ }
+}
+
+impl<T> ExactSizeIterator for Values2<T> {}
+
+/// Creates an empty iterator.
+impl<T> Default for Values2<T> {
+ fn default() -> Self {
+ let empty: Vec<Vec<AnyValue>> = Default::default();
+ Values2 {
+ iter: empty.into_iter().flatten().map(|_| unreachable!()),
+ len: 0,
+ }
+ }
+}
+
+/// Iterate over multiple values for an argument via [`ArgMatches::get_many`].
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::{Command, Arg, ArgAction};
+/// let m = Command::new("myapp")
+/// .arg(Arg::new("output")
+/// .short('o')
+/// .action(ArgAction::Append)
+/// .takes_value(true))
+/// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]);
+///
+/// let mut values = m.get_many::<String>("output")
+/// .unwrap()
+/// .map(|s| s.as_str());
+///
+/// assert_eq!(values.next(), Some("val1"));
+/// assert_eq!(values.next(), Some("val2"));
+/// assert_eq!(values.next(), None);
+/// ```
+#[derive(Clone, Debug)]
+pub struct ValuesRef<'a, T> {
+ #[allow(clippy::type_complexity)]
+ iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, fn(&AnyValue) -> &T>,
+ len: usize,
+}
+
+impl<'a, T: 'a> Iterator for ValuesRef<'a, T> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+impl<'a, T: 'a> DoubleEndedIterator for ValuesRef<'a, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.iter.next_back()
+ }
+}
+
+impl<'a, T: 'a> ExactSizeIterator for ValuesRef<'a, T> {}
+
+/// Creates an empty iterator.
+impl<'a, T: 'a> Default for ValuesRef<'a, T> {
+ fn default() -> Self {
+ static EMPTY: [Vec<AnyValue>; 0] = [];
+ ValuesRef {
+ iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
+ len: 0,
+ }
+ }
+}
+
+/// Iterate over raw argument values via [`ArgMatches::get_raw`].
+///
+/// # Examples
+///
+#[cfg_attr(not(unix), doc = " ```ignore")]
+#[cfg_attr(unix, doc = " ```")]
+/// # use clap::{Command, arg, value_parser};
+/// use std::ffi::OsString;
+/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
+///
+/// let m = Command::new("utf8")
+/// .arg(arg!(<arg> "some arg")
+/// .value_parser(value_parser!(OsString)))
+/// .get_matches_from(vec![OsString::from("myprog"),
+/// // "Hi {0xe9}!"
+/// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
+/// assert_eq!(
+/// &*m.get_raw("arg")
+/// .unwrap()
+/// .next().unwrap()
+/// .as_bytes(),
+/// [b'H', b'i', b' ', 0xe9, b'!']
+/// );
+/// ```
+#[derive(Clone, Debug)]
+pub struct RawValues<'a> {
+ #[allow(clippy::type_complexity)]
+ iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
+ len: usize,
+}
+
+impl<'a> Iterator for RawValues<'a> {
+ type Item = &'a OsStr;
+
+ fn next(&mut self) -> Option<&'a OsStr> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+impl<'a> DoubleEndedIterator for RawValues<'a> {
+ fn next_back(&mut self) -> Option<&'a OsStr> {
+ self.iter.next_back()
+ }
+}
+
+impl<'a> ExactSizeIterator for RawValues<'a> {}
+
+/// Creates an empty iterator.
+impl Default for RawValues<'_> {
+ fn default() -> Self {
+ static EMPTY: [Vec<OsString>; 0] = [];
+ RawValues {
+ iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
+ len: 0,
+ }
+ }
+}
+
+// The following were taken and adapted from vec_map source
+// repo: https://github.com/contain-rs/vec-map
+// commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33
+// license: MIT - Copyright (c) 2015 The Rust Project Developers
+
+/// Deprecated, replaced with [`ArgMatches::get_many()`]
+#[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+)]
+#[derive(Clone, Debug)]
+pub struct Values<'a> {
+ #[allow(clippy::type_complexity)]
+ iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, for<'r> fn(&'r AnyValue) -> &'r str>,
+ len: usize,
+}
+
+#[allow(deprecated)]
+impl<'a> Iterator for Values<'a> {
+ type Item = &'a str;
+
+ fn next(&mut self) -> Option<&'a str> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+#[allow(deprecated)]
+impl<'a> DoubleEndedIterator for Values<'a> {
+ fn next_back(&mut self) -> Option<&'a str> {
+ self.iter.next_back()
+ }
+}
+
+#[allow(deprecated)]
+impl<'a> ExactSizeIterator for Values<'a> {}
+
+/// Creates an empty iterator.
+#[allow(deprecated)]
+impl<'a> Default for Values<'a> {
+ fn default() -> Self {
+ static EMPTY: [Vec<AnyValue>; 0] = [];
+ Values {
+ iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
+ len: 0,
+ }
+ }
+}
+
+#[derive(Clone)]
+#[allow(missing_debug_implementations)]
+pub struct GroupedValues<'a> {
+ #[allow(clippy::type_complexity)]
+ iter: Map<Iter<'a, Vec<AnyValue>>, fn(&Vec<AnyValue>) -> Vec<&str>>,
+ len: usize,
+}
+
+impl<'a> Iterator for GroupedValues<'a> {
+ type Item = Vec<&'a str>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+impl<'a> DoubleEndedIterator for GroupedValues<'a> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.iter.next_back()
+ }
+}
+
+impl<'a> ExactSizeIterator for GroupedValues<'a> {}
+
+/// Creates an empty iterator. Used for `unwrap_or_default()`.
+impl<'a> Default for GroupedValues<'a> {
+ fn default() -> Self {
+ #![allow(deprecated)]
+ static EMPTY: [Vec<AnyValue>; 0] = [];
+ GroupedValues {
+ iter: EMPTY[..].iter().map(|_| unreachable!()),
+ len: 0,
+ }
+ }
+}
+
+/// Deprecated, replaced with [`ArgMatches::get_many()`]
+#[cfg_attr(
+ feature = "deprecated",
+ deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
+)]
+#[derive(Clone, Debug)]
+pub struct OsValues<'a> {
+ #[allow(clippy::type_complexity)]
+ iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, fn(&AnyValue) -> &OsStr>,
+ len: usize,
+}
+
+#[allow(deprecated)]
+impl<'a> Iterator for OsValues<'a> {
+ type Item = &'a OsStr;
+
+ fn next(&mut self) -> Option<&'a OsStr> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+#[allow(deprecated)]
+impl<'a> DoubleEndedIterator for OsValues<'a> {
+ fn next_back(&mut self) -> Option<&'a OsStr> {
+ self.iter.next_back()
+ }
+}
+
+#[allow(deprecated)]
+impl<'a> ExactSizeIterator for OsValues<'a> {}
+
+/// Creates an empty iterator.
+#[allow(deprecated)]
+impl Default for OsValues<'_> {
+ fn default() -> Self {
+ static EMPTY: [Vec<AnyValue>; 0] = [];
+ OsValues {
+ iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
+ len: 0,
+ }
+ }
+}
+
+/// Iterate over indices for where an argument appeared when parsing, via [`ArgMatches::indices_of`]
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::{Command, Arg};
+/// let m = Command::new("myapp")
+/// .arg(Arg::new("output")
+/// .short('o')
+/// .multiple_values(true)
+/// .takes_value(true))
+/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]);
+///
+/// let mut indices = m.indices_of("output").unwrap();
+///
+/// assert_eq!(indices.next(), Some(2));
+/// assert_eq!(indices.next(), Some(3));
+/// assert_eq!(indices.next(), None);
+/// ```
+/// [`ArgMatches::indices_of`]: ArgMatches::indices_of()
+#[derive(Clone, Debug)]
+pub struct Indices<'a> {
+ iter: Cloned<Iter<'a, usize>>,
+ len: usize,
+}
+
+impl<'a> Iterator for Indices<'a> {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<usize> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+}
+
+impl<'a> DoubleEndedIterator for Indices<'a> {
+ fn next_back(&mut self) -> Option<usize> {
+ self.iter.next_back()
+ }
+}
+
+impl<'a> ExactSizeIterator for Indices<'a> {}
+
+/// Creates an empty iterator.
+impl<'a> Default for Indices<'a> {
+ fn default() -> Self {
+ static EMPTY: [usize; 0] = [];
+ // This is never called because the iterator is empty:
+ Indices {
+ iter: EMPTY[..].iter().cloned(),
+ len: 0,
+ }
+ }
+}
+
+#[cfg_attr(debug_assertions, track_caller)]
+#[inline]
+fn unwrap_string(value: &AnyValue) -> &str {
+ match value.downcast_ref::<String>() {
+ Some(value) => value,
+ None => {
+ panic!("Must use `_os` lookups with `Arg::allow_invalid_utf8`",)
+ }
+ }
+}
+
+#[cfg_attr(debug_assertions, track_caller)]
+#[inline]
+fn unwrap_string_arg<'v>(id: &Id, value: &'v AnyValue) -> &'v str {
+ match value.downcast_ref::<String>() {
+ Some(value) => value,
+ None => {
+ panic!(
+ "Must use `_os` lookups with `Arg::allow_invalid_utf8` at `{:?}`",
+ id
+ )
+ }
+ }
+}
+
+#[cfg_attr(debug_assertions, track_caller)]
+#[inline]
+fn unwrap_os_string(value: &AnyValue) -> &OsStr {
+ match value.downcast_ref::<OsString>() {
+ Some(value) => value,
+ None => {
+ panic!("Must use `Arg::allow_invalid_utf8` with `_os` lookups",)
+ }
+ }
+}
+
+#[cfg_attr(debug_assertions, track_caller)]
+#[inline]
+fn unwrap_os_string_arg<'v>(id: &Id, value: &'v AnyValue) -> &'v OsStr {
+ match value.downcast_ref::<OsString>() {
+ Some(value) => value,
+ None => {
+ panic!(
+ "Must use `Arg::allow_invalid_utf8` with `_os` lookups at `{:?}`",
+ id
+ )
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn check_auto_traits() {
+ static_assertions::assert_impl_all!(ArgMatches: Send, Sync, Unpin);
+ }
+
+ #[test]
+ fn test_default_values() {
+ #![allow(deprecated)]
+ let mut values: Values = Values::default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_osvalues() {
+ #![allow(deprecated)]
+ let mut values: OsValues = OsValues::default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_raw_values() {
+ let mut values: RawValues = Default::default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_indices() {
+ let mut indices: Indices = Indices::default();
+ assert_eq!(indices.next(), None);
+ }
+
+ #[test]
+ fn test_default_indices_with_shorter_lifetime() {
+ let matches = ArgMatches::default();
+ let mut indices = matches.indices_of("").unwrap_or_default();
+ assert_eq!(indices.next(), None);
+ }
+
+ #[test]
+ fn values_exact_size() {
+ let l = crate::Command::new("test")
+ .arg(
+ crate::Arg::new("POTATO")
+ .takes_value(true)
+ .multiple_values(true)
+ .required(true),
+ )
+ .try_get_matches_from(["test", "one"])
+ .unwrap()
+ .get_many::<String>("POTATO")
+ .expect("present")
+ .count();
+ assert_eq!(l, 1);
+ }
+
+ #[test]
+ fn os_values_exact_size() {
+ let l = crate::Command::new("test")
+ .arg(
+ crate::Arg::new("POTATO")
+ .takes_value(true)
+ .multiple_values(true)
+ .value_parser(crate::builder::ValueParser::os_string())
+ .required(true),
+ )
+ .try_get_matches_from(["test", "one"])
+ .unwrap()
+ .get_many::<std::ffi::OsString>("POTATO")
+ .expect("present")
+ .count();
+ assert_eq!(l, 1);
+ }
+
+ #[test]
+ fn indices_exact_size() {
+ let l = crate::Command::new("test")
+ .arg(
+ crate::Arg::new("POTATO")
+ .takes_value(true)
+ .multiple_values(true)
+ .required(true),
+ )
+ .try_get_matches_from(["test", "one"])
+ .unwrap()
+ .indices_of("POTATO")
+ .expect("present")
+ .len();
+ assert_eq!(l, 1);
+ }
+}
diff --git a/vendor/clap-3.2.20/src/parser/matches/matched_arg.rs b/vendor/clap-3.2.20/src/parser/matches/matched_arg.rs
new file mode 100644
index 000000000..fde6d37f3
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/matches/matched_arg.rs
@@ -0,0 +1,240 @@
+// Std
+use std::{
+ ffi::{OsStr, OsString},
+ iter::{Cloned, Flatten},
+ slice::Iter,
+};
+
+use crate::builder::ArgPredicate;
+use crate::parser::AnyValue;
+use crate::parser::AnyValueId;
+use crate::parser::ValueSource;
+use crate::util::eq_ignore_case;
+use crate::INTERNAL_ERROR_MSG;
+
+#[derive(Debug, Clone)]
+pub(crate) struct MatchedArg {
+ occurs: u64,
+ source: Option<ValueSource>,
+ indices: Vec<usize>,
+ type_id: Option<AnyValueId>,
+ vals: Vec<Vec<AnyValue>>,
+ raw_vals: Vec<Vec<OsString>>,
+ ignore_case: bool,
+}
+
+impl MatchedArg {
+ pub(crate) fn new_arg(arg: &crate::Arg) -> Self {
+ let ignore_case = arg.is_ignore_case_set();
+ Self {
+ occurs: 0,
+ source: None,
+ indices: Vec::new(),
+ type_id: Some(arg.get_value_parser().type_id()),
+ vals: Vec::new(),
+ raw_vals: Vec::new(),
+ ignore_case,
+ }
+ }
+
+ pub(crate) fn new_group() -> Self {
+ let ignore_case = false;
+ Self {
+ occurs: 0,
+ source: None,
+ indices: Vec::new(),
+ type_id: None,
+ vals: Vec::new(),
+ raw_vals: Vec::new(),
+ ignore_case,
+ }
+ }
+
+ pub(crate) fn new_external(cmd: &crate::Command) -> Self {
+ let ignore_case = false;
+ Self {
+ occurs: 0,
+ source: None,
+ indices: Vec::new(),
+ type_id: Some(
+ cmd.get_external_subcommand_value_parser()
+ .expect(INTERNAL_ERROR_MSG)
+ .type_id(),
+ ),
+ vals: Vec::new(),
+ raw_vals: Vec::new(),
+ ignore_case,
+ }
+ }
+
+ #[cfg_attr(feature = "deprecated", deprecated(since = "3.2.0"))]
+ pub(crate) fn inc_occurrences(&mut self) {
+ self.occurs += 1;
+ }
+
+ #[cfg_attr(feature = "deprecated", deprecated(since = "3.2.0"))]
+ pub(crate) fn set_occurrences(&mut self, occurs: u64) {
+ self.occurs = occurs
+ }
+
+ #[cfg_attr(feature = "deprecated", deprecated(since = "3.2.0"))]
+ pub(crate) fn get_occurrences(&self) -> u64 {
+ self.occurs
+ }
+
+ pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
+ self.indices.iter().cloned()
+ }
+
+ pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
+ self.indices.get(index).cloned()
+ }
+
+ pub(crate) fn push_index(&mut self, index: usize) {
+ self.indices.push(index)
+ }
+
+ #[cfg(feature = "unstable-grouped")]
+ pub(crate) fn vals(&self) -> Iter<Vec<AnyValue>> {
+ self.vals.iter()
+ }
+
+ pub(crate) fn vals_flatten(&self) -> Flatten<Iter<Vec<AnyValue>>> {
+ self.vals.iter().flatten()
+ }
+
+ pub(crate) fn into_vals_flatten(self) -> Flatten<std::vec::IntoIter<Vec<AnyValue>>> {
+ self.vals.into_iter().flatten()
+ }
+
+ pub(crate) fn raw_vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>> {
+ self.raw_vals.iter().flatten()
+ }
+
+ pub(crate) fn first(&self) -> Option<&AnyValue> {
+ self.vals_flatten().next()
+ }
+
+ #[cfg(test)]
+ pub(crate) fn first_raw(&self) -> Option<&OsString> {
+ self.raw_vals_flatten().next()
+ }
+
+ pub(crate) fn new_val_group(&mut self) {
+ self.vals.push(vec![]);
+ self.raw_vals.push(vec![]);
+ }
+
+ pub(crate) fn append_val(&mut self, val: AnyValue, raw_val: OsString) {
+ // We assume there is always a group created before.
+ self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val);
+ self.raw_vals
+ .last_mut()
+ .expect(INTERNAL_ERROR_MSG)
+ .push(raw_val);
+ }
+
+ pub(crate) fn num_vals(&self) -> usize {
+ self.vals.iter().map(|v| v.len()).sum()
+ }
+
+ // Will be used later
+ #[allow(dead_code)]
+ pub(crate) fn num_vals_last_group(&self) -> usize {
+ self.vals.last().map(|x| x.len()).unwrap_or(0)
+ }
+
+ pub(crate) fn all_val_groups_empty(&self) -> bool {
+ self.vals.iter().flatten().count() == 0
+ }
+
+ pub(crate) fn check_explicit(&self, predicate: ArgPredicate) -> bool {
+ if self.source == Some(ValueSource::DefaultValue) {
+ return false;
+ }
+
+ match predicate {
+ ArgPredicate::Equals(val) => self.raw_vals_flatten().any(|v| {
+ if self.ignore_case {
+ // If `v` isn't utf8, it can't match `val`, so `OsStr::to_str` should be fine
+ eq_ignore_case(&v.to_string_lossy(), &val.to_string_lossy())
+ } else {
+ OsString::as_os_str(v) == OsStr::new(val)
+ }
+ }),
+ ArgPredicate::IsPresent => true,
+ }
+ }
+
+ pub(crate) fn source(&self) -> Option<ValueSource> {
+ self.source
+ }
+
+ pub(crate) fn set_source(&mut self, source: ValueSource) {
+ if let Some(existing) = self.source {
+ self.source = Some(existing.max(source));
+ } else {
+ self.source = Some(source)
+ }
+ }
+
+ pub(crate) fn type_id(&self) -> Option<AnyValueId> {
+ self.type_id
+ }
+
+ pub(crate) fn infer_type_id(&self, expected: AnyValueId) -> AnyValueId {
+ self.type_id()
+ .or_else(|| {
+ self.vals_flatten()
+ .map(|v| v.type_id())
+ .find(|actual| *actual != expected)
+ })
+ .unwrap_or(expected)
+ }
+}
+
+impl PartialEq for MatchedArg {
+ fn eq(&self, other: &MatchedArg) -> bool {
+ let MatchedArg {
+ occurs: self_occurs,
+ source: self_source,
+ indices: self_indices,
+ type_id: self_type_id,
+ vals: _,
+ raw_vals: self_raw_vals,
+ ignore_case: self_ignore_case,
+ } = self;
+ let MatchedArg {
+ occurs: other_occurs,
+ source: other_source,
+ indices: other_indices,
+ type_id: other_type_id,
+ vals: _,
+ raw_vals: other_raw_vals,
+ ignore_case: other_ignore_case,
+ } = other;
+ self_occurs == other_occurs
+ && self_source == other_source
+ && self_indices == other_indices
+ && self_type_id == other_type_id
+ && self_raw_vals == other_raw_vals
+ && self_ignore_case == other_ignore_case
+ }
+}
+
+impl Eq for MatchedArg {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_grouped_vals_first() {
+ let mut m = MatchedArg::new_group();
+ m.new_val_group();
+ m.new_val_group();
+ m.append_val(AnyValue::new(String::from("bbb")), "bbb".into());
+ m.append_val(AnyValue::new(String::from("ccc")), "ccc".into());
+ assert_eq!(m.first_raw(), Some(&OsString::from("bbb")));
+ }
+}
diff --git a/vendor/clap-3.2.20/src/parser/matches/mod.rs b/vendor/clap-3.2.20/src/parser/matches/mod.rs
new file mode 100644
index 000000000..7b88eeca7
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/matches/mod.rs
@@ -0,0 +1,17 @@
+mod any_value;
+mod arg_matches;
+mod matched_arg;
+mod value_source;
+
+pub use any_value::AnyValueId;
+pub use arg_matches::RawValues;
+pub use arg_matches::ValuesRef;
+pub use arg_matches::{ArgMatches, Indices};
+pub use value_source::ValueSource;
+
+pub(crate) use any_value::AnyValue;
+pub(crate) use arg_matches::SubCommand;
+pub(crate) use matched_arg::MatchedArg;
+
+#[allow(deprecated)]
+pub use arg_matches::{OsValues, Values};
diff --git a/vendor/clap-3.2.20/src/parser/matches/value_source.rs b/vendor/clap-3.2.20/src/parser/matches/value_source.rs
new file mode 100644
index 000000000..fb762d2af
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/matches/value_source.rs
@@ -0,0 +1,11 @@
+/// Origin of the argument's value
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[non_exhaustive]
+pub enum ValueSource {
+ /// Value came [`Arg::default_value`][crate::Arg::default_value]
+ DefaultValue,
+ /// Value came [`Arg::env`][crate::Arg::env]
+ EnvVariable,
+ /// Value was passed in on the command-line
+ CommandLine,
+}
diff --git a/vendor/clap-3.2.20/src/parser/mod.rs b/vendor/clap-3.2.20/src/parser/mod.rs
new file mode 100644
index 000000000..da81648e1
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/mod.rs
@@ -0,0 +1,27 @@
+//! [`Command`][crate::Command] line argument parser
+
+mod arg_matcher;
+mod error;
+mod matches;
+#[allow(clippy::module_inception)]
+mod parser;
+mod validator;
+
+pub(crate) mod features;
+
+pub(crate) use self::arg_matcher::ArgMatcher;
+pub(crate) use self::matches::AnyValue;
+pub(crate) use self::matches::AnyValueId;
+pub(crate) use self::matches::{MatchedArg, SubCommand};
+pub(crate) use self::parser::Identifier;
+pub(crate) use self::parser::PendingArg;
+pub(crate) use self::parser::{ParseState, Parser};
+pub(crate) use self::validator::Validator;
+
+pub use self::matches::RawValues;
+pub use self::matches::ValuesRef;
+pub use self::matches::{ArgMatches, Indices, ValueSource};
+pub use error::MatchesError;
+
+#[allow(deprecated)]
+pub use self::matches::{OsValues, Values};
diff --git a/vendor/clap-3.2.20/src/parser/parser.rs b/vendor/clap-3.2.20/src/parser/parser.rs
new file mode 100644
index 000000000..ad2bc6e9c
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/parser.rs
@@ -0,0 +1,1729 @@
+// Std
+use std::{
+ cell::Cell,
+ ffi::{OsStr, OsString},
+};
+
+// Third Party
+use clap_lex::RawOsStr;
+
+// Internal
+use crate::builder::AppSettings as AS;
+use crate::builder::{Arg, Command};
+use crate::error::Error as ClapError;
+use crate::error::Result as ClapResult;
+use crate::mkeymap::KeyType;
+use crate::output::fmt::Stream;
+use crate::output::{fmt::Colorizer, Usage};
+use crate::parser::features::suggestions;
+use crate::parser::{ArgMatcher, SubCommand};
+use crate::parser::{Validator, ValueSource};
+use crate::util::Id;
+use crate::ArgAction;
+use crate::{INTERNAL_ERROR_MSG, INVALID_UTF8};
+
+pub(crate) struct Parser<'help, 'cmd> {
+ cmd: &'cmd mut Command<'help>,
+ cur_idx: Cell<usize>,
+ /// Index of the previous flag subcommand in a group of flags.
+ flag_subcmd_at: Option<usize>,
+ /// Counter indicating the number of items to skip
+ /// when revisiting the group of flags which includes the flag subcommand.
+ flag_subcmd_skip: usize,
+}
+
+// Initializing Methods
+impl<'help, 'cmd> Parser<'help, 'cmd> {
+ pub(crate) fn new(cmd: &'cmd mut Command<'help>) -> Self {
+ Parser {
+ cmd,
+ cur_idx: Cell::new(0),
+ flag_subcmd_at: None,
+ flag_subcmd_skip: 0,
+ }
+ }
+}
+
+// Parsing Methods
+impl<'help, 'cmd> Parser<'help, 'cmd> {
+ // The actual parsing function
+ #[allow(clippy::cognitive_complexity)]
+ pub(crate) fn get_matches_with(
+ &mut self,
+ matcher: &mut ArgMatcher,
+ raw_args: &mut clap_lex::RawArgs,
+ mut args_cursor: clap_lex::ArgCursor,
+ ) -> ClapResult<()> {
+ debug!("Parser::get_matches_with");
+ // Verify all positional assertions pass
+
+ let mut subcmd_name: Option<String> = None;
+ let mut keep_state = false;
+ let mut parse_state = ParseState::ValuesDone;
+ let mut pos_counter = 1;
+
+ // Already met any valid arg(then we shouldn't expect subcommands after it).
+ let mut valid_arg_found = false;
+ // If the user already passed '--'. Meaning only positional args follow.
+ let mut trailing_values = false;
+
+ // Count of positional args
+ let positional_count = self
+ .cmd
+ .get_keymap()
+ .keys()
+ .filter(|x| x.is_position())
+ .count();
+ // If any arg sets .last(true)
+ let contains_last = self.cmd.get_arguments().any(|x| x.is_last_set());
+
+ while let Some(arg_os) = raw_args.next(&mut args_cursor) {
+ // Recover the replaced items if any.
+ if let Some(replaced_items) = arg_os
+ .to_value()
+ .ok()
+ .and_then(|a| self.cmd.get_replacement(a))
+ {
+ debug!(
+ "Parser::get_matches_with: found replacer: {:?}, target: {:?}",
+ arg_os, replaced_items
+ );
+ raw_args.insert(&args_cursor, replaced_items);
+ continue;
+ }
+
+ debug!(
+ "Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
+ arg_os.to_value_os(),
+ arg_os.to_value_os().as_raw_bytes()
+ );
+
+ // Has the user already passed '--'? Meaning only positional args follow
+ if !trailing_values {
+ if self.cmd.is_subcommand_precedence_over_arg_set()
+ || !matches!(parse_state, ParseState::Opt(_) | ParseState::Pos(_))
+ {
+ // Does the arg match a subcommand name, or any of its aliases (if defined)
+ let sc_name = self.possible_subcommand(arg_os.to_value(), valid_arg_found);
+ debug!("Parser::get_matches_with: sc={:?}", sc_name);
+ if let Some(sc_name) = sc_name {
+ #[allow(deprecated)]
+ if sc_name == "help"
+ && !self.is_set(AS::NoAutoHelp)
+ && !self.cmd.is_disable_help_subcommand_set()
+ {
+ self.parse_help_subcommand(raw_args.remaining(&mut args_cursor))?;
+ unreachable!("`parse_help_subcommand` always errors");
+ } else {
+ subcmd_name = Some(sc_name.to_owned());
+ }
+ break;
+ }
+ }
+
+ if arg_os.is_escape() {
+ if matches!(&parse_state, ParseState::Opt(opt) | ParseState::Pos(opt) if
+ self.cmd[opt].is_allow_hyphen_values_set())
+ {
+ // ParseResult::MaybeHyphenValue, do nothing
+ } else {
+ debug!("Parser::get_matches_with: setting TrailingVals=true");
+ trailing_values = true;
+ continue;
+ }
+ } else if let Some((long_arg, long_value)) = arg_os.to_long() {
+ let parse_result = self.parse_long_arg(
+ matcher,
+ long_arg,
+ long_value,
+ &parse_state,
+ &mut valid_arg_found,
+ trailing_values,
+ )?;
+ debug!(
+ "Parser::get_matches_with: After parse_long_arg {:?}",
+ parse_result
+ );
+ match parse_result {
+ ParseResult::NoArg => {
+ unreachable!("`to_long` always has the flag specified")
+ }
+ ParseResult::ValuesDone => {
+ parse_state = ParseState::ValuesDone;
+ continue;
+ }
+ ParseResult::Opt(id) => {
+ parse_state = ParseState::Opt(id);
+ continue;
+ }
+ ParseResult::FlagSubCommand(name) => {
+ debug!(
+ "Parser::get_matches_with: FlagSubCommand found in long arg {:?}",
+ &name
+ );
+ subcmd_name = Some(name);
+ break;
+ }
+ ParseResult::EqualsNotProvided { arg } => {
+ let _ = self.resolve_pending(matcher);
+ return Err(ClapError::no_equals(
+ self.cmd,
+ arg,
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ ));
+ }
+ ParseResult::NoMatchingArg { arg } => {
+ let _ = self.resolve_pending(matcher);
+ let remaining_args: Vec<_> = raw_args
+ .remaining(&mut args_cursor)
+ .map(|x| x.to_str().expect(INVALID_UTF8))
+ .collect();
+ return Err(self.did_you_mean_error(&arg, matcher, &remaining_args));
+ }
+ ParseResult::UnneededAttachedValue { rest, used, arg } => {
+ let _ = self.resolve_pending(matcher);
+ return Err(ClapError::too_many_values(
+ self.cmd,
+ rest,
+ arg,
+ Usage::new(self.cmd).create_usage_no_title(&used),
+ ));
+ }
+ ParseResult::MaybeHyphenValue => {
+ // Maybe a hyphen value, do nothing.
+ }
+ ParseResult::AttachedValueNotConsumed => {
+ unreachable!()
+ }
+ }
+ } else if let Some(short_arg) = arg_os.to_short() {
+ // Arg looks like a short flag, and not a possible number
+
+ // Try to parse short args like normal, if allow_hyphen_values or
+ // AllowNegativeNumbers is set, parse_short_arg will *not* throw
+ // an error, and instead return Ok(None)
+ let parse_result = self.parse_short_arg(
+ matcher,
+ short_arg,
+ &parse_state,
+ pos_counter,
+ &mut valid_arg_found,
+ trailing_values,
+ )?;
+ // If it's None, we then check if one of those two AppSettings was set
+ debug!(
+ "Parser::get_matches_with: After parse_short_arg {:?}",
+ parse_result
+ );
+ match parse_result {
+ ParseResult::NoArg => {
+ // Is a single dash `-`, try positional.
+ }
+ ParseResult::ValuesDone => {
+ parse_state = ParseState::ValuesDone;
+ continue;
+ }
+ ParseResult::Opt(id) => {
+ parse_state = ParseState::Opt(id);
+ continue;
+ }
+ ParseResult::FlagSubCommand(name) => {
+ // If there are more short flags to be processed, we should keep the state, and later
+ // revisit the current group of short flags skipping the subcommand.
+ keep_state = self
+ .flag_subcmd_at
+ .map(|at| {
+ raw_args
+ .seek(&mut args_cursor, clap_lex::SeekFrom::Current(-1));
+ // Since we are now saving the current state, the number of flags to skip during state recovery should
+ // be the current index (`cur_idx`) minus ONE UNIT TO THE LEFT of the starting position.
+ self.flag_subcmd_skip = self.cur_idx.get() - at + 1;
+ })
+ .is_some();
+
+ debug!(
+ "Parser::get_matches_with:FlagSubCommandShort: subcmd_name={}, keep_state={}, flag_subcmd_skip={}",
+ name,
+ keep_state,
+ self.flag_subcmd_skip
+ );
+
+ subcmd_name = Some(name);
+ break;
+ }
+ ParseResult::EqualsNotProvided { arg } => {
+ let _ = self.resolve_pending(matcher);
+ return Err(ClapError::no_equals(
+ self.cmd,
+ arg,
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ ));
+ }
+ ParseResult::NoMatchingArg { arg } => {
+ let _ = self.resolve_pending(matcher);
+ return Err(ClapError::unknown_argument(
+ self.cmd,
+ arg,
+ None,
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ ));
+ }
+ ParseResult::MaybeHyphenValue => {
+ // Maybe a hyphen value, do nothing.
+ }
+ ParseResult::UnneededAttachedValue { .. }
+ | ParseResult::AttachedValueNotConsumed => unreachable!(),
+ }
+ }
+
+ if let ParseState::Opt(id) = &parse_state {
+ // Assume this is a value of a previous arg.
+
+ // get the option so we can check the settings
+ let arg_values = matcher.pending_values_mut(id, None);
+ let arg = &self.cmd[id];
+ let parse_result = self.split_arg_values(
+ arg,
+ arg_os.to_value_os(),
+ trailing_values,
+ arg_values,
+ );
+ let parse_result = parse_result.unwrap_or_else(|| {
+ if matcher.needs_more_vals(arg) {
+ ParseResult::Opt(arg.id.clone())
+ } else {
+ ParseResult::ValuesDone
+ }
+ });
+ parse_state = match parse_result {
+ ParseResult::Opt(id) => ParseState::Opt(id),
+ ParseResult::ValuesDone => ParseState::ValuesDone,
+ _ => unreachable!(),
+ };
+ // get the next value from the iterator
+ continue;
+ }
+ }
+
+ // Correct pos_counter.
+ pos_counter = {
+ let is_second_to_last = pos_counter + 1 == positional_count;
+
+ // The last positional argument, or second to last positional
+ // argument may be set to .multiple_values(true) or `.multiple_occurrences(true)`
+ let low_index_mults = is_second_to_last
+ && self
+ .cmd
+ .get_positionals()
+ .any(|a| a.is_multiple() && (positional_count != a.index.unwrap_or(0)))
+ && self
+ .cmd
+ .get_positionals()
+ .last()
+ .map_or(false, |p_name| !p_name.is_last_set());
+
+ let missing_pos = self.cmd.is_allow_missing_positional_set()
+ && is_second_to_last
+ && !trailing_values;
+
+ debug!(
+ "Parser::get_matches_with: Positional counter...{}",
+ pos_counter
+ );
+ debug!(
+ "Parser::get_matches_with: Low index multiples...{:?}",
+ low_index_mults
+ );
+
+ if low_index_mults || missing_pos {
+ let skip_current = if let Some(n) = raw_args.peek(&args_cursor) {
+ if let Some(arg) = self
+ .cmd
+ .get_positionals()
+ .find(|a| a.index == Some(pos_counter))
+ {
+ // If next value looks like a new_arg or it's a
+ // subcommand, skip positional argument under current
+ // pos_counter(which means current value cannot be a
+ // positional argument with a value next to it), assume
+ // current value matches the next arg.
+ self.is_new_arg(&n, arg)
+ || self
+ .possible_subcommand(n.to_value(), valid_arg_found)
+ .is_some()
+ } else {
+ true
+ }
+ } else {
+ true
+ };
+
+ if skip_current {
+ debug!("Parser::get_matches_with: Bumping the positional counter...");
+ pos_counter + 1
+ } else {
+ pos_counter
+ }
+ } else if trailing_values
+ && (self.cmd.is_allow_missing_positional_set() || contains_last)
+ {
+ // Came to -- and one positional has .last(true) set, so we go immediately
+ // to the last (highest index) positional
+ debug!("Parser::get_matches_with: .last(true) and --, setting last pos");
+ positional_count
+ } else {
+ pos_counter
+ }
+ };
+
+ if let Some(arg) = self.cmd.get_keymap().get(&pos_counter) {
+ if arg.is_last_set() && !trailing_values {
+ let _ = self.resolve_pending(matcher);
+ return Err(ClapError::unknown_argument(
+ self.cmd,
+ arg_os.display().to_string(),
+ None,
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ ));
+ }
+
+ if self.cmd.is_trailing_var_arg_set() && pos_counter == positional_count {
+ trailing_values = true;
+ }
+
+ if matcher.pending_arg_id() != Some(&arg.id) || !arg.is_multiple_values_set() {
+ self.resolve_pending(matcher)?;
+ }
+ let arg_values = matcher.pending_values_mut(&arg.id, Some(Identifier::Index));
+ let _parse_result =
+ self.split_arg_values(arg, arg_os.to_value_os(), trailing_values, arg_values);
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!(
+ "Parser::get_matches_with: Ignoring state {:?}; positionals do their own thing",
+ _parse_result
+ );
+ }
+ }
+
+ // Only increment the positional counter if it doesn't allow multiples
+ if !arg.is_multiple() {
+ pos_counter += 1;
+ parse_state = ParseState::ValuesDone;
+ } else {
+ parse_state = ParseState::Pos(arg.id.clone());
+ }
+ valid_arg_found = true;
+ } else if let Some(external_parser) =
+ self.cmd.get_external_subcommand_value_parser().cloned()
+ {
+ // Get external subcommand name
+ let sc_name = match arg_os.to_value() {
+ Ok(s) => s.to_string(),
+ Err(_) => {
+ let _ = self.resolve_pending(matcher);
+ return Err(ClapError::invalid_utf8(
+ self.cmd,
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ ));
+ }
+ };
+
+ // Collect the external subcommand args
+ let mut sc_m = ArgMatcher::new(self.cmd);
+ if cfg!(feature = "unstable-v4") || !raw_args.is_end(&args_cursor) {
+ sc_m.start_occurrence_of_external(self.cmd);
+ }
+
+ for raw_val in raw_args.remaining(&mut args_cursor) {
+ let val = external_parser.parse_ref(self.cmd, None, raw_val)?;
+ let external_id = &Id::empty_hash();
+ sc_m.add_val_to(external_id, val, raw_val.to_os_string());
+ }
+
+ matcher.subcommand(SubCommand {
+ id: Id::from(&*sc_name),
+ name: sc_name,
+ matches: sc_m.into_inner(),
+ });
+
+ self.resolve_pending(matcher)?;
+ #[cfg(feature = "env")]
+ self.add_env(matcher)?;
+ self.add_defaults(matcher)?;
+ return Validator::new(self.cmd).validate(parse_state, matcher);
+ } else {
+ // Start error processing
+ let _ = self.resolve_pending(matcher);
+ return Err(self.match_arg_error(&arg_os, valid_arg_found, trailing_values));
+ }
+ }
+
+ if let Some(ref pos_sc_name) = subcmd_name {
+ let sc_name = self
+ .cmd
+ .find_subcommand(pos_sc_name)
+ .expect(INTERNAL_ERROR_MSG)
+ .get_name()
+ .to_owned();
+ self.parse_subcommand(&sc_name, matcher, raw_args, args_cursor, keep_state)?;
+ }
+
+ self.resolve_pending(matcher)?;
+ #[cfg(feature = "env")]
+ self.add_env(matcher)?;
+ self.add_defaults(matcher)?;
+ Validator::new(self.cmd).validate(parse_state, matcher)
+ }
+
+ fn match_arg_error(
+ &self,
+ arg_os: &clap_lex::ParsedArg<'_>,
+ valid_arg_found: bool,
+ trailing_values: bool,
+ ) -> ClapError {
+ // If argument follows a `--`
+ if trailing_values {
+ // If the arg matches a subcommand name, or any of its aliases (if defined)
+ if self
+ .possible_subcommand(arg_os.to_value(), valid_arg_found)
+ .is_some()
+ {
+ return ClapError::unnecessary_double_dash(
+ self.cmd,
+ arg_os.display().to_string(),
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ );
+ }
+ }
+ let candidates = suggestions::did_you_mean(
+ &arg_os.display().to_string(),
+ self.cmd.all_subcommand_names(),
+ );
+ // If the argument looks like a subcommand.
+ if !candidates.is_empty() {
+ let candidates: Vec<_> = candidates
+ .iter()
+ .map(|candidate| format!("'{}'", candidate))
+ .collect();
+ return ClapError::invalid_subcommand(
+ self.cmd,
+ arg_os.display().to_string(),
+ candidates.join(" or "),
+ self.cmd
+ .get_bin_name()
+ .unwrap_or_else(|| self.cmd.get_name())
+ .to_owned(),
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ );
+ }
+ // If the argument must be a subcommand.
+ if !self.cmd.has_args() || self.cmd.is_infer_subcommands_set() && self.cmd.has_subcommands()
+ {
+ return ClapError::unrecognized_subcommand(
+ self.cmd,
+ arg_os.display().to_string(),
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ );
+ }
+ ClapError::unknown_argument(
+ self.cmd,
+ arg_os.display().to_string(),
+ None,
+ Usage::new(self.cmd).create_usage_with_title(&[]),
+ )
+ }
+
+ // Checks if the arg matches a subcommand name, or any of its aliases (if defined)
+ fn possible_subcommand(
+ &self,
+ arg: Result<&str, &RawOsStr>,
+ valid_arg_found: bool,
+ ) -> Option<&str> {
+ debug!("Parser::possible_subcommand: arg={:?}", arg);
+ let arg = arg.ok()?;
+
+ if !(self.cmd.is_args_conflicts_with_subcommands_set() && valid_arg_found) {
+ if self.cmd.is_infer_subcommands_set() {
+ // For subcommand `test`, we accepts it's prefix: `t`, `te`,
+ // `tes` and `test`.
+ let v = self
+ .cmd
+ .all_subcommand_names()
+ .filter(|s| s.starts_with(arg))
+ .collect::<Vec<_>>();
+
+ if v.len() == 1 {
+ return Some(v[0]);
+ }
+
+ // If there is any ambiguity, fallback to non-infer subcommand
+ // search.
+ }
+ if let Some(sc) = self.cmd.find_subcommand(arg) {
+ return Some(sc.get_name());
+ }
+ }
+ None
+ }
+
+ // Checks if the arg matches a long flag subcommand name, or any of its aliases (if defined)
+ fn possible_long_flag_subcommand(&self, arg: &str) -> Option<&str> {
+ debug!("Parser::possible_long_flag_subcommand: arg={:?}", arg);
+ if self.cmd.is_infer_subcommands_set() {
+ let options = self
+ .cmd
+ .get_subcommands()
+ .fold(Vec::new(), |mut options, sc| {
+ if let Some(long) = sc.get_long_flag() {
+ if long.starts_with(arg) {
+ options.push(long);
+ }
+ options.extend(sc.get_all_aliases().filter(|alias| alias.starts_with(arg)))
+ }
+ options
+ });
+ if options.len() == 1 {
+ return Some(options[0]);
+ }
+
+ for sc in options {
+ if sc == arg {
+ return Some(sc);
+ }
+ }
+ } else if let Some(sc_name) = self.cmd.find_long_subcmd(arg) {
+ return Some(sc_name);
+ }
+ None
+ }
+
+ fn parse_help_subcommand(
+ &self,
+ cmds: impl Iterator<Item = &'cmd OsStr>,
+ ) -> ClapResult<std::convert::Infallible> {
+ debug!("Parser::parse_help_subcommand");
+
+ let mut cmd = self.cmd.clone();
+ let sc = {
+ let mut sc = &mut cmd;
+
+ for cmd in cmds {
+ sc = if let Some(sc_name) =
+ sc.find_subcommand(cmd).map(|sc| sc.get_name().to_owned())
+ {
+ sc._build_subcommand(&sc_name).unwrap()
+ } else {
+ return Err(ClapError::unrecognized_subcommand(
+ sc,
+ cmd.to_string_lossy().into_owned(),
+ Usage::new(sc).create_usage_with_title(&[]),
+ ));
+ };
+ }
+
+ sc
+ };
+ let parser = Parser::new(sc);
+
+ Err(parser.help_err(true, Stream::Stdout))
+ }
+
+ fn is_new_arg(&self, next: &clap_lex::ParsedArg<'_>, current_positional: &Arg) -> bool {
+ #![allow(clippy::needless_bool)] // Prefer consistent if/else-if ladder
+
+ debug!(
+ "Parser::is_new_arg: {:?}:{:?}",
+ next.to_value_os(),
+ current_positional.name
+ );
+
+ if self.cmd.is_allow_hyphen_values_set()
+ || self.cmd[&current_positional.id].is_allow_hyphen_values_set()
+ || (self.cmd.is_allow_negative_numbers_set() && next.is_number())
+ {
+ // If allow hyphen, this isn't a new arg.
+ debug!("Parser::is_new_arg: Allow hyphen");
+ false
+ } else if next.is_long() {
+ // If this is a long flag, this is a new arg.
+ debug!("Parser::is_new_arg: --<something> found");
+ true
+ } else if next.is_short() {
+ // If this is a short flag, this is a new arg. But a singe '-' by
+ // itself is a value and typically means "stdin" on unix systems.
+ debug!("Parser::is_new_arg: -<something> found");
+ true
+ } else {
+ // Nothing special, this is a value.
+ debug!("Parser::is_new_arg: value");
+ false
+ }
+ }
+
+ fn parse_subcommand(
+ &mut self,
+ sc_name: &str,
+ matcher: &mut ArgMatcher,
+ raw_args: &mut clap_lex::RawArgs,
+ args_cursor: clap_lex::ArgCursor,
+ keep_state: bool,
+ ) -> ClapResult<()> {
+ debug!("Parser::parse_subcommand");
+
+ let partial_parsing_enabled = self.cmd.is_ignore_errors_set();
+
+ if let Some(sc) = self.cmd._build_subcommand(sc_name) {
+ let mut sc_matcher = ArgMatcher::new(sc);
+
+ debug!(
+ "Parser::parse_subcommand: About to parse sc={}",
+ sc.get_name()
+ );
+
+ {
+ let mut p = Parser::new(sc);
+ // HACK: maintain indexes between parsers
+ // FlagSubCommand short arg needs to revisit the current short args, but skip the subcommand itself
+ if keep_state {
+ p.cur_idx.set(self.cur_idx.get());
+ p.flag_subcmd_at = self.flag_subcmd_at;
+ p.flag_subcmd_skip = self.flag_subcmd_skip;
+ }
+ if let Err(error) = p.get_matches_with(&mut sc_matcher, raw_args, args_cursor) {
+ if partial_parsing_enabled {
+ debug!(
+ "Parser::parse_subcommand: ignored error in subcommand {}: {:?}",
+ sc_name, error
+ );
+ } else {
+ return Err(error);
+ }
+ }
+ }
+ matcher.subcommand(SubCommand {
+ id: sc.get_id(),
+ name: sc.get_name().to_owned(),
+ matches: sc_matcher.into_inner(),
+ });
+ }
+ Ok(())
+ }
+
+ fn parse_long_arg(
+ &mut self,
+ matcher: &mut ArgMatcher,
+ long_arg: Result<&str, &RawOsStr>,
+ long_value: Option<&RawOsStr>,
+ parse_state: &ParseState,
+ valid_arg_found: &mut bool,
+ trailing_values: bool,
+ ) -> ClapResult<ParseResult> {
+ // maybe here lifetime should be 'a
+ debug!("Parser::parse_long_arg");
+
+ if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt) if
+ self.cmd[opt].is_allow_hyphen_values_set())
+ {
+ return Ok(ParseResult::MaybeHyphenValue);
+ }
+
+ debug!("Parser::parse_long_arg: Does it contain '='...");
+ let long_arg = match long_arg {
+ Ok(long_arg) => long_arg,
+ Err(long_arg) => {
+ return Ok(ParseResult::NoMatchingArg {
+ arg: long_arg.to_str_lossy().into_owned(),
+ });
+ }
+ };
+ if long_arg.is_empty() {
+ debug_assert!(
+ long_value.is_some(),
+ "`--` should be filtered out before this point"
+ );
+ }
+
+ let arg = if let Some(arg) = self.cmd.get_keymap().get(long_arg) {
+ debug!(
+ "Parser::parse_long_arg: Found valid arg or flag '{}'",
+ arg.to_string()
+ );
+ Some((long_arg, arg))
+ } else if self.cmd.is_infer_long_args_set() {
+ self.cmd.get_arguments().find_map(|a| {
+ if let Some(long) = a.long {
+ if long.starts_with(long_arg) {
+ return Some((long, a));
+ }
+ }
+ a.aliases
+ .iter()
+ .find_map(|(alias, _)| alias.starts_with(long_arg).then(|| (*alias, a)))
+ })
+ } else {
+ None
+ };
+
+ if let Some((_long_arg, arg)) = arg {
+ let ident = Identifier::Long;
+ *valid_arg_found = true;
+ if arg.is_takes_value_set() {
+ debug!(
+ "Parser::parse_long_arg({:?}): Found an arg with value '{:?}'",
+ long_arg, &long_value
+ );
+ let has_eq = long_value.is_some();
+ self.parse_opt_value(ident, long_value, arg, matcher, trailing_values, has_eq)
+ } else if let Some(rest) = long_value {
+ let required = self.cmd.required_graph();
+ debug!(
+ "Parser::parse_long_arg({:?}): Got invalid literal `{:?}`",
+ long_arg, rest
+ );
+ let used: Vec<Id> = matcher
+ .arg_ids()
+ .filter(|arg_id| {
+ matcher.check_explicit(arg_id, crate::builder::ArgPredicate::IsPresent)
+ })
+ .filter(|&n| {
+ self.cmd
+ .find(n)
+ .map_or(true, |a| !(a.is_hide_set() || required.contains(&a.id)))
+ })
+ .cloned()
+ .collect();
+
+ Ok(ParseResult::UnneededAttachedValue {
+ rest: rest.to_str_lossy().into_owned(),
+ used,
+ arg: arg.to_string(),
+ })
+ } else {
+ debug!("Parser::parse_long_arg({:?}): Presence validated", long_arg);
+ self.react(Some(ident), ValueSource::CommandLine, arg, vec![], matcher)
+ }
+ } else if let Some(sc_name) = self.possible_long_flag_subcommand(long_arg) {
+ Ok(ParseResult::FlagSubCommand(sc_name.to_string()))
+ } else if self.cmd.is_allow_hyphen_values_set() {
+ Ok(ParseResult::MaybeHyphenValue)
+ } else {
+ Ok(ParseResult::NoMatchingArg {
+ arg: long_arg.to_owned(),
+ })
+ }
+ }
+
+ fn parse_short_arg(
+ &mut self,
+ matcher: &mut ArgMatcher,
+ mut short_arg: clap_lex::ShortFlags<'_>,
+ parse_state: &ParseState,
+ // change this to possible pos_arg when removing the usage of &mut Parser.
+ pos_counter: usize,
+ valid_arg_found: &mut bool,
+ trailing_values: bool,
+ ) -> ClapResult<ParseResult> {
+ debug!("Parser::parse_short_arg: short_arg={:?}", short_arg);
+
+ #[allow(clippy::blocks_in_if_conditions)]
+ if self.cmd.is_allow_negative_numbers_set() && short_arg.is_number() {
+ debug!("Parser::parse_short_arg: negative number");
+ return Ok(ParseResult::MaybeHyphenValue);
+ } else if self.cmd.is_allow_hyphen_values_set()
+ && short_arg
+ .clone()
+ .any(|c| !c.map(|c| self.cmd.contains_short(c)).unwrap_or_default())
+ {
+ debug!("Parser::parse_short_args: contains non-short flag");
+ return Ok(ParseResult::MaybeHyphenValue);
+ } else if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt)
+ if self.cmd[opt].is_allow_hyphen_values_set())
+ {
+ debug!("Parser::parse_short_args: prior arg accepts hyphenated values",);
+ return Ok(ParseResult::MaybeHyphenValue);
+ } else if self
+ .cmd
+ .get_keymap()
+ .get(&pos_counter)
+ .map_or(false, |arg| {
+ arg.is_allow_hyphen_values_set() && !arg.is_last_set()
+ })
+ {
+ debug!(
+ "Parser::parse_short_args: positional at {} allows hyphens",
+ pos_counter
+ );
+ return Ok(ParseResult::MaybeHyphenValue);
+ }
+
+ let mut ret = ParseResult::NoArg;
+
+ let skip = self.flag_subcmd_skip;
+ self.flag_subcmd_skip = 0;
+ let res = short_arg.advance_by(skip);
+ debug_assert_eq!(
+ res,
+ Ok(()),
+ "tracking of `flag_subcmd_skip` is off for `{:?}`",
+ short_arg
+ );
+ while let Some(c) = short_arg.next_flag() {
+ let c = match c {
+ Ok(c) => c,
+ Err(rest) => {
+ return Ok(ParseResult::NoMatchingArg {
+ arg: format!("-{}", rest.to_str_lossy()),
+ });
+ }
+ };
+ debug!("Parser::parse_short_arg:iter:{}", c);
+
+ // Check for matching short options, and return the name if there is no trailing
+ // concatenated value: -oval
+ // Option: -o
+ // Value: val
+ if let Some(arg) = self.cmd.get_keymap().get(&c) {
+ let ident = Identifier::Short;
+ debug!(
+ "Parser::parse_short_arg:iter:{}: Found valid opt or flag",
+ c
+ );
+ *valid_arg_found = true;
+ if !arg.is_takes_value_set() {
+ ret =
+ self.react(Some(ident), ValueSource::CommandLine, arg, vec![], matcher)?;
+ continue;
+ }
+
+ // Check for trailing concatenated value
+ //
+ // Cloning the iterator, so we rollback if it isn't there.
+ let val = short_arg.clone().next_value_os().unwrap_or_default();
+ debug!(
+ "Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii), short_arg={:?}",
+ c, val, val.as_raw_bytes(), short_arg
+ );
+ let val = Some(val).filter(|v| !v.is_empty());
+
+ // Default to "we're expecting a value later".
+ //
+ // If attached value is not consumed, we may have more short
+ // flags to parse, continue.
+ //
+ // e.g. `-xvf`, when require_equals && x.min_vals == 0, we don't
+ // consume the `vf`, even if it's provided as value.
+ let (val, has_eq) = if let Some(val) = val.and_then(|v| v.strip_prefix('=')) {
+ (Some(val), true)
+ } else {
+ (val, false)
+ };
+ match self.parse_opt_value(ident, val, arg, matcher, trailing_values, has_eq)? {
+ ParseResult::AttachedValueNotConsumed => continue,
+ x => return Ok(x),
+ }
+ }
+
+ return if let Some(sc_name) = self.cmd.find_short_subcmd(c) {
+ debug!("Parser::parse_short_arg:iter:{}: subcommand={}", c, sc_name);
+ // Make sure indices get updated before reading `self.cur_idx`
+ self.resolve_pending(matcher)?;
+ self.cur_idx.set(self.cur_idx.get() + 1);
+ debug!("Parser::parse_short_arg: cur_idx:={}", self.cur_idx.get());
+
+ let name = sc_name.to_string();
+ // Get the index of the previously saved flag subcommand in the group of flags (if exists).
+ // If it is a new flag subcommand, then the formentioned index should be the current one
+ // (ie. `cur_idx`), and should be registered.
+ let cur_idx = self.cur_idx.get();
+ self.flag_subcmd_at.get_or_insert(cur_idx);
+ let done_short_args = short_arg.is_empty();
+ if done_short_args {
+ self.flag_subcmd_at = None;
+ }
+ Ok(ParseResult::FlagSubCommand(name))
+ } else {
+ Ok(ParseResult::NoMatchingArg {
+ arg: format!("-{}", c),
+ })
+ };
+ }
+ Ok(ret)
+ }
+
+ fn parse_opt_value(
+ &self,
+ ident: Identifier,
+ attached_value: Option<&RawOsStr>,
+ arg: &Arg<'help>,
+ matcher: &mut ArgMatcher,
+ trailing_values: bool,
+ has_eq: bool,
+ ) -> ClapResult<ParseResult> {
+ debug!(
+ "Parser::parse_opt_value; arg={}, val={:?}, has_eq={:?}",
+ arg.name, attached_value, has_eq
+ );
+ debug!("Parser::parse_opt_value; arg.settings={:?}", arg.settings);
+
+ debug!("Parser::parse_opt_value; Checking for val...");
+ // require_equals is set, but no '=' is provided, try throwing error.
+ if arg.is_require_equals_set() && !has_eq {
+ if arg.min_vals == Some(0) {
+ debug!("Requires equals, but min_vals == 0");
+ let mut arg_values = Vec::new();
+ // We assume this case is valid: require equals, but min_vals == 0.
+ if !arg.default_missing_vals.is_empty() {
+ debug!("Parser::parse_opt_value: has default_missing_vals");
+ for v in arg.default_missing_vals.iter() {
+ let trailing_values = false; // CLI should not be affecting default_missing_values
+ let _parse_result = self.split_arg_values(
+ arg,
+ &RawOsStr::new(v),
+ trailing_values,
+ &mut arg_values,
+ );
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!("Parser::parse_opt_value: Ignoring state {:?}; no values accepted after default_missing_values", _parse_result);
+ }
+ }
+ }
+ };
+ let react_result = self.react(
+ Some(ident),
+ ValueSource::CommandLine,
+ arg,
+ arg_values,
+ matcher,
+ )?;
+ debug_assert_eq!(react_result, ParseResult::ValuesDone);
+ if attached_value.is_some() {
+ Ok(ParseResult::AttachedValueNotConsumed)
+ } else {
+ Ok(ParseResult::ValuesDone)
+ }
+ } else {
+ debug!("Requires equals but not provided. Error.");
+ Ok(ParseResult::EqualsNotProvided {
+ arg: arg.to_string(),
+ })
+ }
+ } else if let Some(v) = attached_value {
+ let mut arg_values = Vec::new();
+ let parse_result = self.split_arg_values(arg, v, trailing_values, &mut arg_values);
+ let react_result = self.react(
+ Some(ident),
+ ValueSource::CommandLine,
+ arg,
+ arg_values,
+ matcher,
+ )?;
+ debug_assert_eq!(react_result, ParseResult::ValuesDone);
+ let mut parse_result = parse_result.unwrap_or_else(|| {
+ if matcher.needs_more_vals(arg) {
+ ParseResult::Opt(arg.id.clone())
+ } else {
+ ParseResult::ValuesDone
+ }
+ });
+ if parse_result != ParseResult::ValuesDone {
+ debug!("Parser::parse_opt_value: Overriding state {:?}; no values accepted after attached", parse_result);
+ parse_result = ParseResult::ValuesDone;
+ }
+ Ok(parse_result)
+ } else {
+ debug!("Parser::parse_opt_value: More arg vals required...");
+ self.resolve_pending(matcher)?;
+ matcher.pending_values_mut(&arg.id, Some(ident));
+ Ok(ParseResult::Opt(arg.id.clone()))
+ }
+ }
+
+ fn split_arg_values(
+ &self,
+ arg: &Arg<'help>,
+ val: &RawOsStr,
+ trailing_values: bool,
+ output: &mut Vec<OsString>,
+ ) -> Option<ParseResult> {
+ debug!("Parser::split_arg_values; arg={}, val={:?}", arg.name, val);
+ debug!(
+ "Parser::split_arg_values; trailing_values={:?}, DontDelimTrailingVals={:?}",
+ trailing_values,
+ self.cmd.is_dont_delimit_trailing_values_set()
+ );
+
+ let mut delim = arg.val_delim;
+ if trailing_values && self.cmd.is_dont_delimit_trailing_values_set() {
+ delim = None;
+ }
+ match delim {
+ Some(delim) if val.contains(delim) => {
+ let vals = val.split(delim).map(|x| x.to_os_str().into_owned());
+ for raw_val in vals {
+ if Some(raw_val.as_os_str()) == arg.terminator.map(OsStr::new) {
+ return Some(ParseResult::ValuesDone);
+ }
+ output.push(raw_val);
+ }
+ // Delimited values are always considered the final value
+ Some(ParseResult::ValuesDone)
+ }
+ _ if Some(val) == arg.terminator.map(RawOsStr::from_str) => {
+ Some(ParseResult::ValuesDone)
+ }
+ _ => {
+ output.push(val.to_os_str().into_owned());
+ if arg.is_require_value_delimiter_set() {
+ Some(ParseResult::ValuesDone)
+ } else {
+ None
+ }
+ }
+ }
+ }
+
+ fn push_arg_values(
+ &self,
+ arg: &Arg<'help>,
+ raw_vals: Vec<OsString>,
+ matcher: &mut ArgMatcher,
+ ) -> ClapResult<()> {
+ debug!("Parser::push_arg_values: {:?}", raw_vals);
+
+ for raw_val in raw_vals {
+ // update the current index because each value is a distinct index to clap
+ self.cur_idx.set(self.cur_idx.get() + 1);
+ debug!(
+ "Parser::add_single_val_to_arg: cur_idx:={}",
+ self.cur_idx.get()
+ );
+ let value_parser = arg.get_value_parser();
+ let val = value_parser.parse_ref(self.cmd, Some(arg), &raw_val)?;
+
+ // Increment or create the group "args"
+ for group in self.cmd.groups_for_arg(&arg.id) {
+ matcher.add_val_to(&group, val.clone(), raw_val.clone());
+ }
+
+ matcher.add_val_to(&arg.id, val, raw_val);
+ matcher.add_index_to(&arg.id, self.cur_idx.get());
+ }
+
+ Ok(())
+ }
+
+ fn resolve_pending(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
+ let pending = match matcher.take_pending() {
+ Some(pending) => pending,
+ None => {
+ return Ok(());
+ }
+ };
+
+ debug!("Parser::resolve_pending: id={:?}", pending.id);
+ let arg = self.cmd.find(&pending.id).expect(INTERNAL_ERROR_MSG);
+ let _ = self.react(
+ pending.ident,
+ ValueSource::CommandLine,
+ arg,
+ pending.raw_vals,
+ matcher,
+ )?;
+
+ Ok(())
+ }
+
+ fn react(
+ &self,
+ ident: Option<Identifier>,
+ source: ValueSource,
+ arg: &Arg<'help>,
+ raw_vals: Vec<OsString>,
+ matcher: &mut ArgMatcher,
+ ) -> ClapResult<ParseResult> {
+ self.resolve_pending(matcher)?;
+
+ debug!(
+ "Parser::react action={:?}, identifier={:?}, source={:?}",
+ arg.get_action(),
+ ident,
+ source
+ );
+ match arg.get_action() {
+ ArgAction::Set => {
+ if source == ValueSource::CommandLine
+ && matches!(ident, Some(Identifier::Short) | Some(Identifier::Long))
+ {
+ // Record flag's index
+ self.cur_idx.set(self.cur_idx.get() + 1);
+ debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
+ }
+ matcher.remove(&arg.id);
+ self.start_custom_arg(matcher, arg, source);
+ self.push_arg_values(arg, raw_vals, matcher)?;
+ if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
+ debug!(
+ "Parser::react not enough values passed in, leaving it to the validator to complain",
+ );
+ }
+ Ok(ParseResult::ValuesDone)
+ }
+ ArgAction::Append => {
+ if source == ValueSource::CommandLine
+ && matches!(ident, Some(Identifier::Short) | Some(Identifier::Long))
+ {
+ // Record flag's index
+ self.cur_idx.set(self.cur_idx.get() + 1);
+ debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
+ }
+ self.start_custom_arg(matcher, arg, source);
+ self.push_arg_values(arg, raw_vals, matcher)?;
+ if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
+ debug!(
+ "Parser::react not enough values passed in, leaving it to the validator to complain",
+ );
+ }
+ Ok(ParseResult::ValuesDone)
+ }
+ #[allow(deprecated)]
+ ArgAction::StoreValue => {
+ if ident == Some(Identifier::Index)
+ && arg.is_multiple_values_set()
+ && matcher.contains(&arg.id)
+ {
+ // HACK: Reuse existing occurrence
+ } else if source == ValueSource::CommandLine {
+ if matches!(ident, Some(Identifier::Short) | Some(Identifier::Long)) {
+ // Record flag's index
+ self.cur_idx.set(self.cur_idx.get() + 1);
+ debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
+ }
+ self.start_occurrence_of_arg(matcher, arg);
+ } else {
+ self.start_custom_arg(matcher, arg, source);
+ }
+ self.push_arg_values(arg, raw_vals, matcher)?;
+ if ident == Some(Identifier::Index) && arg.is_multiple_values_set() {
+ // HACK: Maintain existing occurrence behavior
+ let matched = matcher.get_mut(&arg.id).unwrap();
+ #[allow(deprecated)]
+ matched.set_occurrences(matched.num_vals() as u64);
+ }
+ if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
+ debug!(
+ "Parser::react not enough values passed in, leaving it to the validator to complain",
+ );
+ }
+ Ok(ParseResult::ValuesDone)
+ }
+ #[allow(deprecated)]
+ ArgAction::IncOccurrence => {
+ debug_assert_eq!(raw_vals, Vec::<OsString>::new());
+ if source == ValueSource::CommandLine {
+ if matches!(ident, Some(Identifier::Short) | Some(Identifier::Long)) {
+ // Record flag's index
+ self.cur_idx.set(self.cur_idx.get() + 1);
+ debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
+ }
+ self.start_occurrence_of_arg(matcher, arg);
+ } else {
+ self.start_custom_arg(matcher, arg, source);
+ }
+ matcher.add_index_to(&arg.id, self.cur_idx.get());
+ Ok(ParseResult::ValuesDone)
+ }
+ ArgAction::SetTrue => {
+ let raw_vals = match raw_vals.len() {
+ 0 => {
+ vec![OsString::from("true")]
+ }
+ 1 => raw_vals,
+ _ => {
+ debug!("Parser::react ignoring trailing values: {:?}", raw_vals);
+ let mut raw_vals = raw_vals;
+ raw_vals.resize(1, Default::default());
+ raw_vals
+ }
+ };
+
+ matcher.remove(&arg.id);
+ self.start_custom_arg(matcher, arg, source);
+ self.push_arg_values(arg, raw_vals, matcher)?;
+ Ok(ParseResult::ValuesDone)
+ }
+ ArgAction::SetFalse => {
+ let raw_vals = match raw_vals.len() {
+ 0 => {
+ vec![OsString::from("false")]
+ }
+ 1 => raw_vals,
+ _ => {
+ debug!("Parser::react ignoring trailing values: {:?}", raw_vals);
+ let mut raw_vals = raw_vals;
+ raw_vals.resize(1, Default::default());
+ raw_vals
+ }
+ };
+
+ matcher.remove(&arg.id);
+ self.start_custom_arg(matcher, arg, source);
+ self.push_arg_values(arg, raw_vals, matcher)?;
+ Ok(ParseResult::ValuesDone)
+ }
+ ArgAction::Count => {
+ let raw_vals = match raw_vals.len() {
+ 0 => {
+ let existing_value = *matcher
+ .get_one::<crate::builder::CountType>(arg.get_id())
+ .unwrap_or(&0);
+ let next_value = existing_value.saturating_add(1);
+ vec![OsString::from(next_value.to_string())]
+ }
+ 1 => raw_vals,
+ _ => {
+ debug!("Parser::react ignoring trailing values: {:?}", raw_vals);
+ let mut raw_vals = raw_vals;
+ raw_vals.resize(1, Default::default());
+ raw_vals
+ }
+ };
+
+ matcher.remove(&arg.id);
+ self.start_custom_arg(matcher, arg, source);
+ self.push_arg_values(arg, raw_vals, matcher)?;
+ Ok(ParseResult::ValuesDone)
+ }
+ ArgAction::Help => {
+ debug_assert_eq!(raw_vals, Vec::<OsString>::new());
+ let use_long = match ident {
+ Some(Identifier::Long) => true,
+ Some(Identifier::Short) => false,
+ Some(Identifier::Index) => true,
+ None => true,
+ };
+ debug!("Help: use_long={}", use_long);
+ Err(self.help_err(use_long, Stream::Stdout))
+ }
+ ArgAction::Version => {
+ debug_assert_eq!(raw_vals, Vec::<OsString>::new());
+ let use_long = match ident {
+ Some(Identifier::Long) => true,
+ Some(Identifier::Short) => false,
+ Some(Identifier::Index) => true,
+ None => true,
+ };
+ debug!("Version: use_long={}", use_long);
+ Err(self.version_err(use_long))
+ }
+ }
+ }
+
+ fn remove_overrides(&self, arg: &Arg<'help>, matcher: &mut ArgMatcher) {
+ debug!("Parser::remove_overrides: id={:?}", arg.id);
+ for override_id in &arg.overrides {
+ debug!("Parser::remove_overrides:iter:{:?}: removing", override_id);
+ matcher.remove(override_id);
+ }
+
+ // Override anything that can override us
+ let mut transitive = Vec::new();
+ for arg_id in matcher.arg_ids() {
+ if let Some(overrider) = self.cmd.find(arg_id) {
+ if overrider.overrides.contains(&arg.id) {
+ transitive.push(&overrider.id);
+ }
+ }
+ }
+ for overrider_id in transitive {
+ debug!("Parser::remove_overrides:iter:{:?}: removing", overrider_id);
+ matcher.remove(overrider_id);
+ }
+ }
+
+ #[cfg(feature = "env")]
+ fn add_env(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
+ debug!("Parser::add_env");
+ use crate::util::str_to_bool;
+
+ let trailing_values = false; // defaults are independent of the commandline
+ for arg in self.cmd.get_arguments() {
+ // Use env only if the arg was absent among command line args,
+ // early return if this is not the case.
+ if matcher.contains(&arg.id) {
+ debug!("Parser::add_env: Skipping existing arg `{}`", arg);
+ continue;
+ }
+
+ debug!("Parser::add_env: Checking arg `{}`", arg);
+ if let Some((_, Some(ref val))) = arg.env {
+ let val = RawOsStr::new(val);
+
+ if arg.is_takes_value_set() {
+ debug!(
+ "Parser::add_env: Found an opt with value={:?}, trailing={:?}",
+ val, trailing_values
+ );
+ let mut arg_values = Vec::new();
+ let _parse_result =
+ self.split_arg_values(arg, &val, trailing_values, &mut arg_values);
+ let _ = self.react(None, ValueSource::EnvVariable, arg, arg_values, matcher)?;
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!("Parser::add_env: Ignoring state {:?}; env variables are outside of the parse loop", _parse_result);
+ }
+ }
+ } else {
+ match arg.get_action() {
+ #[allow(deprecated)]
+ ArgAction::StoreValue => unreachable!("{:?} is not a flag", arg.get_id()),
+ #[allow(deprecated)]
+ ArgAction::IncOccurrence => {
+ debug!("Parser::add_env: Found a flag with value `{:?}`", val);
+ let predicate = str_to_bool(val.to_str_lossy());
+ debug!("Parser::add_env: Found boolean literal `{:?}`", predicate);
+ if predicate.unwrap_or(true) {
+ let _ = self.react(
+ None,
+ ValueSource::EnvVariable,
+ arg,
+ vec![],
+ matcher,
+ )?;
+ }
+ }
+ ArgAction::Set
+ | ArgAction::Append
+ | ArgAction::SetTrue
+ | ArgAction::SetFalse
+ | ArgAction::Count => {
+ let mut arg_values = Vec::new();
+ let _parse_result =
+ self.split_arg_values(arg, &val, trailing_values, &mut arg_values);
+ let _ = self.react(
+ None,
+ ValueSource::EnvVariable,
+ arg,
+ arg_values,
+ matcher,
+ )?;
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!("Parser::add_env: Ignoring state {:?}; env variables are outside of the parse loop", _parse_result);
+ }
+ }
+ }
+ // Early return on `Help` or `Version`.
+ ArgAction::Help | ArgAction::Version => {
+ let _ =
+ self.react(None, ValueSource::EnvVariable, arg, vec![], matcher)?;
+ }
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn add_defaults(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
+ debug!("Parser::add_defaults");
+
+ for arg in self.cmd.get_arguments() {
+ debug!("Parser::add_defaults:iter:{}:", arg.name);
+ self.add_default_value(arg, matcher)?;
+ }
+
+ Ok(())
+ }
+
+ fn add_default_value(&self, arg: &Arg<'help>, matcher: &mut ArgMatcher) -> ClapResult<()> {
+ let trailing_values = false; // defaults are independent of the commandline
+
+ if !arg.default_missing_vals.is_empty() {
+ debug!(
+ "Parser::add_default_value:iter:{}: has default missing vals",
+ arg.name
+ );
+ match matcher.get(&arg.id) {
+ Some(ma) if ma.all_val_groups_empty() => {
+ debug!(
+ "Parser::add_default_value:iter:{}: has no user defined vals",
+ arg.name
+ );
+ // The flag occurred, we just want to add the val groups
+ let mut arg_values = Vec::new();
+ for v in arg.default_missing_vals.iter() {
+ let _parse_result = self.split_arg_values(
+ arg,
+ &RawOsStr::new(v),
+ trailing_values,
+ &mut arg_values,
+ );
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!("Parser::add_default_value: Ignoring state {:?}; defaults are outside of the parse loop", _parse_result);
+ }
+ }
+ }
+ self.start_custom_arg(matcher, arg, ValueSource::CommandLine);
+ self.push_arg_values(arg, arg_values, matcher)?;
+ }
+ None => {
+ debug!("Parser::add_default_value:iter:{}: wasn't used", arg.name);
+ // do nothing
+ }
+ _ => {
+ debug!(
+ "Parser::add_default_value:iter:{}: has user defined vals",
+ arg.name
+ );
+ // do nothing
+ }
+ }
+ } else {
+ debug!(
+ "Parser::add_default_value:iter:{}: doesn't have default missing vals",
+ arg.name
+ );
+ // do nothing
+ }
+
+ if !arg.default_vals_ifs.is_empty() {
+ debug!("Parser::add_default_value: has conditional defaults");
+ if !matcher.contains(&arg.id) {
+ for (id, val, default) in arg.default_vals_ifs.iter() {
+ let add = if let Some(a) = matcher.get(id) {
+ match val {
+ crate::builder::ArgPredicate::Equals(v) => {
+ a.raw_vals_flatten().any(|value| v == value)
+ }
+ crate::builder::ArgPredicate::IsPresent => true,
+ }
+ } else {
+ false
+ };
+
+ if add {
+ if let Some(default) = default {
+ let mut arg_values = Vec::new();
+ let _parse_result = self.split_arg_values(
+ arg,
+ &RawOsStr::new(default),
+ trailing_values,
+ &mut arg_values,
+ );
+ let _ = self.react(
+ None,
+ ValueSource::DefaultValue,
+ arg,
+ arg_values,
+ matcher,
+ )?;
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!("Parser::add_default_value: Ignoring state {:?}; defaults are outside of the parse loop", _parse_result);
+ }
+ }
+ }
+ return Ok(());
+ }
+ }
+ }
+ } else {
+ debug!("Parser::add_default_value: doesn't have conditional defaults");
+ }
+
+ if !arg.default_vals.is_empty() {
+ debug!(
+ "Parser::add_default_value:iter:{}: has default vals",
+ arg.name
+ );
+ if matcher.contains(&arg.id) {
+ debug!("Parser::add_default_value:iter:{}: was used", arg.name);
+ // do nothing
+ } else {
+ debug!("Parser::add_default_value:iter:{}: wasn't used", arg.name);
+ let mut arg_values = Vec::new();
+ for v in arg.default_vals.iter() {
+ let _parse_result = self.split_arg_values(
+ arg,
+ &RawOsStr::new(v),
+ trailing_values,
+ &mut arg_values,
+ );
+ if let Some(_parse_result) = _parse_result {
+ if _parse_result != ParseResult::ValuesDone {
+ debug!("Parser::add_default_value: Ignoring state {:?}; defaults are outside of the parse loop", _parse_result);
+ }
+ }
+ }
+ let _ = self.react(None, ValueSource::DefaultValue, arg, arg_values, matcher)?;
+ }
+ } else {
+ debug!(
+ "Parser::add_default_value:iter:{}: doesn't have default vals",
+ arg.name
+ );
+
+ // do nothing
+ }
+
+ Ok(())
+ }
+
+ fn start_custom_arg(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>, source: ValueSource) {
+ if source == ValueSource::CommandLine {
+ // With each new occurrence, remove overrides from prior occurrences
+ self.remove_overrides(arg, matcher);
+ }
+ matcher.start_custom_arg(arg, source);
+ for group in self.cmd.groups_for_arg(&arg.id) {
+ matcher.start_custom_group(&group, source);
+ }
+ }
+
+ /// Increase occurrence of specific argument and the grouped arg it's in.
+ fn start_occurrence_of_arg(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>) {
+ // With each new occurrence, remove overrides from prior occurrences
+ self.remove_overrides(arg, matcher);
+
+ matcher.start_occurrence_of_arg(arg);
+ // Increment or create the group "args"
+ for group in self.cmd.groups_for_arg(&arg.id) {
+ matcher.start_occurrence_of_group(&group);
+ }
+ }
+}
+
+// Error, Help, and Version Methods
+impl<'help, 'cmd> Parser<'help, 'cmd> {
+ /// Is only used for the long flag(which is the only one needs fuzzy searching)
+ fn did_you_mean_error(
+ &mut self,
+ arg: &str,
+ matcher: &mut ArgMatcher,
+ remaining_args: &[&str],
+ ) -> ClapError {
+ debug!("Parser::did_you_mean_error: arg={}", arg);
+ // Didn't match a flag or option
+ let longs = self
+ .cmd
+ .get_keymap()
+ .keys()
+ .filter_map(|x| match x {
+ KeyType::Long(l) => Some(l.to_string_lossy().into_owned()),
+ _ => None,
+ })
+ .collect::<Vec<_>>();
+ debug!("Parser::did_you_mean_error: longs={:?}", longs);
+
+ let did_you_mean = suggestions::did_you_mean_flag(
+ arg,
+ remaining_args,
+ longs.iter().map(|x| &x[..]),
+ self.cmd.get_subcommands_mut(),
+ );
+
+ // Add the arg to the matches to build a proper usage string
+ if let Some((name, _)) = did_you_mean.as_ref() {
+ if let Some(arg) = self.cmd.get_keymap().get(&name.as_ref()) {
+ self.start_occurrence_of_arg(matcher, arg);
+ }
+ }
+
+ let required = self.cmd.required_graph();
+ let used: Vec<Id> = matcher
+ .arg_ids()
+ .filter(|arg_id| {
+ matcher.check_explicit(arg_id, crate::builder::ArgPredicate::IsPresent)
+ })
+ .filter(|n| self.cmd.find(n).map_or(true, |a| !a.is_hide_set()))
+ .cloned()
+ .collect();
+
+ ClapError::unknown_argument(
+ self.cmd,
+ format!("--{}", arg),
+ did_you_mean,
+ Usage::new(self.cmd)
+ .required(&required)
+ .create_usage_with_title(&*used),
+ )
+ }
+
+ fn help_err(&self, use_long: bool, stream: Stream) -> ClapError {
+ match self.cmd.write_help_err(use_long, stream) {
+ Ok(c) => ClapError::display_help(self.cmd, c),
+ Err(e) => e,
+ }
+ }
+
+ fn version_err(&self, use_long: bool) -> ClapError {
+ debug!("Parser::version_err");
+
+ let msg = self.cmd._render_version(use_long);
+ let mut c = Colorizer::new(Stream::Stdout, self.cmd.color_help());
+ c.none(msg);
+ ClapError::display_version(self.cmd, c)
+ }
+}
+
+// Query Methods
+impl<'help, 'cmd> Parser<'help, 'cmd> {
+ pub(crate) fn is_set(&self, s: AS) -> bool {
+ self.cmd.is_set(s)
+ }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) enum ParseState {
+ ValuesDone,
+ Opt(Id),
+ Pos(Id),
+}
+
+/// Recoverable Parsing results.
+#[derive(Debug, PartialEq, Clone)]
+#[must_use]
+enum ParseResult {
+ FlagSubCommand(String),
+ Opt(Id),
+ ValuesDone,
+ /// Value attached to the short flag is not consumed(e.g. 'u' for `-cu` is
+ /// not consumed).
+ AttachedValueNotConsumed,
+ /// This long flag doesn't need a value but is provided one.
+ UnneededAttachedValue {
+ rest: String,
+ used: Vec<Id>,
+ arg: String,
+ },
+ /// This flag might be an hyphen Value.
+ MaybeHyphenValue,
+ /// Equals required but not provided.
+ EqualsNotProvided {
+ arg: String,
+ },
+ /// Failed to match a Arg.
+ NoMatchingArg {
+ arg: String,
+ },
+ /// No argument found e.g. parser is given `-` when parsing a flag.
+ NoArg,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct PendingArg {
+ pub(crate) id: Id,
+ pub(crate) ident: Option<Identifier>,
+ pub(crate) raw_vals: Vec<OsString>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum Identifier {
+ Short,
+ Long,
+ Index,
+}
diff --git a/vendor/clap-3.2.20/src/parser/validator.rs b/vendor/clap-3.2.20/src/parser/validator.rs
new file mode 100644
index 000000000..ebf2b234d
--- /dev/null
+++ b/vendor/clap-3.2.20/src/parser/validator.rs
@@ -0,0 +1,692 @@
+// Internal
+use crate::builder::{AppSettings, Arg, ArgPredicate, Command, PossibleValue};
+use crate::error::{Error, Result as ClapResult};
+use crate::output::fmt::Stream;
+use crate::output::Usage;
+use crate::parser::{ArgMatcher, MatchedArg, ParseState};
+use crate::util::ChildGraph;
+use crate::util::Id;
+use crate::{INTERNAL_ERROR_MSG, INVALID_UTF8};
+
+pub(crate) struct Validator<'help, 'cmd> {
+ cmd: &'cmd Command<'help>,
+ required: ChildGraph<Id>,
+}
+
+impl<'help, 'cmd> Validator<'help, 'cmd> {
+ pub(crate) fn new(cmd: &'cmd Command<'help>) -> Self {
+ let required = cmd.required_graph();
+ Validator { cmd, required }
+ }
+
+ pub(crate) fn validate(
+ &mut self,
+ parse_state: ParseState,
+ matcher: &mut ArgMatcher,
+ ) -> ClapResult<()> {
+ debug!("Validator::validate");
+ let mut conflicts = Conflicts::new();
+ let has_subcmd = matcher.subcommand_name().is_some();
+
+ if let ParseState::Opt(a) = parse_state {
+ debug!("Validator::validate: needs_val_of={:?}", a);
+
+ let o = &self.cmd[&a];
+ let should_err = if let Some(v) = matcher.args.get(&o.id) {
+ v.all_val_groups_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
+ } else {
+ true
+ };
+ if should_err {
+ return Err(Error::empty_value(
+ self.cmd,
+ &get_possible_values(o)
+ .iter()
+ .filter(|pv| !pv.is_hide_set())
+ .map(PossibleValue::get_name)
+ .collect::<Vec<_>>(),
+ o.to_string(),
+ ));
+ }
+ }
+
+ if !has_subcmd && self.cmd.is_arg_required_else_help_set() {
+ let num_user_values = matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ .count();
+ if num_user_values == 0 {
+ let message = self.cmd.write_help_err(false, Stream::Stderr)?;
+ return Err(Error::display_help_error(self.cmd, message));
+ }
+ }
+ #[allow(deprecated)]
+ if !has_subcmd && self.cmd.is_subcommand_required_set() {
+ let bn = self
+ .cmd
+ .get_bin_name()
+ .unwrap_or_else(|| self.cmd.get_name());
+ return Err(Error::missing_subcommand(
+ self.cmd,
+ bn.to_string(),
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ));
+ } else if !has_subcmd && self.cmd.is_set(AppSettings::SubcommandRequiredElseHelp) {
+ debug!("Validator::new::get_matches_with: SubcommandRequiredElseHelp=true");
+ let message = self.cmd.write_help_err(false, Stream::Stderr)?;
+ return Err(Error::display_help_error(self.cmd, message));
+ }
+
+ self.validate_conflicts(matcher, &mut conflicts)?;
+ if !(self.cmd.is_subcommand_negates_reqs_set() && has_subcmd) {
+ self.validate_required(matcher, &mut conflicts)?;
+ }
+ self.validate_matched_args(matcher)?;
+
+ Ok(())
+ }
+
+ fn validate_arg_values(&self, arg: &Arg, ma: &MatchedArg) -> ClapResult<()> {
+ debug!("Validator::validate_arg_values: arg={:?}", arg.name);
+ for val in ma.raw_vals_flatten() {
+ if !arg.possible_vals.is_empty() {
+ debug!(
+ "Validator::validate_arg_values: possible_vals={:?}",
+ arg.possible_vals
+ );
+ let val_str = val.to_string_lossy();
+ let ok = arg
+ .possible_vals
+ .iter()
+ .any(|pv| pv.matches(&val_str, arg.is_ignore_case_set()));
+ if !ok {
+ return Err(Error::invalid_value(
+ self.cmd,
+ val_str.into_owned(),
+ &arg.possible_vals
+ .iter()
+ .filter(|pv| !pv.is_hide_set())
+ .map(PossibleValue::get_name)
+ .collect::<Vec<_>>(),
+ arg.to_string(),
+ ));
+ }
+ }
+ {
+ #![allow(deprecated)]
+ if arg.is_forbid_empty_values_set() && val.is_empty() {
+ debug!("Validator::validate_arg_values: illegal empty val found");
+ return Err(Error::empty_value(
+ self.cmd,
+ &get_possible_values(arg)
+ .iter()
+ .filter(|pv| !pv.is_hide_set())
+ .map(PossibleValue::get_name)
+ .collect::<Vec<_>>(),
+ arg.to_string(),
+ ));
+ }
+ }
+
+ if let Some(ref vtor) = arg.validator {
+ debug!("Validator::validate_arg_values: checking validator...");
+ let mut vtor = vtor.lock().unwrap();
+ if let Err(e) = vtor(&*val.to_string_lossy()) {
+ debug!("error");
+ return Err(Error::value_validation(
+ arg.to_string(),
+ val.to_string_lossy().into_owned(),
+ e,
+ )
+ .with_cmd(self.cmd));
+ } else {
+ debug!("good");
+ }
+ }
+ if let Some(ref vtor) = arg.validator_os {
+ debug!("Validator::validate_arg_values: checking validator_os...");
+ let mut vtor = vtor.lock().unwrap();
+ if let Err(e) = vtor(val) {
+ debug!("error");
+ return Err(Error::value_validation(
+ arg.to_string(),
+ val.to_string_lossy().into(),
+ e,
+ )
+ .with_cmd(self.cmd));
+ } else {
+ debug!("good");
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn validate_conflicts(
+ &mut self,
+ matcher: &ArgMatcher,
+ conflicts: &mut Conflicts,
+ ) -> ClapResult<()> {
+ debug!("Validator::validate_conflicts");
+
+ self.validate_exclusive(matcher)?;
+
+ for arg_id in matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ .filter(|arg_id| self.cmd.find(arg_id).is_some())
+ {
+ debug!("Validator::validate_conflicts::iter: id={:?}", arg_id);
+ let conflicts = conflicts.gather_conflicts(self.cmd, matcher, arg_id);
+ self.build_conflict_err(arg_id, &conflicts, matcher)?;
+ }
+
+ Ok(())
+ }
+
+ fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> {
+ debug!("Validator::validate_exclusive");
+ let args_count = matcher
+ .arg_ids()
+ .filter(|arg_id| {
+ matcher.check_explicit(arg_id, crate::builder::ArgPredicate::IsPresent)
+ })
+ .count();
+ if args_count <= 1 {
+ // Nothing present to conflict with
+ return Ok(());
+ }
+
+ matcher
+ .arg_ids()
+ .filter(|arg_id| {
+ matcher.check_explicit(arg_id, crate::builder::ArgPredicate::IsPresent)
+ })
+ .filter_map(|name| {
+ debug!("Validator::validate_exclusive:iter:{:?}", name);
+ self.cmd
+ .find(name)
+ // Find `arg`s which are exclusive but also appear with other args.
+ .filter(|&arg| arg.is_exclusive_set() && args_count > 1)
+ })
+ // Throw an error for the first conflict found.
+ .try_for_each(|arg| {
+ Err(Error::argument_conflict(
+ self.cmd,
+ arg.to_string(),
+ Vec::new(),
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ))
+ })
+ }
+
+ fn build_conflict_err(
+ &self,
+ name: &Id,
+ conflict_ids: &[Id],
+ matcher: &ArgMatcher,
+ ) -> ClapResult<()> {
+ if conflict_ids.is_empty() {
+ return Ok(());
+ }
+
+ debug!("Validator::build_conflict_err: name={:?}", name);
+ let mut seen = std::collections::HashSet::new();
+ let conflicts = conflict_ids
+ .iter()
+ .flat_map(|c_id| {
+ if self.cmd.find_group(c_id).is_some() {
+ self.cmd.unroll_args_in_group(c_id)
+ } else {
+ vec![c_id.clone()]
+ }
+ })
+ .filter_map(|c_id| {
+ seen.insert(c_id.clone()).then(|| {
+ let c_arg = self.cmd.find(&c_id).expect(INTERNAL_ERROR_MSG);
+ c_arg.to_string()
+ })
+ })
+ .collect();
+
+ let former_arg = self.cmd.find(name).expect(INTERNAL_ERROR_MSG);
+ let usg = self.build_conflict_err_usage(matcher, conflict_ids);
+ Err(Error::argument_conflict(
+ self.cmd,
+ former_arg.to_string(),
+ conflicts,
+ usg,
+ ))
+ }
+
+ fn build_conflict_err_usage(&self, matcher: &ArgMatcher, conflicting_keys: &[Id]) -> String {
+ let used_filtered: Vec<Id> = matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ .filter(|n| {
+ // Filter out the args we don't want to specify.
+ self.cmd.find(n).map_or(true, |a| !a.is_hide_set())
+ })
+ .filter(|key| !conflicting_keys.contains(key))
+ .cloned()
+ .collect();
+ let required: Vec<Id> = used_filtered
+ .iter()
+ .filter_map(|key| self.cmd.find(key))
+ .flat_map(|arg| arg.requires.iter().map(|item| &item.1))
+ .filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key))
+ .chain(used_filtered.iter())
+ .cloned()
+ .collect();
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&required)
+ }
+
+ fn gather_requires(&mut self, matcher: &ArgMatcher) {
+ debug!("Validator::gather_requires");
+ for name in matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ {
+ debug!("Validator::gather_requires:iter:{:?}", name);
+ if let Some(arg) = self.cmd.find(name) {
+ let is_relevant = |(val, req_arg): &(ArgPredicate<'_>, Id)| -> Option<Id> {
+ let required = matcher.check_explicit(&arg.id, *val);
+ required.then(|| req_arg.clone())
+ };
+
+ for req in self.cmd.unroll_arg_requires(is_relevant, &arg.id) {
+ self.required.insert(req);
+ }
+ } else if let Some(g) = self.cmd.find_group(name) {
+ debug!("Validator::gather_requires:iter:{:?}:group", name);
+ for r in &g.requires {
+ self.required.insert(r.clone());
+ }
+ }
+ }
+ }
+
+ fn validate_matched_args(&self, matcher: &ArgMatcher) -> ClapResult<()> {
+ debug!("Validator::validate_matched_args");
+ matcher.iter().try_for_each(|(name, ma)| {
+ debug!(
+ "Validator::validate_matched_args:iter:{:?}: vals={:#?}",
+ name,
+ ma.vals_flatten()
+ );
+ if let Some(arg) = self.cmd.find(name) {
+ self.validate_arg_num_vals(arg, ma)?;
+ self.validate_arg_values(arg, ma)?;
+ self.validate_arg_num_occurs(arg, ma)?;
+ }
+ Ok(())
+ })
+ }
+
+ fn validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> {
+ #![allow(deprecated)]
+ debug!(
+ "Validator::validate_arg_num_occurs: {:?}={}",
+ a.name,
+ ma.get_occurrences()
+ );
+ // Occurrence of positional argument equals to number of values rather
+ // than number of grouped values.
+ if ma.get_occurrences() > 1 && !a.is_multiple_occurrences_set() && !a.is_positional() {
+ // Not the first time, and we don't allow multiples
+ return Err(Error::unexpected_multiple_usage(
+ self.cmd,
+ a.to_string(),
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ));
+ }
+ if let Some(max_occurs) = a.max_occurs {
+ debug!(
+ "Validator::validate_arg_num_occurs: max_occurs set...{}",
+ max_occurs
+ );
+ let occurs = ma.get_occurrences() as usize;
+ if occurs > max_occurs {
+ return Err(Error::too_many_occurrences(
+ self.cmd,
+ a.to_string(),
+ max_occurs,
+ occurs,
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ));
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_arg_num_vals(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> {
+ debug!("Validator::validate_arg_num_vals");
+ if let Some(num) = a.num_vals {
+ let total_num = ma.num_vals();
+ debug!("Validator::validate_arg_num_vals: num_vals set...{}", num);
+ #[allow(deprecated)]
+ let should_err = if a.is_multiple_occurrences_set() {
+ total_num % num != 0
+ } else {
+ num != total_num
+ };
+ if should_err {
+ debug!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
+ return Err(Error::wrong_number_of_values(
+ self.cmd,
+ a.to_string(),
+ num,
+ #[allow(deprecated)]
+ if a.is_multiple_occurrences_set() {
+ total_num % num
+ } else {
+ total_num
+ },
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ));
+ }
+ }
+ if let Some(num) = a.max_vals {
+ debug!("Validator::validate_arg_num_vals: max_vals set...{}", num);
+ if ma.num_vals() > num {
+ debug!("Validator::validate_arg_num_vals: Sending error TooManyValues");
+ return Err(Error::too_many_values(
+ self.cmd,
+ ma.raw_vals_flatten()
+ .last()
+ .expect(INTERNAL_ERROR_MSG)
+ .to_str()
+ .expect(INVALID_UTF8)
+ .to_string(),
+ a.to_string(),
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ));
+ }
+ }
+ let min_vals_zero = if let Some(num) = a.min_vals {
+ debug!("Validator::validate_arg_num_vals: min_vals set: {}", num);
+ if ma.num_vals() < num && num != 0 {
+ debug!("Validator::validate_arg_num_vals: Sending error TooFewValues");
+ return Err(Error::too_few_values(
+ self.cmd,
+ a.to_string(),
+ num,
+ ma.num_vals(),
+ Usage::new(self.cmd)
+ .required(&self.required)
+ .create_usage_with_title(&[]),
+ ));
+ }
+ num == 0
+ } else {
+ false
+ };
+ // Issue 665 (https://github.com/clap-rs/clap/issues/665)
+ // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
+ if a.is_takes_value_set() && !min_vals_zero && ma.all_val_groups_empty() {
+ return Err(Error::empty_value(
+ self.cmd,
+ &get_possible_values(a)
+ .iter()
+ .filter(|pv| !pv.is_hide_set())
+ .map(PossibleValue::get_name)
+ .collect::<Vec<_>>(),
+ a.to_string(),
+ ));
+ }
+ Ok(())
+ }
+
+ fn validate_required(
+ &mut self,
+ matcher: &ArgMatcher,
+ conflicts: &mut Conflicts,
+ ) -> ClapResult<()> {
+ debug!("Validator::validate_required: required={:?}", self.required);
+ self.gather_requires(matcher);
+
+ let is_exclusive_present = matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ .any(|id| {
+ self.cmd
+ .find(id)
+ .map(|arg| arg.is_exclusive_set())
+ .unwrap_or_default()
+ });
+ debug!(
+ "Validator::validate_required: is_exclusive_present={}",
+ is_exclusive_present
+ );
+
+ for arg_or_group in self
+ .required
+ .iter()
+ .filter(|r| !matcher.check_explicit(r, ArgPredicate::IsPresent))
+ {
+ debug!("Validator::validate_required:iter:aog={:?}", arg_or_group);
+ if let Some(arg) = self.cmd.find(arg_or_group) {
+ debug!("Validator::validate_required:iter: This is an arg");
+ if !is_exclusive_present && !self.is_missing_required_ok(arg, matcher, conflicts) {
+ return self.missing_required_error(matcher, vec![]);
+ }
+ } else if let Some(group) = self.cmd.find_group(arg_or_group) {
+ debug!("Validator::validate_required:iter: This is a group");
+ if !self
+ .cmd
+ .unroll_args_in_group(&group.id)
+ .iter()
+ .any(|a| matcher.check_explicit(a, ArgPredicate::IsPresent))
+ {
+ return self.missing_required_error(matcher, vec![]);
+ }
+ }
+ }
+
+ // Validate the conditionally required args
+ for a in self.cmd.get_arguments() {
+ for (other, val) in &a.r_ifs {
+ if matcher.check_explicit(other, ArgPredicate::Equals(std::ffi::OsStr::new(*val)))
+ && !matcher.check_explicit(&a.id, ArgPredicate::IsPresent)
+ {
+ return self.missing_required_error(matcher, vec![a.id.clone()]);
+ }
+ }
+
+ let match_all = a.r_ifs_all.iter().all(|(other, val)| {
+ matcher.check_explicit(other, ArgPredicate::Equals(std::ffi::OsStr::new(*val)))
+ });
+ if match_all
+ && !a.r_ifs_all.is_empty()
+ && !matcher.check_explicit(&a.id, ArgPredicate::IsPresent)
+ {
+ return self.missing_required_error(matcher, vec![a.id.clone()]);
+ }
+ }
+
+ self.validate_required_unless(matcher)?;
+
+ Ok(())
+ }
+
+ fn is_missing_required_ok(
+ &self,
+ a: &Arg<'help>,
+ matcher: &ArgMatcher,
+ conflicts: &mut Conflicts,
+ ) -> bool {
+ debug!("Validator::is_missing_required_ok: {}", a.name);
+ let conflicts = conflicts.gather_conflicts(self.cmd, matcher, &a.id);
+ !conflicts.is_empty()
+ }
+
+ fn validate_required_unless(&self, matcher: &ArgMatcher) -> ClapResult<()> {
+ debug!("Validator::validate_required_unless");
+ let failed_args: Vec<_> = self
+ .cmd
+ .get_arguments()
+ .filter(|&a| {
+ (!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
+ && !matcher.check_explicit(&a.id, ArgPredicate::IsPresent)
+ && self.fails_arg_required_unless(a, matcher)
+ })
+ .map(|a| a.id.clone())
+ .collect();
+ if failed_args.is_empty() {
+ Ok(())
+ } else {
+ self.missing_required_error(matcher, failed_args)
+ }
+ }
+
+ // Failing a required unless means, the arg's "unless" wasn't present, and neither were they
+ fn fails_arg_required_unless(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
+ debug!("Validator::fails_arg_required_unless: a={:?}", a.name);
+ let exists = |id| matcher.check_explicit(id, ArgPredicate::IsPresent);
+
+ (a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists))
+ && !a.r_unless.iter().any(exists)
+ }
+
+ // `incl`: an arg to include in the error even if not used
+ fn missing_required_error(&self, matcher: &ArgMatcher, incl: Vec<Id>) -> ClapResult<()> {
+ debug!("Validator::missing_required_error; incl={:?}", incl);
+ debug!(
+ "Validator::missing_required_error: reqs={:?}",
+ self.required
+ );
+
+ let usg = Usage::new(self.cmd).required(&self.required);
+
+ let req_args = usg
+ .get_required_usage_from(&incl, Some(matcher), true)
+ .into_iter()
+ .collect::<Vec<_>>();
+
+ debug!(
+ "Validator::missing_required_error: req_args={:#?}",
+ req_args
+ );
+
+ let used: Vec<Id> = matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ .filter(|n| {
+ // Filter out the args we don't want to specify.
+ self.cmd.find(n).map_or(true, |a| !a.is_hide_set())
+ })
+ .cloned()
+ .chain(incl)
+ .collect();
+
+ Err(Error::missing_required_argument(
+ self.cmd,
+ req_args,
+ usg.create_usage_with_title(&used),
+ ))
+ }
+}
+
+#[derive(Default, Clone, Debug)]
+struct Conflicts {
+ potential: std::collections::HashMap<Id, Vec<Id>>,
+}
+
+impl Conflicts {
+ fn new() -> Self {
+ Self::default()
+ }
+
+ fn gather_conflicts(&mut self, cmd: &Command, matcher: &ArgMatcher, arg_id: &Id) -> Vec<Id> {
+ debug!("Conflicts::gather_conflicts: arg={:?}", arg_id);
+ let mut conflicts = Vec::new();
+ for other_arg_id in matcher
+ .arg_ids()
+ .filter(|arg_id| matcher.check_explicit(arg_id, ArgPredicate::IsPresent))
+ {
+ if arg_id == other_arg_id {
+ continue;
+ }
+
+ if self
+ .gather_direct_conflicts(cmd, arg_id)
+ .contains(other_arg_id)
+ {
+ conflicts.push(other_arg_id.clone());
+ }
+ if self
+ .gather_direct_conflicts(cmd, other_arg_id)
+ .contains(arg_id)
+ {
+ conflicts.push(other_arg_id.clone());
+ }
+ }
+ debug!("Conflicts::gather_conflicts: conflicts={:?}", conflicts);
+ conflicts
+ }
+
+ fn gather_direct_conflicts(&mut self, cmd: &Command, arg_id: &Id) -> &[Id] {
+ self.potential.entry(arg_id.clone()).or_insert_with(|| {
+ let conf = if let Some(arg) = cmd.find(arg_id) {
+ let mut conf = arg.blacklist.clone();
+ for group_id in cmd.groups_for_arg(arg_id) {
+ let group = cmd.find_group(&group_id).expect(INTERNAL_ERROR_MSG);
+ conf.extend(group.conflicts.iter().cloned());
+ if !group.multiple {
+ for member_id in &group.args {
+ if member_id != arg_id {
+ conf.push(member_id.clone());
+ }
+ }
+ }
+ }
+
+ // Overrides are implicitly conflicts
+ conf.extend(arg.overrides.iter().cloned());
+
+ conf
+ } else if let Some(group) = cmd.find_group(arg_id) {
+ group.conflicts.clone()
+ } else {
+ debug_assert!(false, "id={:?} is unknown", arg_id);
+ Vec::new()
+ };
+ debug!(
+ "Conflicts::gather_direct_conflicts id={:?}, conflicts={:?}",
+ arg_id, conf
+ );
+ conf
+ })
+ }
+}
+
+fn get_possible_values<'help>(a: &Arg<'help>) -> Vec<PossibleValue<'help>> {
+ #![allow(deprecated)]
+ if !a.is_takes_value_set() {
+ vec![]
+ } else if let Some(pvs) = a.get_possible_values() {
+ // Check old first in case the user explicitly set possible values and the derive inferred
+ // a `ValueParser` with some.
+ pvs.to_vec()
+ } else {
+ a.get_value_parser()
+ .possible_values()
+ .map(|pvs| pvs.collect())
+ .unwrap_or_default()
+ }
+}