Include subsequence matches in history-pager

If a `contains` search yields no results, try again with `contains_subsequence`.

(cherry picked from commit 00692bcdfe)
This commit is contained in:
Eddie Lebow 2023-01-15 00:41:19 -05:00 committed by Fabian Boehm
parent 85c03e4b67
commit e1c2a4e50c
5 changed files with 20 additions and 2 deletions

View File

@ -195,6 +195,9 @@ bool history_item_t::matches_search(const wcstring &term, enum history_search_ty
if (wcpattern2.back() != ANY_STRING) wcpattern2.push_back(ANY_STRING);
return wildcard_match(content_to_match, wcpattern2);
}
case history_search_type_t::contains_subsequence: {
return subsequence_in_string(term, content_to_match);
}
case history_search_type_t::match_everything: {
return true;
}

View File

@ -57,6 +57,8 @@ enum class history_search_type_t {
contains_glob,
/// Search for commands starting with the given glob pattern.
prefix_glob,
/// Search for commands containing the given string as a subsequence
contains_subsequence,
/// Matches everything.
match_everything,
};

View File

@ -1295,11 +1295,21 @@ static history_pager_result_t history_pager_search(const std::shared_ptr<history
completion_list_t completions;
history_search_t search{history, search_string, history_search_type_t::contains,
smartcase_flags(search_string), history_index};
while (completions.size() < page_size && search.go_to_next_match(direction)) {
bool next_match_found = search.go_to_next_match(direction);
if (!next_match_found) {
// If there were no matches, try again with subsequence search
search =
history_search_t{history, search_string, history_search_type_t::contains_subsequence,
smartcase_flags(search_string), history_index};
next_match_found = search.go_to_next_match(direction);
}
while (completions.size() < page_size && next_match_found) {
const history_item_t &item = search.current_item();
completions.push_back(completion_t{
item.str(), L"", string_fuzzy_match_t::exact_match(),
COMPLETE_REPLACES_COMMANDLINE | COMPLETE_DONT_ESCAPE | COMPLETE_DONT_SORT});
next_match_found = search.go_to_next_match(direction);
}
size_t last_index = search.current_index();
if (direction == history_search_direction_t::forward)

View File

@ -119,7 +119,7 @@ bool string_suffixes_string_case_insensitive(const wcstring &proposed_suffix,
/// Returns true if needle, represented as a subsequence, is contained within haystack.
/// Note subsequence is not substring: "foo" is a subsequence of "follow" for example.
static bool subsequence_in_string(const wcstring &needle, const wcstring &haystack) {
bool subsequence_in_string(const wcstring &needle, const wcstring &haystack) {
// Impossible if needle is larger than haystack.
if (needle.size() > haystack.size()) {
return false;

View File

@ -34,6 +34,9 @@ bool string_suffixes_string_case_insensitive(const wcstring &proposed_suffix,
bool string_prefixes_string_case_insensitive(const wcstring &proposed_prefix,
const wcstring &value);
/// Test if a string matches a subsequence of another.
bool subsequence_in_string(const wcstring &needle, const wcstring &haystack);
/// Case-insensitive string search, modeled after std::string::find().
/// \param fuzzy indicates this is being used for fuzzy matching and case insensitivity is
/// expanded to include symbolic characters (#3584).