Move more logic into RankedMatch

This commit is contained in:
Maxime Coste 2015-10-27 21:25:18 +00:00
parent 2eba789610
commit 89d22f3335
4 changed files with 58 additions and 35 deletions

View File

@ -95,11 +95,13 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
struct RankedMatchAndBuffer : RankedMatch struct RankedMatchAndBuffer : RankedMatch
{ {
RankedMatchAndBuffer(StringView w, int r = 0, const Buffer* b = nullptr) RankedMatchAndBuffer(const RankedMatch& m, const Buffer* b = nullptr)
: RankedMatch{w, r}, buffer{b} {} : RankedMatch{m}, buffer{b} {}
bool operator==(const RankedMatchAndBuffer& other) const { return word == other.word; } bool operator==(StringView other) const { return candidate() == other; }
bool operator<(const RankedMatchAndBuffer& other) const { return rank > other.rank; }
bool operator==(const RankedMatchAndBuffer& other) const { return RankedMatch::operator==(other); }
bool operator<(const RankedMatchAndBuffer& other) const { return RankedMatch::operator<(other);; }
const Buffer* buffer; const Buffer* buffer;
}; };
@ -109,7 +111,7 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
auto& word_db = get_word_db(buf); auto& word_db = get_word_db(buf);
auto bufmatches = word_db.find_matching(prefix); auto bufmatches = word_db.find_matching(prefix);
for (auto& m : bufmatches) for (auto& m : bufmatches)
matches.push_back({ m.word, m.rank, &buf }); matches.push_back({ m, &buf });
}; };
add_matches(buffer); add_matches(buffer);
@ -127,23 +129,12 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
} }
} }
unordered_erase(matches, StringView{prefix}); unordered_erase(matches, StringView{prefix});
// Sort by word, favoring lowercase std::sort(matches.begin(), matches.end());
std::sort(matches.begin(), matches.end(),
[](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) {
const bool low_a = islower(a), low_b = islower(b);
return low_a == low_b ? a < b : low_a;
});
});
matches.erase(std::unique(matches.begin(), matches.end()), matches.end()); matches.erase(std::unique(matches.begin(), matches.end()), matches.end());
// Stable sort by rank to preserve by word sorting
std::stable_sort(matches.begin(), matches.end());
const auto longest = std::accumulate(matches.begin(), matches.end(), 0_char, const auto longest = std::accumulate(matches.begin(), matches.end(), 0_char,
[](const CharCount& lhs, const RankedMatchAndBuffer& rhs) [](const CharCount& lhs, const RankedMatchAndBuffer& rhs)
{ return std::max(lhs, rhs.word.char_length()); }); { return std::max(lhs, rhs.candidate().char_length()); });
InsertCompletion::CandidateList candidates; InsertCompletion::CandidateList candidates;
candidates.reserve(matches.size()); candidates.reserve(matches.size());
@ -152,17 +143,15 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
DisplayLine menu_entry; DisplayLine menu_entry;
if (m.buffer) if (m.buffer)
{ {
const auto pad_len = longest + 1 - m.word.char_length(); const auto pad_len = longest + 1 - m.candidate().char_length();
menu_entry.push_back(m.word.str()); menu_entry.push_back(m.candidate().str());
menu_entry.push_back(String{' ', pad_len}); menu_entry.push_back(String{' ', pad_len});
menu_entry.push_back({ m.buffer->display_name(), get_face("MenuInfo") }); menu_entry.push_back({ m.buffer->display_name(), get_face("MenuInfo") });
} }
else else
menu_entry.push_back(m.word.str()); menu_entry.push_back(m.candidate().str());
menu_entry.push_back({ " " + to_string(m.rank), get_face("cyan") }); candidates.push_back({m.candidate().str(), "", std::move(menu_entry)});
candidates.push_back({m.word.str(), "", std::move(menu_entry)});
} }
return { begin.coord(), cursor_pos, std::move(candidates), buffer.timestamp() }; return { begin.coord(), cursor_pos, std::move(candidates), buffer.timestamp() };

View File

@ -3,7 +3,7 @@
namespace Kakoune namespace Kakoune
{ {
int match_rank(StringView candidate, StringView query) static bool match_rank(StringView candidate, StringView query)
{ {
int rank = 0; int rank = 0;
auto it = candidate.begin(); auto it = candidate.begin();
@ -37,4 +37,29 @@ int match_rank(StringView candidate, StringView query)
return rank; return rank;
} }
RankedMatch::RankedMatch(StringView candidate, StringView query)
{
if (candidate.empty() or query.empty())
{
m_candidate = candidate;
return;
}
m_match_rank = match_rank(candidate, query);
}
bool RankedMatch::operator<(const RankedMatch& other) const
{
if (m_match_rank == other.m_match_rank)
return std::lexicographical_compare(
m_candidate.begin(), m_candidate.end(),
other.m_candidate.begin(), other.m_candidate.end(),
[](char a, char b) {
const bool low_a = islower(a), low_b = islower(b);
return low_a == low_b ? a < b : low_a;
});
return m_match_rank < other.m_match_rank;
}
} }

View File

@ -9,12 +9,20 @@ namespace Kakoune
struct RankedMatch struct RankedMatch
{ {
StringView word; RankedMatch(StringView candidate, StringView query);
int rank;
};
using RankedMatchList = Vector<RankedMatch>;
int match_rank(StringView candidate, StringView query); const StringView& candidate() const { return m_candidate; }
bool operator<(const RankedMatch& other) const;
bool operator==(const RankedMatch& other) const { return m_candidate == other.m_candidate; }
explicit operator bool() const { return not m_candidate.empty(); }
private:
StringView m_candidate;
int m_match_rank = 0;
};
using RankedMatchList = Vector<RankedMatch>;
} }

View File

@ -160,7 +160,7 @@ RankedMatchList WordDB::find_matching(StringView query)
{ {
if (query.empty()) if (query.empty())
{ {
res.push_back({word.first, 1 }); res.push_back(RankedMatch{word.first, query});
continue; continue;
} }
@ -168,8 +168,9 @@ RankedMatchList WordDB::find_matching(StringView query)
if (not matches(to_lower(letters), to_lower(word_letters)) or if (not matches(to_lower(letters), to_lower(word_letters)) or
not matches(letters & upper_mask, word_letters & upper_mask)) not matches(letters & upper_mask, word_letters & upper_mask))
continue; continue;
if (int rank = match_rank(word.first, query))
res.push_back({ word.first, rank }); if (RankedMatch match{word.first, query})
res.push_back(match);
} }
return res; return res;
@ -178,14 +179,14 @@ RankedMatchList WordDB::find_matching(StringView query)
UnitTest test_word_db{[]() UnitTest test_word_db{[]()
{ {
auto cmp_words = [](const RankedMatch& lhs, const RankedMatch& rhs) { auto cmp_words = [](const RankedMatch& lhs, const RankedMatch& rhs) {
return lhs.word < rhs.word; return lhs.candidate() < rhs.candidate();
}; };
auto eq = [](ArrayView<const RankedMatch> lhs, const WordList& rhs) { auto eq = [](ArrayView<const RankedMatch> lhs, const WordList& rhs) {
return lhs.size() == rhs.size() and return lhs.size() == rhs.size() and
std::equal(lhs.begin(), lhs.end(), rhs.begin(), std::equal(lhs.begin(), lhs.end(), rhs.begin(),
[](const RankedMatch& lhs, const StringView& rhs) { [](const RankedMatch& lhs, const StringView& rhs) {
return lhs.word == rhs; return lhs.candidate() == rhs;
}); });
}; };