fix(lex): Make long args more convinient

This commit is contained in:
Ed Page 2022-04-15 10:07:20 -05:00
parent 1247a955cf
commit 6291289c0f
4 changed files with 53 additions and 25 deletions

View file

@ -10,7 +10,6 @@ use std::ops::Index;
use std::path::Path;
// Third Party
use os_str_bytes::RawOsStr;
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
@ -4655,7 +4654,7 @@ impl<'help> App<'help> {
}
/// Find a flag subcommand name by long flag or an alias
pub(crate) fn find_long_subcmd(&self, long: &RawOsStr) -> Option<&str> {
pub(crate) fn find_long_subcmd(&self, long: &str) -> Option<&str> {
self.get_subcommands()
.find(|sc| sc.long_flag_aliases_to(long))
.map(|sc| sc.get_name())

View file

@ -49,6 +49,15 @@ impl PartialEq<&str> for KeyType {
}
}
impl PartialEq<str> for KeyType {
fn eq(&self, rhs: &str) -> bool {
match self {
KeyType::Long(l) => l == rhs,
_ => false,
}
}
}
impl PartialEq<OsStr> for KeyType {
fn eq(&self, rhs: &OsStr) -> bool {
match self {

View file

@ -124,14 +124,28 @@ impl<'s> ParsedArg<'s> {
/// Treat as a long-flag
///
/// **NOTE:** May return an empty flag. Check [`ParsedArg::is_escape`] to separately detect `--`.
pub fn to_long(&self) -> Option<(&RawOsStr, Option<&RawOsStr>)> {
let remainder = self.inner.as_ref().strip_prefix("--")?;
let parts = if let Some((p0, p1)) = remainder.split_once("=") {
(p0, Some(p1))
pub fn to_long(&self) -> Option<(Result<&str, &RawOsStr>, Option<&RawOsStr>)> {
if let Some(raw) = self.utf8 {
let remainder = raw.strip_prefix("--")?;
let (flag, value) = if let Some((p0, p1)) = remainder.split_once("=") {
(p0, Some(p1))
} else {
(remainder, None)
};
let flag = Ok(flag);
let value = value.map(RawOsStr::from_str);
Some((flag, value))
} else {
(remainder, None)
};
Some(parts)
let raw = self.inner.as_ref();
let remainder = raw.strip_prefix("--")?;
let (flag, value) = if let Some((p0, p1)) = remainder.split_once("=") {
(p0, Some(p1))
} else {
(remainder, None)
};
let flag = flag.to_str().ok_or_else(|| flag);
Some((flag, value))
}
}
/// Can treat as a long-flag

View file

@ -568,21 +568,18 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
// Checks if the arg matches a long flag subcommand name, or any of its aliases (if defined)
fn possible_long_flag_subcommand(&self, arg_os: &RawOsStr) -> Option<&str> {
debug!("Parser::possible_long_flag_subcommand: arg={:?}", arg_os);
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 RawOsStr::from_str(long).starts_with_os(arg_os) {
if long.starts_with(arg) {
options.push(long);
}
options.extend(
sc.get_all_aliases()
.filter(|alias| RawOsStr::from_str(alias).starts_with_os(arg_os)),
)
options.extend(sc.get_all_aliases().filter(|alias| alias.starts_with(arg)))
}
options
});
@ -591,11 +588,11 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
for sc in options {
if sc == arg_os {
if sc == arg {
return Some(sc);
}
}
} else if let Some(sc_name) = self.cmd.find_long_subcmd(arg_os) {
} else if let Some(sc_name) = self.cmd.find_long_subcmd(arg) {
return Some(sc_name);
}
None
@ -827,7 +824,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
fn parse_long_arg(
&mut self,
matcher: &mut ArgMatcher,
long_arg: &RawOsStr,
long_arg: Result<&str, &RawOsStr>,
long_value: Option<&RawOsStr>,
parse_state: &ParseState,
valid_arg_found: &mut bool,
@ -847,24 +844,31 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
debug!("Parser::parse_long_arg: cur_idx:={}", self.cur_idx.get());
debug!("Parser::parse_long_arg: Does it contain '='...");
let long_arg = match long_arg {
Ok(long_arg) => long_arg,
Err(long_arg) => {
return ParseResult::NoMatchingArg {
arg: long_arg.to_str_lossy().into_owned(),
};
}
};
if long_arg.is_empty() {
debug_assert!(long_value.is_none(), "{:?}", long_value);
return ParseResult::NoArg;
}
let opt = if let Some(opt) = self.cmd.get_keymap().get(&*long_arg.to_os_str()) {
let opt = if let Some(opt) = self.cmd.get_keymap().get(long_arg) {
debug!(
"Parser::parse_long_arg: Found valid opt or flag '{}'",
opt.to_string()
);
Some(opt)
} else if self.cmd.is_infer_long_args_set() {
let arg_str = long_arg.to_str_lossy();
self.cmd.get_arguments().find(|a| {
a.long.map_or(false, |long| long.starts_with(&*arg_str))
a.long.map_or(false, |long| long.starts_with(long_arg))
|| a.aliases
.iter()
.any(|(alias, _)| alias.starts_with(&*arg_str))
.any(|(alias, _)| alias.starts_with(long_arg))
})
} else {
None
@ -898,7 +902,9 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
used,
arg: opt.to_string(),
}
} else if let Some(parse_result) = self.check_for_help_and_version_str(long_arg) {
} else if let Some(parse_result) =
self.check_for_help_and_version_str(RawOsStr::from_str(long_arg))
{
parse_result
} else {
debug!("Parser::parse_long_arg: Presence validated");
@ -910,7 +916,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
ParseResult::MaybeHyphenValue
} else {
ParseResult::NoMatchingArg {
arg: long_arg.to_str_lossy().into_owned(),
arg: long_arg.to_owned(),
}
}
}