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 // Check if we are entering a combined option and argument (like --color=auto or
// -I/usr/include). // -I/usr/include).
for o in &options { 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 { let Some(short_opt_pos) = short_opt_pos else {
continue; continue;
}; };
if o.option.char_at(0) != s.char_at(short_opt_pos) { if o.option.char_at(0) != s.char_at(short_opt_pos) {
continue; continue;
} }
Some(s.slice_from(short_opt_pos + 1)) Some(short_opt_pos + 1)
} else { } else {
param_match2(o, s) param_match2(o, s)
}; };
@ -1304,7 +1304,7 @@ impl<'ctx> Completer<'ctx> {
.get_or_insert(o.result_mode.requires_param) &= .get_or_insert(o.result_mode.requires_param) &=
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 { if o.result_mode.requires_param {
use_common = false; use_common = false;
} }
@ -1314,7 +1314,14 @@ impl<'ctx> Completer<'ctx> {
if o.result_mode.force_files { if o.result_mode.force_files {
has_force = true; 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); 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. /// 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. // We may get a complete_entry_opt_t with no options if it's just arguments.
if e.option.is_empty() { if e.option.is_empty() {
return None; return None;
@ -2238,7 +2245,7 @@ fn param_match2<'s>(e: &CompleteEntryOpt, optstr: &'s wstr) -> Option<&'s wstr>
return None; return None;
} }
cursor += 1; cursor += 1;
Some(optstr.slice_from(cursor)) Some(cursor)
} }
/// Parses a token of short options plus one optional parameter like /// 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`. /// Returns the index of the first match against the provided substring or `None`.
fn find(&self, search: impl AsRef<[char]>) -> Option<usize> { fn find(&self, search: impl AsRef<[char]>) -> Option<usize> {
subslice_position(self.as_char_slice(), search.as_ref()) 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 # CHECK: -zARGZ
complete -C'foo -z' 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) # Builtins (with subcommands; #2705)
complete -c complete_test_subcommand -n 'test (commandline -xp)[1] = complete_test_subcommand' -xa ok complete -c complete_test_subcommand -n 'test (commandline -xp)[1] = complete_test_subcommand' -xa ok