summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2020-11-07 10:19:11 +1100
committerMaxime Coste <mawww@kakoune.org>2020-11-07 10:42:51 +1100
commit3ae2a5c2f666bae94f756407e262ebce7b5f5ef2 (patch)
treea0c3354646fba98d60af048b1f115fb2a2c2f36e
parentb1745ee8d353bdbe154666aadddccae87359dddf (diff)
Fix performance issue with word completion
When pasting many words with <a-p> we can end-up with a huge concatenated word and many selections, the previous code ended up iterating from each selection cursor to that word start and end to find the word under the cursor. This could lead to performance issue as each selection would trigger iteration on that huge word. This is unnecessary as word completion has a word length limit, so we now take it into account to avoid iterating to far from the cursor position.
-rw-r--r--src/insert_completer.cc14
-rw-r--r--src/word_db.cc4
-rw-r--r--src/word_db.hh2
3 files changed, 13 insertions, 7 deletions
diff --git a/src/insert_completer.cc b/src/insert_completer.cc
index 03ce45a5..ca6b08a1 100644
--- a/src/insert_completer.cc
+++ b/src/insert_completer.cc
@@ -86,9 +86,12 @@ InsertCompletion complete_word(const SelectionList& sels,
HashMap<StringView, int> sel_word_counts;
for (int i = 0; i < sels.size(); ++i)
{
+ int len = 0;
+ auto is_short_enough_word = [&] (Codepoint c) { return len++ < WordDB::max_word_len && is_word_pred(c); };
+
Utf8It end{buffer.iterator_at(sels[i].cursor()), buffer};
Utf8It begin = end-1;
- if (not skip_while_reverse(begin, buffer.begin(), is_word_pred) and
+ if (not skip_while_reverse(begin, buffer.begin(), is_short_enough_word) and
begin < end) // (begin might == end if end == buffer.begin())
++begin;
@@ -98,10 +101,13 @@ InsertCompletion complete_word(const SelectionList& sels,
prefix = buffer.substr(word_begin, end.base().coord());
}
- skip_while(end, buffer.end(), is_word_pred);
+ skip_while(end, buffer.end(), is_short_enough_word);
- StringView word = buffer.substr(begin.base().coord(), end.base().coord());
- ++sel_word_counts[word];
+ if (len <= WordDB::max_word_len)
+ {
+ StringView word = buffer.substr(begin.base().coord(), end.base().coord());
+ ++sel_word_counts[word];
+ }
}
struct RankedMatchAndBuffer : RankedMatch
diff --git a/src/word_db.cc b/src/word_db.cc
index 17db080b..ed0c7d99 100644
--- a/src/word_db.cc
+++ b/src/word_db.cc
@@ -21,8 +21,6 @@ WordDB& get_word_db(const Buffer& buffer)
struct WordSplitter
{
- static constexpr CharCount max_word_len = 50;
-
struct Iterator
{
Iterator(const char* begin, const WordSplitter& splitter)
@@ -48,7 +46,7 @@ struct WordSplitter
utf8::to_next(m_word_end, end);
++word_len;
}
- if (m_word_begin == end or word_len < max_word_len)
+ if (m_word_begin == end or word_len < WordDB::max_word_len)
break;
}
diff --git a/src/word_db.hh b/src/word_db.hh
index dab65d4c..ac7b8c01 100644
--- a/src/word_db.hh
+++ b/src/word_db.hh
@@ -18,6 +18,8 @@ class Buffer;
class WordDB : public OptionManagerWatcher
{
public:
+ static constexpr CharCount max_word_len = 50;
+
WordDB(const Buffer& buffer);
~WordDB();
WordDB(const WordDB&) = delete;