Tweak RankedMatch logic, prioritize matches that are in a single word

This commit is contained in:
Maxime Coste 2016-09-26 21:54:39 +01:00
parent 0d5a1ddf4c
commit b5450aa375
2 changed files with 47 additions and 22 deletions

View File

@ -70,26 +70,38 @@ static bool smartcase_eq(Codepoint query, Codepoint candidate)
return query == (islower(query) ? to_lower(candidate) : candidate); return query == (islower(query) ? to_lower(candidate) : candidate);
} }
static bool subsequence_match_smart_case(StringView str, StringView subseq, int& out_max_index) struct SubseqRes
{ {
int max_index = 0; bool matches;
int max_index;
bool single_word;
};
static SubseqRes subsequence_match_smart_case(StringView str, StringView subseq)
{
bool single_word = true;
int max_index = -1;
auto it = str.begin(); auto it = str.begin();
int index = 0; int index = 0;
for (auto subseq_it = subseq.begin(); subseq_it != subseq.end();) for (auto subseq_it = subseq.begin(); subseq_it != subseq.end();)
{ {
if (it == str.end()) if (it == str.end())
return false; return { false };
const Codepoint c = utf8::read_codepoint(subseq_it, subseq.end()); const Codepoint c = utf8::read_codepoint(subseq_it, subseq.end());
while (not smartcase_eq(c, utf8::read_codepoint(it, subseq.end()))) while (true)
{ {
auto str_c = utf8::read_codepoint(it, str.end());
if (smartcase_eq(c, str_c))
break;
if (single_word and max_index != -1 and not is_word(str_c))
single_word = false;
++index; ++index;
if (it == str.end()) if (it == str.end())
return false; return { false };
} }
max_index = index++; max_index = index++;
} }
out_max_index = max_index; return { true, max_index, single_word };
return true;
} }
template<typename TestFunc> template<typename TestFunc>
@ -99,11 +111,23 @@ RankedMatch::RankedMatch(StringView candidate, StringView query, TestFunc func)
return; return;
if (query.empty()) if (query.empty())
m_candidate = candidate;
else if (func() and subsequence_match_smart_case(candidate, query, m_max_index))
{ {
m_candidate = candidate; m_candidate = candidate;
return;
}
if (not func())
return;
auto res = subsequence_match_smart_case(candidate, query);
if (not res.matches)
return;
m_candidate = candidate;
m_max_index = res.max_index;
if (res.single_word)
m_flags |= Flags::SingleWord;
if (smartcase_eq(query[0], candidate[0])) if (smartcase_eq(query[0], candidate[0]))
m_flags |= Flags::FirstCharMatch; m_flags |= Flags::FirstCharMatch;
if (std::equal(query.begin(), query.end(), candidate.begin())) if (std::equal(query.begin(), query.end(), candidate.begin()))
@ -116,7 +140,6 @@ RankedMatch::RankedMatch(StringView candidate, StringView query, TestFunc func)
if (m_word_boundary_match_count == query.length()) if (m_word_boundary_match_count == query.length())
m_flags |= Flags::OnlyWordBoundary; m_flags |= Flags::OnlyWordBoundary;
} }
}
RankedMatch::RankedMatch(StringView candidate, UsedLetters candidate_letters, RankedMatch::RankedMatch(StringView candidate, UsedLetters candidate_letters,
StringView query, UsedLetters query_letters) StringView query, UsedLetters query_letters)
@ -179,6 +202,7 @@ UnitTest test_ranked_match{[] {
kak_assert(RankedMatch{"source", "so"} < RankedMatch{"source_data", "so"}); kak_assert(RankedMatch{"source", "so"} < RankedMatch{"source_data", "so"});
kak_assert(not (RankedMatch{"source_data", "so"} < RankedMatch{"source", "so"})); kak_assert(not (RankedMatch{"source_data", "so"} < RankedMatch{"source", "so"}));
kak_assert(not (RankedMatch{"source", "so"} < RankedMatch{"source", "so"})); kak_assert(not (RankedMatch{"source", "so"} < RankedMatch{"source", "so"}));
kak_assert(RankedMatch{"single/word", "wo"} < RankedMatch{"multiw/ord", "wo"});
}}; }};
UnitTest test_used_letters{[]() UnitTest test_used_letters{[]()

View File

@ -40,7 +40,8 @@ private:
OnlyWordBoundary = 1 << 0, OnlyWordBoundary = 1 << 0,
FirstCharMatch = 1 << 1, FirstCharMatch = 1 << 1,
Prefix = 1 << 2, Prefix = 1 << 2,
FullMatch = 1 << 3, SingleWord = 1 << 3,
FullMatch = 1 << 4,
}; };
StringView m_candidate; StringView m_candidate;