blob: ad2bc6e9ca63b912420c49b50df415e7cb3a0ba5 [file] [log] [blame]
// 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,
}