diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 3d15d3f3..a4ce0ba6 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -93,17 +93,17 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos) String current_word{begin, end}; - struct RankedWordAndBuffer : WordDB::RankedWord + struct RankedMatchAndBuffer : RankedMatch { - RankedWordAndBuffer(StringView w, int r = 0, const Buffer* b = nullptr) - : WordDB::RankedWord{w, r}, buffer{b} {} + RankedMatchAndBuffer(StringView w, int r = 0, const Buffer* b = nullptr) + : RankedMatch{w, r}, buffer{b} {} - bool operator==(const RankedWordAndBuffer& other) const { return word == other.word; } - bool operator<(const RankedWordAndBuffer& other) const { return rank > other.rank; } + bool operator==(const RankedMatchAndBuffer& other) const { return word == other.word; } + bool operator<(const RankedMatchAndBuffer& other) const { return rank > other.rank; } const Buffer* buffer; }; - Vector matches; + Vector matches; auto add_matches = [&](const Buffer& buf) { auto& word_db = get_word_db(buf); @@ -129,7 +129,7 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos) unordered_erase(matches, StringView{prefix}); // Sort by word, favoring lowercase std::sort(matches.begin(), matches.end(), - [](const RankedWordAndBuffer& lhs, const RankedWordAndBuffer& rhs) { + [](const RankedMatchAndBuffer& lhs, const RankedMatchAndBuffer& rhs) { return std::lexicographical_compare( lhs.word.begin(), lhs.word.end(), rhs.word.begin(), rhs.word.end(), [](char a, char b) { @@ -142,7 +142,7 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos) std::stable_sort(matches.begin(), matches.end()); const auto longest = std::accumulate(matches.begin(), matches.end(), 0_char, - [](const CharCount& lhs, const RankedWordAndBuffer& rhs) + [](const CharCount& lhs, const RankedMatchAndBuffer& rhs) { return std::max(lhs, rhs.word.char_length()); }); InsertCompletion::CandidateList candidates; diff --git a/src/ranked_match.cc b/src/ranked_match.cc new file mode 100644 index 00000000..0063b8ae --- /dev/null +++ b/src/ranked_match.cc @@ -0,0 +1,40 @@ +#include "ranked_match.hh" + +namespace Kakoune +{ + +int match_rank(StringView candidate, StringView query) +{ + int rank = 0; + auto it = candidate.begin(); + char prev = 0; + for (auto c : query) + { + if (it == candidate.end()) + return 0; + + const bool islow = islower(c); + auto eq_c = [islow, c](char ch) { return islow ? tolower(ch) == c : ch == c; }; + + if (eq_c(*it)) // improve rank on contiguous + ++rank; + + while (!eq_c(*it)) + { + prev = *it; + if (++it == candidate.end()) + return 0; + } + // Improve rank on word boundaries + if (prev == 0 or prev == '_' or + (islower(prev) and isupper(*it))) + rank += 5; + + prev = c; + ++rank; + ++it; + } + return rank; +} + +} diff --git a/src/ranked_match.hh b/src/ranked_match.hh new file mode 100644 index 00000000..2e248dc1 --- /dev/null +++ b/src/ranked_match.hh @@ -0,0 +1,21 @@ +#ifndef ranked_match_hh_INCLUDED +#define ranked_match_hh_INCLUDED + +#include "string.hh" +#include "vector.hh" + +namespace Kakoune +{ + +struct RankedMatch +{ + StringView word; + int rank; +}; +using RankedMatchList = Vector; + +int match_rank(StringView candidate, StringView query); + +} + +#endif // ranked_match_hh_INCLUDED diff --git a/src/word_db.cc b/src/word_db.cc index c1c8f967..80b59f0c 100644 --- a/src/word_db.cc +++ b/src/word_db.cc @@ -146,42 +146,8 @@ int WordDB::get_word_occurences(StringView word) const return 0; } -WordDB::RankedWordList WordDB::find_matching(StringView query) +RankedMatchList WordDB::find_matching(StringView query) { - auto match_rank = [](StringView candidate, StringView query) - { - int rank = 0; - auto it = candidate.begin(); - char prev = 0; - for (auto c : query) - { - if (it == candidate.end()) - return 0; - - const bool islow = islower(c); - auto eq_c = [islow, c](char ch) { return islow ? tolower(ch) == c : ch == c; }; - - if (eq_c(*it)) // improve rank on contiguous - ++rank; - - while (!eq_c(*it)) - { - prev = *it; - if (++it == candidate.end()) - return 0; - } - // Improve rank on word boundaries - if (prev == 0 or prev == '_' or - (islower(prev) and isupper(*it))) - rank += 5; - - prev = c; - ++rank; - ++it; - } - return rank; - }; - auto matches = [](UsedLetters query, UsedLetters letters) { return (query & letters) == query; @@ -189,7 +155,7 @@ WordDB::RankedWordList WordDB::find_matching(StringView query) update_db(); const UsedLetters letters = used_letters(query); - RankedWordList res; + RankedMatchList res; for (auto&& word : m_words) { if (query.empty()) @@ -211,14 +177,14 @@ WordDB::RankedWordList WordDB::find_matching(StringView query) UnitTest test_word_db{[]() { - auto cmp_words = [](const WordDB::RankedWord& lhs, const WordDB::RankedWord& rhs) { + auto cmp_words = [](const RankedMatch& lhs, const RankedMatch& rhs) { return lhs.word < rhs.word; }; - auto eq = [](ArrayView lhs, const WordList& rhs) { + auto eq = [](ArrayView lhs, const WordList& rhs) { return lhs.size() == rhs.size() and std::equal(lhs.begin(), lhs.end(), rhs.begin(), - [](const WordDB::RankedWord& lhs, const StringView& rhs) { + [](const RankedMatch& lhs, const StringView& rhs) { return lhs.word == rhs; }); }; diff --git a/src/word_db.hh b/src/word_db.hh index 45aa5228..91846eb6 100644 --- a/src/word_db.hh +++ b/src/word_db.hh @@ -5,6 +5,7 @@ #include "shared_string.hh" #include "unordered_map.hh" #include "vector.hh" +#include "ranked_match.hh" #include @@ -22,14 +23,7 @@ public: WordDB(const WordDB&) = delete; WordDB(WordDB&&) = default; - struct RankedWord - { - StringView word; - int rank; - }; - using RankedWordList = Vector; - - RankedWordList find_matching(StringView str); + RankedMatchList find_matching(StringView str); int get_word_occurences(StringView word) const; private: