summaryrefslogtreecommitdiff
path: root/src/modification.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/modification.cc')
-rw-r--r--src/modification.cc128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/modification.cc b/src/modification.cc
new file mode 100644
index 00000000..b5e91c1f
--- /dev/null
+++ b/src/modification.cc
@@ -0,0 +1,128 @@
+#include "modification.hh"
+
+#include "buffer.hh"
+
+namespace Kakoune
+{
+
+namespace
+{
+
+ByteCount change_added_column(const Buffer::Change& change)
+{
+ kak_assert(change.type == Buffer::Change::Insert);
+ if (change.begin.line == change.end.line)
+ return change.end.column - change.begin.column;
+ else
+ return change.end.column;
+}
+
+}
+
+std::vector<Modification> compute_modifications(memoryview<Buffer::Change> changes)
+{
+ std::vector<Modification> res;
+ for (auto& change : changes)
+ {
+ auto pos = std::upper_bound(res.begin(), res.end(), change.begin,
+ [](const ByteCoord& l, const Modification& c)
+ { return l < c.new_coord; });
+
+ if (pos != res.begin())
+ {
+ auto& prev = *(pos-1);
+ if (change.begin <= prev.added_end())
+ --pos;
+ else
+ pos = res.insert(pos, {prev.get_old_coord(change.begin), change.begin, {}, {}});
+ }
+ else
+ pos = res.insert(pos, {change.begin, change.begin, {}, {}});
+
+ auto& modif = *pos;
+ auto next = pos + 1;
+ if (change.type == Buffer::Change::Insert)
+ {
+ const LineCount last_line = modif.new_coord.line + modif.num_added.line;
+
+ ByteCoord num_added = { change.end.line - change.begin.line, 0 };
+
+ modif.num_added.line += num_added.line;
+
+ if (change.begin.line == last_line)
+ {
+ if (change.end.line == change.begin.line)
+ num_added.column = change.end.column - change.begin.column;
+ else
+ num_added.column = change.end.column - modif.num_added.column;
+
+ modif.num_added.column += num_added.column;
+ kak_assert(modif.num_added.column >= 0);
+ }
+
+ for (auto it = next; it != res.end(); ++it)
+ {
+ if (it->new_coord.line == change.begin.line and it->num_added.line == 0)
+ it->new_coord.column += num_added.column;
+
+ it->new_coord.line += num_added.line;
+ }
+ }
+ else
+ {
+ ByteCoord num_removed = { change.end.line - change.begin.line, 0 };
+ if (num_removed.line != 0)
+ num_removed.column = change.end.column;
+ else
+ num_removed.column = change.end.column - change.begin.column;
+
+ auto delend = std::upper_bound(next, res.end(), change.end,
+ [](const ByteCoord& l, const Modification& c)
+ { return l < c.new_coord; });
+
+ for (auto it = next; it != delend; ++it)
+ {
+ {
+ LineCount removed_from_it = (change.begin.line + num_removed.line - it->new_coord.line);
+ modif.num_removed.line += it->num_removed.line - std::min(removed_from_it, it->num_added.line);
+ modif.num_added.line += std::max(0_line, it->num_added.line - removed_from_it);
+ }
+
+ if (it->new_coord.line == change.end.line)
+ {
+ ByteCount removed_from_it = num_removed.column - it->new_coord.column;
+ modif.num_removed.column += it->num_removed.column - std::min(removed_from_it, it->num_added.column);
+ modif.num_added.column += std::max(0_byte, it->num_added.column - removed_from_it);
+ }
+ }
+ next = res.erase(next, delend);
+
+ ByteCoord num_added_after_pos = { modif.new_coord.line + modif.num_added.line - change.begin.line, 0 };
+ if (change.begin.line == modif.new_coord.line + modif.num_added.line)
+ {
+ if (modif.num_added.line == 0)
+ num_added_after_pos.column = modif.new_coord.column + modif.num_added.column - change.begin.column;
+ else
+ num_added_after_pos.column = modif.num_added.column - change.begin.column;
+ }
+ ByteCoord num_removed_from_added = std::min(num_removed, num_added_after_pos);
+ modif.num_added -= num_removed_from_added;
+ modif.num_removed += num_removed - num_removed_from_added;
+
+ for (auto it = next; it != res.end(); ++it)
+ {
+ if (it->new_coord.line == change.end.line and it->num_added.line == 0)
+ it->new_coord.column -= num_removed.column;
+ it->new_coord.line -= num_removed.line;
+ }
+ }
+ }
+ return res;
+}
+
+std::vector<Modification> compute_modifications(const Buffer& buffer, size_t timestamp)
+{
+ return compute_modifications(buffer.changes_since(timestamp));
+}
+
+}