From 57f289850c24a44a2590cb30762853f2a61f4efd Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 30 May 2016 12:56:04 +0200 Subject: 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. --- src/reader.cpp | 85 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 41 deletions(-) (limited to 'src') 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 &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) { -- cgit v1.2.3