WordDB now uses a LineChangeWatcher based implementation
This commit is contained in:
parent
a96b2d3cd2
commit
ad818853a2
122
src/word_db.cc
122
src/word_db.cc
|
@ -6,15 +6,9 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
WordDB::WordDB(const Buffer& buffer)
|
static std::vector<String> get_words(const String& content)
|
||||||
: BufferChangeListener_AutoRegister{const_cast<Buffer&>(buffer)}
|
|
||||||
{
|
|
||||||
for (auto line = 0_line, end = buffer.line_count(); line < end; ++line)
|
|
||||||
add_words(line, buffer[line]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WordDB::add_words(LineCount line, const String& content)
|
|
||||||
{
|
{
|
||||||
|
std::vector<String> res;
|
||||||
using Iterator = utf8::utf8_iterator<String::const_iterator,
|
using Iterator = utf8::utf8_iterator<String::const_iterator,
|
||||||
utf8::InvalidBytePolicy::Pass>;
|
utf8::InvalidBytePolicy::Pass>;
|
||||||
auto word_start = content.begin();
|
auto word_start = content.begin();
|
||||||
|
@ -30,80 +24,86 @@ void WordDB::add_words(LineCount line, const String& content)
|
||||||
}
|
}
|
||||||
else if (in_word and not word)
|
else if (in_word and not word)
|
||||||
{
|
{
|
||||||
String w{word_start, it.base()};
|
res.push_back({word_start, it.base()});
|
||||||
m_word_to_lines[w].push_back(line);
|
|
||||||
m_line_to_words[line].push_back(w);
|
|
||||||
in_word = false;
|
in_word = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
WordDB::LineToWords::iterator WordDB::remove_line(LineToWords::iterator it)
|
static void add_words(WordDB::WordList& wl, const std::vector<String>& words)
|
||||||
{
|
{
|
||||||
if (it == m_line_to_words.end())
|
for (auto& w : words)
|
||||||
return it;
|
++wl[w];
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& word : it->second)
|
static void remove_words(WordDB::WordList& wl, const std::vector<String>& words)
|
||||||
|
{
|
||||||
|
for (auto& w : words)
|
||||||
{
|
{
|
||||||
auto wtl_it = m_word_to_lines.find(word);
|
auto it = wl.find(w);
|
||||||
auto& lines = wtl_it->second;
|
kak_assert(it != wl.end() and it->second > 0);
|
||||||
lines.erase(find(lines, it->first));
|
if (--it->second == 0)
|
||||||
if (lines.empty())
|
wl.erase(it);
|
||||||
m_word_to_lines.erase(wtl_it);
|
|
||||||
}
|
}
|
||||||
return m_line_to_words.erase(it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WordDB::update_lines(LineToWords::iterator begin, LineToWords::iterator end,
|
WordDB::WordDB(const Buffer& buffer)
|
||||||
LineCount num)
|
: m_change_watcher{buffer}
|
||||||
{
|
{
|
||||||
std::vector<std::pair<LineCount, std::vector<String>>>
|
m_line_to_words.reserve((int)buffer.line_count());
|
||||||
to_update{std::make_move_iterator(begin), std::make_move_iterator(end)};
|
for (auto line = 0_line, end = buffer.line_count(); line < end; ++line)
|
||||||
m_line_to_words.erase(begin, end);
|
|
||||||
|
|
||||||
for (auto& elem : to_update)
|
|
||||||
{
|
{
|
||||||
for (auto& word : elem.second)
|
m_line_to_words.push_back(get_words(buffer[line]));
|
||||||
|
add_words(m_words, m_line_to_words.back());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WordDB::update_db()
|
||||||
|
{
|
||||||
|
auto modifs = m_change_watcher.compute_modifications();
|
||||||
|
if (modifs.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& buffer = m_change_watcher.registry();
|
||||||
|
|
||||||
|
LineToWords new_lines;
|
||||||
|
new_lines.reserve((int)buffer.line_count());
|
||||||
|
|
||||||
|
auto old_line = 0_line;
|
||||||
|
for (auto& modif : modifs)
|
||||||
|
{
|
||||||
|
kak_assert(0_line <= modif.new_line and modif.new_line < buffer.line_count());
|
||||||
|
kak_assert(old_line <= modif.old_line);
|
||||||
|
while (old_line < modif.old_line)
|
||||||
|
new_lines.push_back(std::move(m_line_to_words[(int)old_line++]));
|
||||||
|
|
||||||
|
kak_assert((int)new_lines.size() == (int)modif.new_line);
|
||||||
|
|
||||||
|
while (old_line <= modif.old_line + modif.num_removed)
|
||||||
{
|
{
|
||||||
auto& lines = m_word_to_lines[word];
|
kak_assert(old_line < m_line_to_words.size());
|
||||||
*find(lines, elem.first) += num;
|
remove_words(m_words, m_line_to_words[(int)old_line++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto l = 0_line; l <= modif.num_added; ++l)
|
||||||
|
{
|
||||||
|
new_lines.push_back(get_words(buffer[modif.new_line + l]));
|
||||||
|
add_words(m_words, new_lines.back());
|
||||||
}
|
}
|
||||||
elem.first += num;
|
|
||||||
}
|
}
|
||||||
m_line_to_words.insert(std::make_move_iterator(to_update.begin()),
|
while (old_line != (int)m_line_to_words.size())
|
||||||
std::make_move_iterator(to_update.end()));
|
new_lines.push_back(std::move(m_line_to_words[(int)old_line++]));
|
||||||
|
|
||||||
|
m_line_to_words = std::move(new_lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WordDB::on_insert(const Buffer& buffer, BufferCoord begin, BufferCoord end)
|
std::vector<String> WordDB::find_prefix(const String& prefix)
|
||||||
{
|
{
|
||||||
auto num = end.line - begin.line;
|
update_db();
|
||||||
if (num > 0)
|
|
||||||
update_lines(m_line_to_words.upper_bound(begin.line),
|
|
||||||
m_line_to_words.end(), num);
|
|
||||||
|
|
||||||
remove_line(m_line_to_words.find(begin.line));
|
|
||||||
for (auto line = begin.line; line <= end.line; ++line)
|
|
||||||
add_words(line, buffer[line]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WordDB::on_erase(const Buffer& buffer, BufferCoord begin, BufferCoord end)
|
|
||||||
{
|
|
||||||
auto first = m_line_to_words.lower_bound(begin.line);
|
|
||||||
auto last = m_line_to_words.upper_bound(end.line);
|
|
||||||
while (first != last)
|
|
||||||
first = remove_line(first);
|
|
||||||
|
|
||||||
auto num = end.line - begin.line;
|
|
||||||
if (num > 0)
|
|
||||||
update_lines(last, m_line_to_words.end(), -num);
|
|
||||||
|
|
||||||
add_words(begin.line, buffer[begin.line]);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<String> WordDB::find_prefix(const String& prefix) const
|
|
||||||
{
|
|
||||||
std::vector<String> res;
|
std::vector<String> res;
|
||||||
for (auto it = m_word_to_lines.lower_bound(prefix); it != m_word_to_lines.end(); ++it)
|
for (auto it = m_words.lower_bound(prefix); it != m_words.end(); ++it)
|
||||||
{
|
{
|
||||||
if (not prefix_match(it->first, prefix))
|
if (not prefix_match(it->first, prefix))
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
#define word_db_hh_INCLUDED
|
#define word_db_hh_INCLUDED
|
||||||
|
|
||||||
#include "buffer.hh"
|
#include "buffer.hh"
|
||||||
|
#include "line_change_watcher.hh"
|
||||||
|
|
||||||
#include <set>
|
#include <map>
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
@ -11,26 +12,21 @@ namespace Kakoune
|
||||||
class String;
|
class String;
|
||||||
|
|
||||||
// maintain a database of words available in a buffer
|
// maintain a database of words available in a buffer
|
||||||
class WordDB : public BufferChangeListener_AutoRegister
|
class WordDB
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WordDB(const Buffer& buffer);
|
WordDB(const Buffer& buffer);
|
||||||
|
|
||||||
void on_insert(const Buffer& buffer, BufferCoord begin, BufferCoord end) override;
|
std::vector<String> find_prefix(const String& prefix);
|
||||||
void on_erase(const Buffer& buffer, BufferCoord begin, BufferCoord end) override;
|
|
||||||
|
|
||||||
std::vector<String> find_prefix(const String& prefix) const;
|
|
||||||
|
|
||||||
|
using WordList = std::map<String, int>;
|
||||||
private:
|
private:
|
||||||
using WordToLines = std::map<String, std::vector<LineCount>>;
|
using LineToWords = std::vector<std::vector<String>>;
|
||||||
using LineToWords = std::map<LineCount, std::vector<String>>;
|
|
||||||
|
|
||||||
void add_words(LineCount line, const String& content);
|
void update_db();
|
||||||
LineToWords::iterator remove_line(LineToWords::iterator it);
|
|
||||||
void update_lines(LineToWords::iterator begin, LineToWords::iterator end,
|
|
||||||
LineCount num);
|
|
||||||
|
|
||||||
WordToLines m_word_to_lines;
|
LineChangeWatcher m_change_watcher;
|
||||||
|
WordList m_words;
|
||||||
LineToWords m_line_to_words;
|
LineToWords m_line_to_words;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user