diff --git a/src/modification.cc b/src/modification.cc index 876463f1..ba22a373 100644 --- a/src/modification.cc +++ b/src/modification.cc @@ -134,6 +134,9 @@ std::vector compute_modifications(memoryview chang else num_removed.column = change.end.column - change.begin.column; + ByteCoord num_added; + + // merge modifications lying in the erased range. auto delend = std::upper_bound(next, res.end(), change.end, [](const ByteCoord& l, const Modification& c) { return l < c.new_coord; }); @@ -142,36 +145,44 @@ std::vector compute_modifications(memoryview chang { { LineCount removed_from_it = change.end.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); + num_removed.line += it->num_removed.line - std::min(removed_from_it, it->num_added.line); + num_added.line += std::max(0_line, it->num_added.line - removed_from_it); } if (it->new_coord.line == change.end.line) + num_removed.column += it->num_removed.column; + if (it->new_coord.line + it->num_added.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); + ByteCount removed_from_added = std::min(num_removed.column, it->num_added.column); + num_added.column += std::max(0_byte, it->num_added.column - removed_from_added); + num_removed.column -= removed_from_added; } + if (it->new_coord.line == change.begin.line) + num_removed.column += it->new_coord.column - change.begin.column; } 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) + // update modification with changes + if (change.end.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; + ByteCount removed_from_added = std::min(num_removed.column, modif.num_added.column); + modif.num_added.column = std::max(0_byte, modif.num_added.column - removed_from_added) + num_added.column; + modif.num_removed.column += num_removed.column - removed_from_added; + } + else if (change.end.line > modif.new_coord.line + modif.num_added.line) + { + modif.num_added.column = num_added.column; + modif.num_removed.column = num_removed.column; } - ByteCoord num_removed_from_added = std::min(num_removed, num_added_after_pos); - modif.num_added -= num_removed_from_added; - if (change.begin.line == modif.new_coord.line) modif.num_added.column += change.begin.column - modif.new_coord.column; - else - modif.num_added.column += change.begin.column; - modif.num_removed += num_removed - num_removed_from_added; + { + LineCount change_pos_in_modif = change.begin.line - modif.new_coord.line; + LineCount removed_from_added = std::min(num_removed.line, modif.num_added.line - change_pos_in_modif); + modif.num_added.line = std::max(0_line, modif.num_added.line - removed_from_added) + num_added.line; + modif.num_removed.line += num_removed.line - removed_from_added; + } for (auto it = next; it != res.end(); ++it) { diff --git a/src/unit_tests.cc b/src/unit_tests.cc index 36c885bd..16b6b122 100644 --- a/src/unit_tests.cc +++ b/src/unit_tests.cc @@ -217,6 +217,33 @@ void test_modification() kak_assert(modif.num_added == ByteCoord{0 COMMA 10}); kak_assert(modif.num_removed == ByteCoord{0 COMMA 10}); } + { + std::vector change = { + { Buffer::Change::Insert, {1, 10}, {2, 20}, false }, + { Buffer::Change::Erase, {1, 5}, {2, 10}, false }, + }; + auto modifs = compute_modifications(change); + kak_assert(modifs.size() == 1); + auto& modif = modifs[0]; + kak_assert(modif.old_coord == ByteCoord{1 COMMA 5}); + kak_assert(modif.new_coord == ByteCoord{1 COMMA 5}); + kak_assert(modif.num_added == ByteCoord{0 COMMA 10}); + kak_assert(modif.num_removed == ByteCoord{0 COMMA 5}); + } + { + std::vector change = { + { Buffer::Change::Insert, {1, 10}, {2, 20}, false }, + { Buffer::Change::Erase, {1, 5}, {2, 10}, false }, + { Buffer::Change::Erase, {1, 10}, {2, 0}, false }, + }; + auto modifs = compute_modifications(change); + kak_assert(modifs.size() == 1); + auto& modif = modifs[0]; + kak_assert(modif.old_coord == ByteCoord{1 COMMA 5}); + kak_assert(modif.new_coord == ByteCoord{1 COMMA 5}); + kak_assert(modif.num_added == ByteCoord{0 COMMA 5}); + kak_assert(modif.num_removed == ByteCoord{1 COMMA 0}); + } Buffer buffer("test", Buffer::Flags::None, { "tchou mutch\n",