mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-30 19:41:15 -03:00
Don't insert prefix for non-prefix matches
The issue here is that when inserting a common prefix for e.g. a substring match, we increase the amount of available candidates again to things the user didn't want. An example is in share/functions - a completion for "inter" would previously expand to "__fish_" because it matched: - __fish_config_interactive.fish - __fish_print_interfaces.fish - __fish_print_lpr_printers.fish The completion afterwards would then show 189 possible matches, only three of which (the above) actually matched the original "inter". Fixes #3089.
This commit is contained in:
committed by
Kurtis Rader
parent
63a851cfd6
commit
57f289850c
@@ -1433,53 +1433,56 @@ static bool handle_completions(const std::vector<completion_t> &comp,
|
||||
surviving_completions.push_back(el);
|
||||
}
|
||||
|
||||
// Try to find a common prefix to insert among the surviving completions.
|
||||
wcstring common_prefix;
|
||||
complete_flags_t flags = 0;
|
||||
bool prefix_is_partial_completion = false;
|
||||
for (size_t i = 0; i < surviving_completions.size(); i++) {
|
||||
const completion_t &el = surviving_completions.at(i);
|
||||
if (i == 0) {
|
||||
// First entry, use the whole string.
|
||||
common_prefix = el.completion;
|
||||
flags = el.flags;
|
||||
} else {
|
||||
// Determine the shared prefix length.
|
||||
size_t idx, max = mini(common_prefix.size(), el.completion.size());
|
||||
for (idx = 0; idx < max; idx++) {
|
||||
wchar_t ac = common_prefix.at(idx), bc = el.completion.at(idx);
|
||||
bool matches = (ac == bc);
|
||||
// If we are replacing the token, allow case to vary.
|
||||
if (will_replace_token && !matches) {
|
||||
// Hackish way to compare two strings in a case insensitive way, hopefully
|
||||
// better than towlower().
|
||||
matches = (wcsncasecmp(&ac, &bc, 1) == 0);
|
||||
bool use_prefix = false;
|
||||
if (match_type_shares_prefix(best_match_type)) {
|
||||
// Try to find a common prefix to insert among the surviving completions.
|
||||
wcstring common_prefix;
|
||||
complete_flags_t flags = 0;
|
||||
bool prefix_is_partial_completion = false;
|
||||
for (size_t i = 0; i < surviving_completions.size(); i++) {
|
||||
const completion_t &el = surviving_completions.at(i);
|
||||
if (i == 0) {
|
||||
// First entry, use the whole string.
|
||||
common_prefix = el.completion;
|
||||
flags = el.flags;
|
||||
} else {
|
||||
// Determine the shared prefix length.
|
||||
size_t idx, max = mini(common_prefix.size(), el.completion.size());
|
||||
for (idx = 0; idx < max; idx++) {
|
||||
wchar_t ac = common_prefix.at(idx), bc = el.completion.at(idx);
|
||||
bool matches = (ac == bc);
|
||||
// If we are replacing the token, allow case to vary.
|
||||
if (will_replace_token && !matches) {
|
||||
// Hackish way to compare two strings in a case insensitive way,
|
||||
// hopefully better than towlower().
|
||||
matches = (wcsncasecmp(&ac, &bc, 1) == 0);
|
||||
}
|
||||
if (!matches) break;
|
||||
}
|
||||
if (!matches) break;
|
||||
|
||||
// idx is now the length of the new common prefix.
|
||||
common_prefix.resize(idx);
|
||||
prefix_is_partial_completion = true;
|
||||
|
||||
// Early out if we decide there's no common prefix.
|
||||
if (idx == 0) break;
|
||||
}
|
||||
|
||||
// idx is now the length of the new common prefix.
|
||||
common_prefix.resize(idx);
|
||||
prefix_is_partial_completion = true;
|
||||
|
||||
// Early out if we decide there's no common prefix.
|
||||
if (idx == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if we use the prefix. We use it if it's non-empty and it will actually make the
|
||||
// command line longer. It may make the command line longer by virtue of not using
|
||||
// REPLACE_TOKEN (so it always appends to the command line), or by virtue of replacing the
|
||||
// token but being longer than it.
|
||||
bool use_prefix = common_prefix.size() > (will_replace_token ? tok.size() : 0);
|
||||
assert(!use_prefix || !common_prefix.empty());
|
||||
// Determine if we use the prefix. We use it if it's non-empty and it will actually make
|
||||
// the command line longer. It may make the command line longer by virtue of not using
|
||||
// REPLACE_TOKEN (so it always appends to the command line), or by virtue of replacing
|
||||
// the token but being longer than it.
|
||||
use_prefix = common_prefix.size() > (will_replace_token ? tok.size() : 0);
|
||||
assert(!use_prefix || !common_prefix.empty());
|
||||
|
||||
if (use_prefix) {
|
||||
// We got something. If more than one completion contributed, then it means we have a
|
||||
// prefix; don't insert a space after it.
|
||||
if (prefix_is_partial_completion) flags |= COMPLETE_NO_SPACE;
|
||||
completion_insert(common_prefix.c_str(), flags);
|
||||
success = true;
|
||||
if (use_prefix) {
|
||||
// We got something. If more than one completion contributed, then it means we have
|
||||
// a prefix; don't insert a space after it.
|
||||
if (prefix_is_partial_completion) flags |= COMPLETE_NO_SPACE;
|
||||
completion_insert(common_prefix.c_str(), flags);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (continue_after_prefix_insertion || !use_prefix) {
|
||||
|
||||
Reference in New Issue
Block a user