Fix performance of word completion with many different selections

Fixes #1228
This commit is contained in:
Maxime Coste 2017-02-20 19:19:26 +00:00
parent 5eef2b9105
commit fe2d0fab71
4 changed files with 28 additions and 16 deletions

View File

@ -143,6 +143,7 @@ public:
size_t current_history_id() const noexcept; size_t current_history_id() const noexcept;
String string(BufferCoord begin, BufferCoord end) const; String string(BufferCoord begin, BufferCoord end) const;
StringView substr(BufferCoord begin, BufferCoord end) const;
const char& byte_at(BufferCoord c) const; const char& byte_at(BufferCoord c) const;
ByteCount distance(BufferCoord begin, BufferCoord end) const; ByteCount distance(BufferCoord begin, BufferCoord end) const;

View File

@ -89,6 +89,12 @@ inline size_t Buffer::timestamp() const
return m_changes.size(); return m_changes.size();
} }
inline StringView Buffer::substr(BufferCoord begin, BufferCoord end) const
{
kak_assert(begin.line == end.line);
return m_lines[begin.line].substr(begin.column, end.column - begin.column);
}
inline ConstArrayView<Buffer::Change> Buffer::changes_since(size_t timestamp) const inline ConstArrayView<Buffer::Change> Buffer::changes_since(size_t timestamp) const
{ {
if (timestamp < m_changes.size()) if (timestamp < m_changes.size())

View File

@ -90,25 +90,24 @@ InsertCompletion complete_word(const SelectionList& sels, const OptionManager& o
return {}; return {};
BufferCoord word_begin; BufferCoord word_begin;
String prefix; StringView prefix;
IdMap<int> sel_word_counts; UnorderedMap<StringView, int> sel_word_counts;
for (int i = 0; i < sels.size(); ++i) for (int i = 0; i < sels.size(); ++i)
{ {
Utf8It end{buffer.iterator_at(sels[i].cursor()), buffer}; Utf8It end{buffer.iterator_at(sels[i].cursor()), buffer};
Utf8It begin = end-1; Utf8It begin = end-1;
if (not skip_while_reverse(begin, buffer.begin(), if (not skip_while_reverse(begin, buffer.begin(), is_word_pred))
[&](Codepoint c) { return is_word_pred(c); }))
++begin; ++begin;
if (i == sels.main_index()) if (i == sels.main_index())
{ {
word_begin = begin.base().coord(); word_begin = begin.base().coord();
prefix = buffer.string(word_begin, end.base().coord()); prefix = buffer.substr(word_begin, end.base().coord());
} }
skip_while(end, buffer.end(), [&](Codepoint c) { return is_word_pred(c); }); skip_while(end, buffer.end(), is_word_pred);
auto word = buffer.string(begin.base().coord(), end.base().coord()); StringView word = buffer.substr(begin.base().coord(), end.base().coord());
++sel_word_counts[word]; ++sel_word_counts[word];
} }
@ -137,8 +136,8 @@ InsertCompletion complete_word(const SelectionList& sels, const OptionManager& o
// Remove words that are being edited // Remove words that are being edited
for (auto& word_count : sel_word_counts) for (auto& word_count : sel_word_counts)
{ {
if (get_word_db(buffer).get_word_occurences(word_count.key) <= word_count.value) if (get_word_db(buffer).get_word_occurences(word_count.first) <= word_count.second)
unordered_erase(matches, StringView{word_count.key}); unordered_erase(matches, word_count.first);
} }
if (other_buffers) if (other_buffers)
@ -156,7 +155,7 @@ InsertCompletion complete_word(const SelectionList& sels, const OptionManager& o
if (RankedMatch match{word, prefix}) if (RankedMatch match{word, prefix})
matches.emplace_back(match, nullptr); matches.emplace_back(match, nullptr);
unordered_erase(matches, StringView{prefix}); unordered_erase(matches, prefix);
std::sort(matches.begin(), matches.end()); std::sort(matches.begin(), matches.end());
matches.erase(std::unique(matches.begin(), matches.end()), matches.end()); matches.erase(std::unique(matches.begin(), matches.end()), matches.end());
@ -206,7 +205,7 @@ InsertCompletion complete_filename(const SelectionList& sels,
if (begin == pos) if (begin == pos)
return {}; return {};
auto prefix = buffer.string(begin.coord(), pos.coord()); StringView prefix = buffer.substr(begin.coord(), pos.coord());
if (require_slash and not contains(prefix, '/')) if (require_slash and not contains(prefix, '/'))
return {}; return {};
@ -273,8 +272,7 @@ InsertCompletion complete_option(const SelectionList& sels,
if (cursor_pos.line == coord.line and cursor_pos.column >= coord.column) if (cursor_pos.line == coord.line and cursor_pos.column >= coord.column)
{ {
StringView query = buffer[coord.line].substr( StringView query = buffer.substr(coord, cursor_pos);
coord.column, cursor_pos.column - coord.column);
const ColumnCount tabstop = options["tabstop"].get<int>(); const ColumnCount tabstop = options["tabstop"].get<int>();
const ColumnCount column = get_column(buffer, tabstop, cursor_pos); const ColumnCount column = get_column(buffer, tabstop, cursor_pos);

View File

@ -237,6 +237,12 @@ static void check_timeout(const int& timeout)
throw runtime_error{"the minimum acceptable timeout is 50 milliseconds"}; throw runtime_error{"the minimum acceptable timeout is 50 milliseconds"};
} }
static void check_extra_word_char(const String& extra_chars)
{
if (contains_that(extra_chars, is_blank))
throw runtime_error{"blanks are not accepted for extra completion characters"};
}
void register_options() void register_options()
{ {
OptionsRegistry& reg = GlobalScope::instance().option_registry(); OptionsRegistry& reg = GlobalScope::instance().option_registry();
@ -303,9 +309,10 @@ void register_options()
"%val{bufname} %val{cursor_line}:%val{cursor_char_column} "_str); "%val{bufname} %val{cursor_line}:%val{cursor_char_column} "_str);
reg.declare_option("debug", "various debug flags", DebugFlags::None); reg.declare_option("debug", "various debug flags", DebugFlags::None);
reg.declare_option("readonly", "prevent buffers from being modified", false); reg.declare_option("readonly", "prevent buffers from being modified", false);
reg.declare_option("completion_extra_word_char", reg.declare_option<String, check_extra_word_char>(
"Additional characters to be considered as words for insert completion", "completion_extra_word_char",
""_str); "Additional characters to be considered as words for insert completion",
""_str);
} }
static Client* local_client = nullptr; static Client* local_client = nullptr;