Make word insert completion work better with unicode char

This commit is contained in:
Maxime Coste 2015-10-30 13:57:46 +00:00
parent 92c3aa4d31
commit 2bf44b6b49
3 changed files with 30 additions and 24 deletions

View File

@ -10,6 +10,7 @@
#include "user_interface.hh" #include "user_interface.hh"
#include "window.hh" #include "window.hh"
#include "word_db.hh" #include "word_db.hh"
#include "utf8_iterator.hh"
#include <numeric> #include <numeric>
@ -75,23 +76,24 @@ WordDB& get_word_db(const Buffer& buffer)
template<bool other_buffers> template<bool other_buffers>
InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos) InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
{ {
auto pos = buffer.iterator_at(cursor_pos); using Utf8It = utf8::iterator<BufferIterator>;
if (pos == buffer.begin() or not is_word(*utf8::previous(pos, buffer.begin()))) Utf8It pos{buffer.iterator_at(cursor_pos), buffer};
return {}; if (pos == buffer.begin() or not is_word(*(pos-1)))
return {};
auto end = buffer.iterator_at(cursor_pos); auto end = Utf8It{buffer.iterator_at(cursor_pos), buffer};
auto begin = end-1; auto begin = end-1;
while (begin != buffer.begin() and is_word(*begin)) while (begin != buffer.begin() and is_word(*begin))
--begin; --begin;
if (not is_word(*begin)) if (not is_word(*begin))
++begin; ++begin;
String prefix{begin, end}; String prefix{begin.base(), end.base()};
while (end != buffer.end() and is_word(*end)) while (end != buffer.end() and is_word(*end))
++end; ++end;
String current_word{begin, end}; String current_word{begin.base(), end.base()};
struct RankedMatchAndBuffer : RankedMatch struct RankedMatchAndBuffer : RankedMatch
{ {
@ -153,7 +155,7 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos)
candidates.push_back({m.candidate().str(), "", std::move(menu_entry)}); candidates.push_back({m.candidate().str(), "", std::move(menu_entry)});
} }
return { begin.coord(), cursor_pos, std::move(candidates), buffer.timestamp() }; return { begin.base().coord(), cursor_pos, std::move(candidates), buffer.timestamp() };
} }
template<bool require_slash> template<bool require_slash>

View File

@ -1,55 +1,59 @@
#include "ranked_match.hh" #include "ranked_match.hh"
#include "utf8_iterator.hh"
#include "unit_tests.hh" #include "unit_tests.hh"
namespace Kakoune namespace Kakoune
{ {
using Utf8It = utf8::iterator<const char*>;
static int count_word_boundaries_match(StringView candidate, StringView query) static int count_word_boundaries_match(StringView candidate, StringView query)
{ {
int count = 0; int count = 0;
auto it = query.begin(); Utf8It qit{query.begin(), query};
char prev = 0; Codepoint prev = 0;
for (auto c : candidate) for (Utf8It it{candidate.begin(), candidate}; it != candidate.end(); ++it)
{ {
const Codepoint c = *it;
const bool is_word_boundary = prev == 0 or const bool is_word_boundary = prev == 0 or
(ispunct(prev) and is_word(c)) or (!iswalnum(prev) and iswalnum(c)) or
(islower(prev) and isupper(c)); (islower(prev) and isupper(c));
prev = c; prev = c;
if (not is_word_boundary) if (not is_word_boundary)
continue; continue;
const char lc = tolower(c); const Codepoint lc = tolower(c);
for (; it != query.end(); ++it) for (; qit != query.end(); ++qit)
{ {
const char qc = *it; const Codepoint qc = *qit;
if (qc == (islower(qc) ? lc : c)) if (qc == (islower(qc) ? lc : c))
{ {
++count; ++count;
++it; ++qit;
break; break;
} }
} }
if (it == query.end()) if (qit == query.end())
break; break;
} }
return count; return count;
} }
static bool smartcase_eq(char query, char candidate) static bool smartcase_eq(Codepoint query, Codepoint candidate)
{ {
return query == (islower(query) ? tolower(candidate) : candidate); return query == (islower(query) ? tolower(candidate) : candidate);
} }
static bool subsequence_match_smart_case(StringView str, StringView subseq) static bool subsequence_match_smart_case(StringView str, StringView subseq)
{ {
auto it = str.begin(); Utf8It it{str.begin(), str};
for (auto& c : subseq) for (Utf8It subseq_it{subseq.begin(), subseq}; subseq_it != subseq.end(); ++subseq_it)
{ {
if (it == str.end()) if (it == str.end())
return false; return false;
while (not smartcase_eq(c, *it)) while (not smartcase_eq(*subseq_it, *it))
{ {
if (++it == str.end()) if (++it == str.end())
return false; return false;
@ -98,9 +102,9 @@ bool RankedMatch::operator<(const RankedMatch& other) const
return m_first_char_match; return m_first_char_match;
return std::lexicographical_compare( return std::lexicographical_compare(
m_candidate.begin(), m_candidate.end(), Utf8It{m_candidate.begin(), m_candidate}, Utf8It{m_candidate.end(), m_candidate},
other.m_candidate.begin(), other.m_candidate.end(), Utf8It{other.m_candidate.begin(), other.m_candidate}, Utf8It{other.m_candidate.end(), other.m_candidate},
[](char a, char b) { [](Codepoint a, Codepoint b) {
const bool low_a = islower(a), low_b = islower(b); const bool low_a = islower(a), low_b = islower(b);
return low_a == low_b ? a < b : low_a; return low_a == low_b ? a < b : low_a;
}); });

View File

@ -25,7 +25,7 @@ public:
template<typename Container> template<typename Container>
iterator(Iterator it, const Container& c) iterator(Iterator it, const Container& c)
: m_it{std::move(it)}, m_begin{begin(c)}, m_end{end(c)} : m_it{std::move(it)}, m_begin{std::begin(c)}, m_end{std::end(c)}
{} {}
iterator& operator++() iterator& operator++()