fix(lex)!: Don't do prefix matching by default

Finding this a pain in `clap_complete`; not offering the benefits I
expected.
This commit is contained in:
Ed Page 2022-04-27 12:36:42 -05:00
parent 3d64ebacac
commit f083ef92c5
4 changed files with 35 additions and 61 deletions

View file

@ -293,14 +293,14 @@ impl<'s> ParsedArg<'s> {
}
/// Treat as a long-flag
///
/// **NOTE:** May return an empty flag. Check [`ParsedArg::is_escape`] to separately detect `--`.
///
/// **NOTE:** Will not match [`ParsedArg::is_stdio`], completion engines will need to check
/// that case.
pub fn to_long(&self) -> Option<(Result<&str, &RawOsStr>, Option<&RawOsStr>)> {
if let Some(raw) = self.utf8 {
let remainder = raw.strip_prefix("--")?;
if remainder.is_empty() {
debug_assert!(self.is_escape());
return None;
}
let (flag, value) = if let Some((p0, p1)) = remainder.split_once('=') {
(p0, Some(p1))
} else {
@ -312,6 +312,11 @@ impl<'s> ParsedArg<'s> {
} else {
let raw = self.inner.as_ref();
let remainder = raw.strip_prefix("--")?;
if remainder.is_empty() {
debug_assert!(self.is_escape());
return None;
}
let (flag, value) = if let Some((p0, p1)) = remainder.split_once('=') {
(p0, Some(p1))
} else {
@ -323,20 +328,18 @@ impl<'s> ParsedArg<'s> {
}
/// Can treat as a long-flag
///
/// **NOTE:** May return an empty flag. Check [`ParsedArg::is_escape`] to separately detect `--`.
pub fn is_long(&self) -> bool {
self.inner.as_ref().starts_with("--")
self.inner.as_ref().starts_with("--") && !self.is_escape()
}
/// Treat as a short-flag
///
/// **NOTE:** Maybe return an empty flag. Check [`ParsedArg::is_stdio`] to separately detect
/// `-`.
pub fn to_short(&self) -> Option<ShortFlags<'_>> {
if let Some(remainder_os) = self.inner.as_ref().strip_prefix('-') {
if remainder_os.starts_with('-') {
None
} else if remainder_os.is_empty() {
debug_assert!(self.is_stdio());
None
} else {
let remainder = self.utf8.map(|s| &s[1..]);
Some(ShortFlags::new(remainder_os, remainder))
@ -347,11 +350,10 @@ impl<'s> ParsedArg<'s> {
}
/// Can treat as a short-flag
///
/// **NOTE:** Maybe return an empty flag. Check [`ParsedArg::is_stdio`] to separately detect
/// `-`.
pub fn is_short(&self) -> bool {
self.inner.as_ref().starts_with('-') && !self.is_long()
self.inner.as_ref().starts_with('-')
&& !self.is_stdio()
&& !self.inner.as_ref().starts_with("--")
}
/// Treat as a value

View file

@ -13,17 +13,15 @@ fn to_long_stdio() {
}
#[test]
fn to_long_escape() {
fn to_long_no_escape() {
let raw = clap_lex::RawArgs::new(["bin", "--"]);
let mut cursor = raw.cursor();
assert_eq!(raw.next_os(&mut cursor), Some(std::ffi::OsStr::new("bin")));
let next = raw.next(&mut cursor).unwrap();
assert!(next.is_long());
assert!(!next.is_long());
let (key, value) = next.to_long().unwrap();
assert_eq!(key, Ok(""));
assert_eq!(value, None);
assert_eq!(next.to_long(), None);
}
#[test]
@ -75,10 +73,9 @@ fn to_short_stdio() {
assert_eq!(raw.next_os(&mut cursor), Some(std::ffi::OsStr::new("bin")));
let next = raw.next(&mut cursor).unwrap();
assert!(next.is_short());
assert!(!next.is_short());
let mut shorts = next.to_short().unwrap();
assert_eq!(shorts.next_value_os(), None);
assert!(next.to_short().is_none());
}
#[test]

View file

@ -87,20 +87,6 @@ fn advance_by_nothing() {
assert_eq!(actual, "short");
}
#[test]
fn advance_by_nothing_with_nothing() {
let raw = clap_lex::RawArgs::new(["bin", "-"]);
let mut cursor = raw.cursor();
assert_eq!(raw.next_os(&mut cursor), Some(std::ffi::OsStr::new("bin")));
let next = raw.next(&mut cursor).unwrap();
let mut shorts = next.to_short().unwrap();
assert_eq!(shorts.advance_by(0), Ok(()));
let actual: String = shorts.map(|s| s.unwrap()).collect();
assert_eq!(actual, "");
}
#[test]
fn advance_by_something() {
let raw = clap_lex::RawArgs::new(["bin", "-short"]);
@ -129,17 +115,6 @@ fn advance_by_out_of_bounds() {
assert_eq!(actual, "");
}
#[test]
fn is_empty() {
let raw = clap_lex::RawArgs::new(["bin", "-"]);
let mut cursor = raw.cursor();
assert_eq!(raw.next_os(&mut cursor), Some(std::ffi::OsStr::new("bin")));
let next = raw.next(&mut cursor).unwrap();
let shorts = next.to_short().unwrap();
assert!(shorts.is_empty());
}
#[test]
fn is_not_empty() {
let raw = clap_lex::RawArgs::new(["bin", "-hello"]);
@ -165,7 +140,7 @@ fn is_partial_not_empty() {
#[test]
fn is_exhausted_empty() {
let raw = clap_lex::RawArgs::new(["bin", "-"]);
let raw = clap_lex::RawArgs::new(["bin", "-hello"]);
let mut cursor = raw.cursor();
assert_eq!(raw.next_os(&mut cursor), Some(std::ffi::OsStr::new("bin")));
let next = raw.next(&mut cursor).unwrap();

View file

@ -190,7 +190,17 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
}
if let Some((long_arg, long_value)) = arg_os.to_long() {
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,
@ -205,9 +215,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
);
match parse_result {
ParseResult::NoArg => {
debug!("Parser::get_matches_with: setting TrailingVals=true");
trailing_values = true;
continue;
unreachable!("`to_long` always has the flag specified")
}
ParseResult::ValuesDone => {
parse_state = ParseState::ValuesDone;
@ -661,14 +669,6 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
// If allow hyphen, this isn't a new arg.
debug!("Parser::is_new_arg: Allow hyphen");
false
} else if next.is_escape() {
// Ensure we don't assuming escapes are long args
debug!("Parser::is_new_arg: -- found");
false
} else if next.is_stdio() {
// Ensure we don't assume stdio is a short arg
debug!("Parser::is_new_arg: - found");
false
} else if next.is_long() {
// If this is a long flag, this is a new arg.
debug!("Parser::is_new_arg: --<something> found");