Skip to content

Commit

Permalink
fix: completer showing previous argument after space
Browse files Browse the repository at this point in the history
  • Loading branch information
RoloEdits committed Jan 10, 2025
1 parent 32f8040 commit de7858d
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 135 deletions.
46 changes: 35 additions & 11 deletions helix-core/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ impl<'a> Args<'a> {
args: &'a str,
validate: bool,
) -> anyhow::Result<Self> {
let positionals = ArgsParser::from(args)
let positionals: Vec<_> = ArgsParser::from(args)
.with_mode(signature.parse_mode)
.collect();

if validate {
ensure_signature(name, signature, args.len())?;
ensure_signature(name, signature, positionals.len())?;
}

Ok(Args { positionals })
Expand Down Expand Up @@ -335,18 +335,29 @@ impl<'a> Iterator for ArgsParser<'a> {
if in_quotes {
// Found the proper closing quote, so can return the arg and advance the state along.
if bytes[self.idx] == quote {
let arg = &self.input[self.start..self.idx];
self.idx += 1;
let old_start = self.start;
self.start = self.idx;

let output = match self.mode {
ParseMode::RawParams => {
// Include start and end quotes in return value
Cow::from(&self.input[old_start - 1..=self.idx])
let arg = &self.input[self.start - 1..=self.idx];
self.idx += 1;
self.start = self.idx;
Cow::from(arg)
}
ParseMode::LiteralParams => {
let arg = &self.input[self.start..self.idx];
self.idx += 1;
self.start = self.idx;

unescape(arg, false)
}

ParseMode::LiteralParamsUnescapeBackslash => {
let arg = &self.input[self.start..self.idx];
self.idx += 1;
self.start = self.idx;

unescape(arg, true)
}
ParseMode::LiteralParams => unescape(arg, false),
ParseMode::LiteralParamsUnescapeBackslash => unescape(arg, true),
_ => {
unreachable!(
"other variants are returned early at start of `next` {:?}",
Expand Down Expand Up @@ -452,7 +463,7 @@ impl<'a> Iterator for ArgsParser<'a> {
// of the code. Either way, all that remains for the check above will be to return a full arg.
self.start = self.idx;
}
_ => {
t => {
// If previous loop didn't find any backslash and was already escaped it will change to false
// as the backslash chain was broken.
//
Expand Down Expand Up @@ -746,4 +757,17 @@ mod test {
args.next()
);
}

#[test]
fn should_remain_in_bounds_when_raw_params_parsing_path() {
let mut args = ArgsParser::from(r#""C:\\Users\\Helix\\AppData\\Local\\Temp\\.tmp3Dugy8""#);
let result = args.next();

assert_eq!(
Some(Cow::from(
r#""C:\\Users\\Helix\\AppData\\Local\\Temp\\.tmp3Dugy8""#
)),
result
);
}
}
20 changes: 17 additions & 3 deletions helix-core/src/shellwords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl<'a> Shellwords<'a> {
/// assert_eq!(Shellwords::from(":open ").ends_with_whitespace(), true);
/// assert_eq!(Shellwords::from(":open foo.txt ").ends_with_whitespace(), true);
/// assert_eq!(Shellwords::from(":open").ends_with_whitespace(), false);
/// assert_eq!(Shellwords::from(r#":open "a "#).ends_with_whitespace(), false);
/// assert_eq!(Shellwords::from(":open a\\ b.txt").ends_with_whitespace(), false);
/// #[cfg(windows)]
/// assert_eq!(Shellwords::from(":open a\\\t").ends_with_whitespace(), true);
Expand All @@ -95,10 +96,23 @@ impl<'a> Shellwords<'a> {
self.input.ends_with(' ') || self.input.ends_with('\t'),
|last| {
if cfg!(windows) {
self.input.ends_with(' ') || self.input.ends_with('\t')
let ends_with_whitespace =
self.input.ends_with(' ') || self.input.ends_with('\t');
let last_starts_with_quote =
last.starts_with('"') && !last.starts_with('\'') && !last.starts_with('`');

ends_with_whitespace && !last_starts_with_quote
} else {
!(last.ends_with("\\ ") || last.ends_with("\\\t"))
&& (self.input.ends_with(' ') || self.input.ends_with('\t'))
let ends_with_escaped_whitespace =
last.ends_with("\\ ") || last.ends_with("\\\t");
let end_with_whitespace =
self.input.ends_with(' ') || self.input.ends_with('\t');
let last_starts_with_quotes =
last.starts_with('"') && !last.starts_with('\'') && !last.starts_with('`');
let ends_in_true_whitespace =
!ends_with_escaped_whitespace && end_with_whitespace;

ends_in_true_whitespace && !last_starts_with_quotes
}
},
)
Expand Down
Loading

0 comments on commit de7858d

Please sign in to comment.