diff --git a/src/buffer.cc b/src/buffer.cc index 5219f1b6..c92f09b1 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -39,7 +39,7 @@ Buffer::Buffer(String name, Flags flags, std::vector lines, pos += m_lines.back().length(); } - m_changes.push_back({ Change::Insert, {0,0}, line_count() }); + m_changes.push_back({ Change::Insert, {0,0}, line_count(), true }); if (flags & Flags::File) { @@ -78,7 +78,7 @@ void Buffer::reload(std::vector lines, time_t fs_timestamp) for (auto listener : m_change_listeners) listener->on_erase(*this, {0,0}, back_coord()); - m_changes.push_back({ Change::Erase, {0,0}, back_coord() }); + m_changes.push_back({ Change::Erase, {0,0}, back_coord(), true }); m_history.clear(); m_current_undo_group.clear(); @@ -99,7 +99,7 @@ void Buffer::reload(std::vector lines, time_t fs_timestamp) } m_fs_timestamp = fs_timestamp; - m_changes.push_back({ Change::Insert, {0,0}, back_coord() }); + m_changes.push_back({ Change::Insert, {0,0}, back_coord(), true }); for (auto listener : m_change_listeners) listener->on_insert(*this, {0,0}, back_coord()); @@ -459,6 +459,7 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content) ByteCoord begin; ByteCoord end; + bool at_end = false; // if we inserted at the end of the buffer, we have created a new // line without inserting a '\n' if (is_end(pos)) @@ -477,6 +478,7 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content) begin = pos.column == 0 ? pos : ByteCoord{ pos.line + 1, 0 }; end = ByteCoord{ line_count()-1, m_lines.back().length() }; + at_end = true; } else { @@ -519,7 +521,7 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content) end = ByteCoord{ last_line, m_lines[last_line].length() - suffix.length() }; } - m_changes.push_back({ Change::Insert, begin, end }); + m_changes.push_back({ Change::Insert, begin, end, at_end }); for (auto listener : m_change_listeners) listener->on_insert(*this, begin, end); return begin; @@ -550,7 +552,7 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end) for (LineCount i = begin.line+1; i < line_count(); ++i) m_lines[i].start -= length; - m_changes.push_back({ Change::Erase, begin, end }); + m_changes.push_back({ Change::Erase, begin, end, is_end(begin) }); for (auto listener : m_change_listeners) listener->on_erase(*this, begin, end); return next; diff --git a/src/buffer.hh b/src/buffer.hh index 46b982a8..89684ce5 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -182,6 +182,7 @@ public: Type type; ByteCoord begin; ByteCoord end; + bool at_end; }; memoryview changes_since(size_t timestamp) const; private: diff --git a/src/line_change_watcher.cc b/src/line_change_watcher.cc index 2e7ba879..c13a43b2 100644 --- a/src/line_change_watcher.cc +++ b/src/line_change_watcher.cc @@ -1,12 +1,57 @@ #include "line_change_watcher.hh" +#include "buffer.hh" + namespace Kakoune { +namespace +{ + +struct Change +{ + LineCount pos; + LineCount num; +}; + +std::vector compute_changes(const Buffer& buffer, size_t timestamp) +{ + std::vector res; + for (auto& change : buffer.changes_since(timestamp)) + { + ByteCoord begin = change.begin; + ByteCoord end = change.end; + if (change.type == Buffer::Change::Insert) + { + if (change.at_end and begin != ByteCoord{0,0}) + { + kak_assert(begin.column == 0); + --begin.line; + } + res.push_back({begin.line, end.line - begin.line}); + } + else + { + if (change.at_end and begin != ByteCoord{0,0}) + { + kak_assert(begin.column == 0); + --begin.line; + } + res.push_back({begin.line, begin.line - end.line}); + } + } + return res; +} + +} + +LineChangeWatcher::LineChangeWatcher(const Buffer& buffer) + : m_buffer(&buffer), m_timestamp(buffer.timestamp()) {} + std::vector LineChangeWatcher::compute_modifications() { std::vector res; - for (auto& change : m_changes) + for (auto& change : compute_changes(*m_buffer, m_timestamp)) { auto pos = std::upper_bound(res.begin(), res.end(), change.pos, [](const LineCount& l, const LineModification& c) @@ -58,28 +103,8 @@ std::vector LineChangeWatcher::compute_modifications() it->new_line -= num_removed; } } - m_changes.clear(); + m_timestamp = m_buffer->timestamp(); return res; } -void LineChangeWatcher::on_insert(const Buffer& buffer, ByteCoord begin, ByteCoord end) -{ - if (buffer.is_end(end)) - { - kak_assert(begin.column == 0); - --begin.line; - } - m_changes.push_back({begin.line, end.line - begin.line}); -} - -void LineChangeWatcher::on_erase(const Buffer& buffer, ByteCoord begin, ByteCoord end) -{ - if (begin.line == buffer.line_count()) - { - kak_assert(begin.column == 0); - --begin.line; - } - m_changes.push_back({begin.line, begin.line - end.line}); -} - } diff --git a/src/line_change_watcher.hh b/src/line_change_watcher.hh index ce7bedfa..d35167ca 100644 --- a/src/line_change_watcher.hh +++ b/src/line_change_watcher.hh @@ -1,11 +1,14 @@ #ifndef line_change_watcher_hh_INCLUDED #define line_change_watcher_hh_INCLUDED -#include "buffer.hh" +#include "units.hh" +#include "utils.hh" namespace Kakoune { +class Buffer; + struct LineModification { LineCount old_line; // line position in the old buffer @@ -16,23 +19,17 @@ struct LineModification LineCount diff() const { return new_line - old_line + num_added - num_removed; } }; -class LineChangeWatcher : public BufferChangeListener_AutoRegister +class LineChangeWatcher { public: - LineChangeWatcher (const Buffer& buffer) - : BufferChangeListener_AutoRegister(const_cast(buffer)) {} + LineChangeWatcher (const Buffer& buffer); std::vector compute_modifications(); -private: - void on_insert(const Buffer& buffer, ByteCoord begin, ByteCoord end) override; - void on_erase(const Buffer& buffer, ByteCoord begin, ByteCoord end) override; - struct Change - { - LineCount pos; - LineCount num; - }; - std::vector m_changes; + const Buffer& buffer() const { return *m_buffer; } +private: + safe_ptr m_buffer; + size_t m_timestamp; }; } diff --git a/src/word_db.cc b/src/word_db.cc index 62e19290..73f6e1ad 100644 --- a/src/word_db.cc +++ b/src/word_db.cc @@ -65,7 +65,7 @@ void WordDB::update_db() if (modifs.empty()) return; - auto& buffer = m_change_watcher.registry(); + auto& buffer = m_change_watcher.buffer(); LineToWords new_lines; new_lines.reserve((int)buffer.line_count());