summaryrefslogtreecommitdiffstats
path: root/vendor/clap-3.2.20/src/parser/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap-3.2.20/src/parser/parser.rs')
-rw-r--r--vendor/clap-3.2.20/src/parser/parser.rs1729
1 files changed, 1729 insertions, 0 deletions
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,
+}