pub(crate) struct Parser<'cmd> {
cmd: &'cmd mut Command,
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,
}
// Already met any valid arg(then we shouldn't expect subcommands after it). letmut valid_arg_found = false; // If the user already passed '--'. Meaning only positional args follow. letmut 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());
// Has the user already passed '--'? Meaning only positional args follow if !trailing_values { ifself.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:?}"); iflet Some(sc_name) = sc_name { if sc_name == "help" && !self.cmd.is_disable_help_subcommand_set() {
ok!(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;
matcher.start_trailing(); continue;
}
} elseiflet Some((long_arg, long_value)) = arg_os.to_long() { let parse_result = ok!(self.parse_long_arg(
matcher,
long_arg,
long_value,
&parse_state,
pos_counter,
&mut valid_arg_found,
));
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).collect(); return Err(self.did_you_mean_error(
&arg,
matcher,
&remaining_args,
trailing_values,
));
}
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_with_title(&used),
));
}
ParseResult::MaybeHyphenValue => { // Maybe a hyphen value, do nothing.
}
ParseResult::AttachedValueNotConsumed => {
unreachable!()
}
}
} elseiflet 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 = ok!(self.parse_short_arg(
matcher,
short_arg,
&parse_state,
pos_counter,
&mut valid_arg_found,
)); // 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();
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); // We already know it looks like a flag let suggested_trailing_arg =
!trailing_values && self.cmd.has_positionals(); return Err(ClapError::unknown_argument( self.cmd,
arg,
None,
suggested_trailing_arg,
Usage::new(self.cmd).create_usage_with_title(&[]),
));
}
ParseResult::MaybeHyphenValue => { // Maybe a hyphen value, do nothing.
}
ParseResult::UnneededAttachedValue { .. }
| ParseResult::AttachedValueNotConsumed => unreachable!(),
}
}
iflet 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 = &self.cmd[id]; let parse_result = iflet Some(parse_result) = self.check_terminator(arg, arg_os.to_value_os())
{
parse_result
} else { let trailing_values = false; let arg_values = matcher.pending_values_mut(id, None, trailing_values);
arg_values.push(arg_os.to_value_os().to_owned()); if matcher.needs_more_vals(arg) {
ParseResult::Opt(arg.get_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;
}
}
// 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.get_index().unwrap_or(0))
})
&& self
.cmd
.get_positionals()
.last()
.map(|p_name| !p_name.is_last_set())
.unwrap_or_default();
let is_terminated = self
.cmd
.get_keymap()
.get(&pos_counter)
.map(|a| a.get_value_terminator().is_some())
.unwrap_or_default();
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) && !is_terminated { let skip_current = iflet Some(n) = raw_args.peek(&args_cursor) { iflet Some(arg) = self
.cmd
.get_positionals()
.find(|a| a.get_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
}
} elseif 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
}
};
iflet Some(arg) = self.cmd.get_keymap().get(&pos_counter) { if arg.is_last_set() && !trailing_values { let _ = self.resolve_pending(matcher); // Its already considered a positional, we don't need to suggest turning it // into one let suggested_trailing_arg = false; return Err(ClapError::unknown_argument( self.cmd,
arg_os.display().to_string(),
None,
suggested_trailing_arg,
Usage::new(self.cmd).create_usage_with_title(&[]),
));
}
if arg.is_trailing_var_arg_set() {
trailing_values = true;
}
for raw_val in raw_args.remaining(&mut args_cursor) { let val = ok!(external_parser.parse_ref( self.cmd,
None,
raw_val,
ValueSource::CommandLine
)); let external_id = Id::from_static_ref(Id::EXTERNAL);
sc_m.add_val_to(&external_id, val, raw_val.to_os_string());
}
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() { return ClapError::invalid_subcommand( self.cmd,
arg_os.display().to_string(),
candidates, self.cmd.get_bin_name_fallback().to_owned(),
suggested_trailing_arg,
Usage::new(self.cmd).create_usage_with_title(&[]),
);
}
// If the argument must be a subcommand. if !self.cmd.has_positionals() || self.cmd.is_infer_subcommands_set() { return ClapError::unrecognized_subcommand( self.cmd,
arg_os.display().to_string(),
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, &OsStr>,
valid_arg_found: bool,
) -> Option<&str> {
debug!("Parser::possible_subcommand: arg={arg:?}"); let arg = some!(arg.ok());
if !(self.cmd.is_args_conflicts_with_subcommands_set() && valid_arg_found) { ifself.cmd.is_infer_subcommands_set() { // For subcommand `test`, we accepts it's prefix: `t`, `te`, // `tes` and `test`. letmut iter = self.cmd.get_subcommands().filter_map(|s| { if s.get_name().starts_with(arg) { return Some(s.get_name());
}
// Use find here instead of chaining the iterator because we want to accept // conflicts in aliases.
s.get_all_aliases().find(|s| s.starts_with(arg))
});
iflet name @ Some(_) = iter.next() { if iter.next().is_none() { return name;
}
}
} // Don't use an else here because we want inference to support exact matching even if // there are conflicts. iflet 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:?}"); ifself.cmd.is_infer_subcommands_set() { letmut iter = self.cmd.get_subcommands().filter_map(|sc| {
sc.get_long_flag().and_then(|long| { if long.starts_with(arg) {
Some(sc.get_name())
} else {
sc.get_all_long_flag_aliases().find_map(|alias| { if alias.starts_with(arg) {
Some(sc.get_name())
} else {
None
}
})
}
})
});
ifself.cmd[current_positional.get_id()].is_allow_hyphen_values_set()
|| (self.cmd[current_positional.get_id()].is_allow_negative_numbers_set()
&& next.is_negative_number())
{ // If allow hyphen, this isn't a new arg.
debug!("Parser::is_new_arg: Allow hyphen"); false
} elseif next.is_long() { // If this is a long flag, this is a new arg.
debug!("Parser::is_new_arg: --<something> found"); true
} elseif next.is_short() { // If this is a short flag, this is a new arg. But a single '-' 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
}
}
debug!( "Parser::parse_subcommand: About to parse sc={}",
sc.get_name()
);
{ letmut 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;
} iflet 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 {
name: sc.get_name().to_owned(),
matches: sc_matcher.into_inner(),
});
}
Ok(())
}
fn parse_long_arg(
&mutself,
matcher: &mut ArgMatcher,
long_arg: Result<&str, &OsStr>,
long_value: Option<&OsStr>,
parse_state: &ParseState,
pos_counter: usize,
valid_arg_found: &mut bool,
) -> ClapResult<ParseResult> { // maybe here lifetime should be 'a
debug!("Parser::parse_long_arg");
#[allow(clippy::blocks_in_conditions)] if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt) if self.cmd[opt].is_allow_hyphen_values_set())
{
debug!("Parser::parse_long_arg: prior arg accepts hyphenated values",); 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_os) => { return Ok(ParseResult::NoMatchingArg {
arg: long_arg_os.to_string_lossy().into_owned(),
})
}
}; if long_arg.is_empty() {
debug_assert!(
long_value.is_some(), "`--` should be filtered out before this point"
);
}
let arg = iflet Some(arg) = self.cmd.get_keymap().get(long_arg) {
debug!("Parser::parse_long_arg: Found valid arg or flag '{arg}'");
Some((long_arg, arg))
} elseifself.cmd.is_infer_long_args_set() { letmut iter = self.cmd.get_arguments().filter_map(|a| { iflet Some(long) = a.get_long() { if long.starts_with(long_arg) { return Some((long, a));
}
}
a.aliases
.iter()
.find_map(|(alias, _)| alias.starts_with(long_arg).then(|| (alias.as_str(), a)))
});
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:?}`"
); whilelet Some(c) = short_arg.next_flag() { let c = match c {
Ok(c) => c,
Err(rest) => { return Ok(ParseResult::NoMatchingArg {
arg: format!("-{}", rest.to_string_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 iflet Some(arg) = self.cmd.get_keymap().get(&c) { let ident = Identifier::Short;
debug!("Parser::parse_short_arg:iter:{c}: Found valid opt or flag");
*valid_arg_found = true; if !arg.is_takes_value_set() { let arg_values = Vec::new(); let trailing_idx = None;
ret = ok!(self.react(
Some(ident),
ValueSource::CommandLine,
arg,
arg_values,
trailing_idx,
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:{c}: val={val:?}, short_arg={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) = iflet Some(val) = val.and_then(|v| v.strip_prefix("=")) {
(Some(val), true)
} else {
(val, false)
}; match ok!(self.parse_opt_value(ident, val, arg, matcher, has_eq)) {
ParseResult::AttachedValueNotConsumed => continue,
x => return Ok(x),
}
}
returniflet Some(sc_name) = self.cmd.find_short_subcmd(c) {
debug!("Parser::parse_short_arg:iter:{c}: subcommand={sc_name}"); // Make sure indices get updated before reading `self.cur_idx`
ok!(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)
}
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 = ok!(value_parser.parse_ref(self.cmd, Some(arg), &raw_val, source));
// Process before `default_missing_values` to avoid it counting as values from the command // line if source == ValueSource::CommandLine {
ok!(self.verify_num_args(arg, &raw_vals));
}
if raw_vals.is_empty() { // We assume this case is valid: require equals, but min_vals == 0. if !arg.default_missing_vals.is_empty() {
debug!("Parser::react: has default_missing_vals");
trailing_idx = None;
raw_vals.extend(
arg.default_missing_vals
.iter()
.map(|s| s.as_os_str().to_owned()),
);
}
}
iflet Some(val_delim) = arg.get_value_delimiter() { ifself.cmd.is_dont_delimit_trailing_values_set() && trailing_idx == Some(0) { // Nothing to do
} else { letmut val_delim_buffer = [0; 4]; let val_delim = val_delim.encode_utf8(&mut val_delim_buffer); letmut split_raw_vals = Vec::with_capacity(raw_vals.len()); for (i, raw_val) in raw_vals.into_iter().enumerate() { if !raw_val.contains(val_delim)
|| (self.cmd.is_dont_delimit_trailing_values_set()
&& trailing_idx == Some(i))
{
split_raw_vals.push(raw_val);
} else {
split_raw_vals.extend(raw_val.split(val_delim).map(|x| x.to_owned()));
}
}
raw_vals = split_raw_vals;
}
}
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());
} if matcher.remove(arg.get_id())
&& !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
{ return Err(ClapError::argument_conflict( self.cmd,
arg.to_string(),
vec![arg.to_string()],
Usage::new(self.cmd).create_usage_with_title(&[]),
));
} self.start_custom_arg(matcher, arg, source);
ok!(self.push_arg_values(arg, raw_vals, source, 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);
ok!(self.push_arg_values(arg, raw_vals, source, 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::SetTrue => { let raw_vals = if raw_vals.is_empty() {
vec![OsString::from("true")]
} else {
raw_vals
};
fn remove_overrides(&self, arg: &Arg, matcher: &mut ArgMatcher) {
debug!("Parser::remove_overrides: id={:?}", arg.id); for override_id in &arg.overrides {
debug!("Parser::remove_overrides:iter:{override_id:?}: removing");
matcher.remove(override_id);
}
// Override anything that can override us letmut transitive = Vec::new(); for arg_id in matcher.arg_ids() { iflet Some(overrider) = self.cmd.find(arg_id) { if overrider.overrides.contains(arg.get_id()) {
transitive.push(overrider.get_id());
}
}
} for overrider_id in transitive {
debug!("Parser::remove_overrides:iter:{overrider_id:?}: removing");
matcher.remove(overrider_id);
}
}
for arg inself.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}`"); iflet Some((_, Some(ref val))) = arg.env {
debug!("Parser::add_env: Found an opt with value={val:?}"); let arg_values = vec![val.to_owned()]; let trailing_idx = None; let _ = ok!(self.react(
None,
ValueSource::EnvVariable,
arg,
arg_values,
trailing_idx,
matcher,
));
}
}
for arg inself.cmd.get_arguments() {
debug!("Parser::add_defaults:iter:{}:", arg.get_id());
ok!(self.add_default_value(arg, matcher));
}
Ok(())
}
fn add_default_value(&self, arg: &Arg, matcher: &mut ArgMatcher) -> ClapResult<()> { if !arg.default_vals_ifs.is_empty() {
debug!("Parser::add_default_value: has conditional defaults"); if !matcher.contains(arg.get_id()) { for (id, val, default) in arg.default_vals_ifs.iter() { let add = iflet 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 { iflet Some(default) = default { let arg_values = vec![default.to_os_string()]; let trailing_idx = None; let _ = ok!(self.react(
None,
ValueSource::DefaultValue,
arg,
arg_values,
trailing_idx,
matcher,
));
} 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.get_id()
); if matcher.contains(arg.get_id()) {
debug!("Parser::add_default_value:iter:{}: was used", arg.get_id()); // do nothing
} else {
debug!( "Parser::add_default_value:iter:{}: wasn't used",
arg.get_id()
); let arg_values: Vec<_> = arg
.default_vals
.iter()
.map(crate::builder::OsStr::to_os_string)
.collect(); let trailing_idx = None; let _ = ok!(self.react(
None,
ValueSource::DefaultValue,
arg,
arg_values,
trailing_idx,
matcher,
));
}
} else {
debug!( "Parser::add_default_value:iter:{}: doesn't have default vals",
arg.get_id()
);
// do nothing
}
Ok(())
}
fn start_custom_arg(&self, matcher: &mut ArgMatcher, arg: &Arg, 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); if source.is_explicit() { for group inself.cmd.groups_for_arg(arg.get_id()) {
matcher.start_custom_group(group.clone(), source);
matcher.add_val_to(
&group,
AnyValue::new(arg.get_id().clone()),
OsString::from(arg.get_id().as_str()),
);
}
}
}
}
// Error, Help, and Version Methods impl<'cmd> Parser<'cmd> { /// Is only used for the long flag(which is the only one needs fuzzy searching) fn did_you_mean_error(
&mutself,
arg: &str,
matcher: &mut ArgMatcher,
remaining_args: &[&OsStr],
trailing_values: bool,
) -> 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 iflet Some((name, _)) = did_you_mean.as_ref() { iflet Some(arg) = self.cmd.get_keymap().get(&name.as_ref()) { self.start_custom_arg(matcher, arg, ValueSource::CommandLine);
}
} let did_you_mean = did_you_mean.map(|(arg, cmd)| (format!("--{arg}"), cmd));
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(|a| !a.is_hide_set()).unwrap_or(true))
.cloned()
.collect();
// `did_you_mean` is a lot more likely and should cause us to skip the `--` suggestion // with the one exception being that the CLI is trying to capture arguments // // In theory, this is only called for `--long`s, so we don't need to check let suggested_trailing_arg = (did_you_mean.is_none()
|| self
.cmd
.get_positionals()
.any(|arg| arg.is_last_set() || arg.is_trailing_var_arg_set()))
&& !trailing_values
&& self.cmd.has_positionals();
ClapError::unknown_argument( self.cmd,
format!("--{arg}"),
did_you_mean,
suggested_trailing_arg,
Usage::new(self.cmd)
.required(&required)
.create_usage_with_title(&used),
)
}
/// 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,
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.