summaryrefslogtreecommitdiff
path: root/src/selection.cc
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2022-11-28 20:27:44 +1100
committerMaxime Coste <mawww@kakoune.org>2022-11-28 20:27:44 +1100
commit2688893156ca45672b1d277092c0cc9004eaffae (patch)
tree6fdef59cc650b6b2171e987e4e95e13d20921259 /src/selection.cc
parent760a45556cfb8f50813ce8d1712a0a23f86dcf52 (diff)
Fix pasting after when selections are overlapping
With overlapping selections, pasting after breaks assumption of SelectionList::for_each as our changes are no longer happening in increasing locations. We hence cannot rely on the ForwardChangeTracker in that case and have to rely on the more general (and more costly) ranges update logic. This interacts poorly with paste linewise pastes and we try to preserve the current behaviour by tracking the last paste position. Overall, this change really begs for overlapping selections to be removed, but we will fix them like that for now. Fixes #4779
Diffstat (limited to 'src/selection.cc')
-rw-r--r--src/selection.cc43
1 files changed, 33 insertions, 10 deletions
diff --git a/src/selection.cc b/src/selection.cc
index cbf9bef2..f0f0270c 100644
--- a/src/selection.cc
+++ b/src/selection.cc
@@ -362,22 +362,45 @@ static void fix_overflowing_selections(Vector<Selection>& selections,
}
}
-void SelectionList::for_each(ApplyFunc func)
+bool any_overlaps(ConstArrayView<Selection> sels)
+{
+ for (int i = 0; i + 1 < sels.size(); ++i)
+ {
+ if (overlaps(sels[i], sels[i+1]))
+ return true;
+ }
+ return false;
+}
+
+void SelectionList::for_each(ApplyFunc func, bool may_append)
{
update();
- ForwardChangesTracker changes_tracker;
- for (size_t index = 0; index < m_selections.size(); ++index)
+ if (may_append and any_overlaps(m_selections))
+ {
+ size_t timestamp = m_buffer->timestamp();
+ for (size_t index = 0; index < m_selections.size(); ++index)
+ {
+ auto& sel = m_selections[index];
+ update_ranges(*m_buffer, timestamp, ArrayView<Selection>(sel));
+ func(index, sel);
+ }
+ }
+ else
{
- auto& sel = m_selections[index];
+ ForwardChangesTracker changes_tracker;
+ for (size_t index = 0; index < m_selections.size(); ++index)
+ {
+ auto& sel = m_selections[index];
- sel.anchor() = changes_tracker.get_new_coord_tolerant(sel.anchor());
- sel.cursor() = changes_tracker.get_new_coord_tolerant(sel.cursor());
- kak_assert(m_buffer->is_valid(sel.anchor()) and m_buffer->is_valid(sel.cursor()));
+ sel.anchor() = changes_tracker.get_new_coord_tolerant(sel.anchor());
+ sel.cursor() = changes_tracker.get_new_coord_tolerant(sel.cursor());
+ kak_assert(m_buffer->is_valid(sel.anchor()) and m_buffer->is_valid(sel.cursor()));
- func(index, sel);
+ func(index, sel);
- changes_tracker.update(*m_buffer, m_timestamp);
+ changes_tracker.update(*m_buffer, m_timestamp);
+ }
}
// We might just have been deleting text if strings were empty,
@@ -414,7 +437,7 @@ void SelectionList::replace(ConstArrayView<String> strings)
for_each([&](size_t index, Selection& sel) {
Kakoune::replace(*m_buffer, sel, strings[std::min(strings.size()-1, index)]);
- });
+ }, false);
}
void SelectionList::erase()