aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Fabian Homborg <FHomborg@gmail.com>2016-05-30 12:56:04 +0200
committerGravatar Kurtis Rader <krader@skepticism.us>2016-06-02 21:25:50 -0700
commit57f289850c24a44a2590cb30762853f2a61f4efd (patch)
treef7dea9ef2892299df94775589c5ace0d0377a2fc
parent63a851cfd6f6be2ecfaf695495ed788b8115fb9d (diff)
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.
-rw-r--r--src/reader.cpp85
1 files changed, 44 insertions, 41 deletions
diff --git a/src/reader.cpp b/src/reader.cpp
index b67f290b..968a508a 100644
--- a/src/reader.cpp
+++ b/src/reader.cpp
@@ -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;
+ // 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;
+ // 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) {