Fix performance of word completion with many different selections
Fixes #1228
This commit is contained in:
parent
5eef2b9105
commit
fe2d0fab71
|
@ -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;
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
13
src/main.cc
13
src/main.cc
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user