Fix replacing completions with a -foo prefix

Fixes #10904
This commit is contained in:
Johannes Altmanninger 2024-12-14 08:30:34 +01:00
parent 84d8655677
commit f9febba2b0
3 changed files with 22 additions and 5 deletions

View file

@ -1284,14 +1284,14 @@ impl<'ctx> Completer<'ctx> {
// Check if we are entering a combined option and argument (like --color=auto or
// -I/usr/include).
for o in &options {
let arg = if o.typ == CompleteOptionType::Short {
let arg_offset = if o.typ == CompleteOptionType::Short {
let Some(short_opt_pos) = short_opt_pos else {
continue;
};
if o.option.char_at(0) != s.char_at(short_opt_pos) {
continue;
}
Some(s.slice_from(short_opt_pos + 1))
Some(short_opt_pos + 1)
} else {
param_match2(o, s)
};
@ -1304,7 +1304,7 @@ impl<'ctx> Completer<'ctx> {
.get_or_insert(o.result_mode.requires_param) &=
o.result_mode.requires_param;
}
if let Some(arg) = arg {
if let Some(arg_offset) = arg_offset {
if o.result_mode.requires_param {
use_common = false;
}
@ -1314,7 +1314,14 @@ impl<'ctx> Completer<'ctx> {
if o.result_mode.force_files {
has_force = true;
}
let (arg_prefix, arg) = s.split_once(arg_offset);
let first_new = self.completions.completions.len();
self.complete_from_args(arg, &o.comp, o.localized_desc(), o.flags);
for compl in &mut self.completions.completions[first_new..] {
if compl.replaces_token() {
compl.completion.insert_utfstr(0, arg_prefix);
}
}
}
}
}
@ -2213,7 +2220,7 @@ fn param_match(e: &CompleteEntryOpt, optstr: &wstr) -> bool {
}
/// Test if a string is an option with an argument, like --color=auto or -I/usr/include.
fn param_match2<'s>(e: &CompleteEntryOpt, optstr: &'s wstr) -> Option<&'s wstr> {
fn param_match2(e: &CompleteEntryOpt, optstr: &wstr) -> Option<usize> {
// We may get a complete_entry_opt_t with no options if it's just arguments.
if e.option.is_empty() {
return None;
@ -2238,7 +2245,7 @@ fn param_match2<'s>(e: &CompleteEntryOpt, optstr: &'s wstr) -> Option<&'s wstr>
return None;
}
cursor += 1;
Some(optstr.slice_from(cursor))
Some(cursor)
}
/// Parses a token of short options plus one optional parameter like

View file

@ -244,6 +244,10 @@ pub trait WExt {
}
}
fn split_once(&self, pos: usize) -> (&wstr, &wstr) {
(self.slice_to(pos), self.slice_from(pos))
}
/// Returns the index of the first match against the provided substring or `None`.
fn find(&self, search: impl AsRef<[char]>) -> Option<usize> {
subslice_position(self.as_char_slice(), search.as_ref())

View file

@ -133,6 +133,12 @@ complete -C'foo -y' | string match -- -y-single-long
# CHECK: -zARGZ
complete -C'foo -z'
function foo2; end
complete -c foo2 -s s -l long -xa "hello-world goodbye-friend"
complete -C"foo2 -sfrie"
# CHECK: -sgoodbye-friend
complete -C"foo2 --long=frien"
# CHECK: --long=goodbye-friend
# Builtins (with subcommands; #2705)
complete -c complete_test_subcommand -n 'test (commandline -xp)[1] = complete_test_subcommand' -xa ok