summaryrefslogtreecommitdiff
path: root/src/normal.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/normal.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/normal.cc')
-rw-r--r--src/normal.cc25
1 files changed, 13 insertions, 12 deletions
diff --git a/src/normal.cc b/src/normal.cc
index a6cabec1..1142d871 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -429,7 +429,7 @@ void replace_with_char(Context& context, NormalParams)
context.selections().for_each([&](size_t index, Selection& sel) {
CharCount count = char_length(buffer, sel);
replace(buffer, sel, String{*cp, count});
- });
+ }, false);
}, "replace with char", "enter char to replace with\n");
}
@@ -455,7 +455,7 @@ void for_each_codepoint(Context& context, NormalParams)
begin != end; ++begin)
utf8::dump(std::back_inserter(str), func(*begin));
replace(buffer, sel, str);
- });
+ }, false);
}
void command(const Context& context, EnvVarMap env_vars, char reg = 0)
@@ -664,14 +664,14 @@ enum class PasteMode
Replace
};
-BufferCoord paste_pos(Buffer& buffer, const Selection& sel, PasteMode mode, bool linewise)
+BufferCoord paste_pos(Buffer& buffer, BufferCoord min, BufferCoord max, PasteMode mode, bool linewise)
{
switch (mode)
{
case PasteMode::Append:
- return linewise ? std::min(buffer.line_count(), sel.max().line+1) : buffer.char_next(sel.max());
+ return linewise ? std::min(buffer.line_count(), max.line+1) : buffer.char_next(max);
case PasteMode::Insert:
- return linewise ? sel.min().line : sel.min();
+ return linewise ? min.line : min;
default:
kak_assert(false);
return {};
@@ -690,16 +690,17 @@ void paste(Context& context, NormalParams params)
auto& buffer = context.buffer();
ScopedEdition edition(context);
ScopedSelectionEdition selection_edition{context};
- context.selections().for_each([&](size_t index, Selection& sel) {
+ context.selections().for_each([&, last=BufferCoord{}](size_t index, Selection& sel) mutable {
auto& str = strings[std::min(strings.size()-1, index)];
auto& min = sel.min();
auto& max = sel.max();
BufferRange range = (mode == PasteMode::Replace) ?
buffer.replace(min, buffer.char_next(max), str)
- : buffer.insert(paste_pos(buffer, sel, mode, linewise), str);
+ : buffer.insert(paste_pos(buffer, min, std::max(max, last), mode, linewise), str);
min = range.begin;
max = range.end > range.begin ? buffer.char_prev(range.end) : range.begin;
- });
+ last = max;
+ }, mode == PasteMode::Append);
}
template<PasteMode mode>
@@ -733,7 +734,7 @@ void paste_all(Context& context, NormalParams params)
selections.for_each([&](size_t, const Selection& sel) {
auto range = (mode == PasteMode::Replace) ?
buffer.replace(sel.min(), buffer.char_next(sel.max()), all)
- : buffer.insert(paste_pos(buffer, sel, mode, linewise), all);
+ : buffer.insert(paste_pos(buffer, sel.min(), sel.max(), mode, linewise), all);
ByteCount pos_offset = 0;
BufferCoord pos = range.begin;
@@ -744,7 +745,7 @@ void paste_all(Context& context, NormalParams params)
pos = buffer.next(end);
pos_offset = offset;
}
- });
+ }, mode == PasteMode::Append);
}
selections = std::move(result);
}
@@ -784,10 +785,10 @@ void insert_output(Context& context, NormalParams params)
auto& min = sel.min();
auto& max = sel.max();
- auto range = insert(buffer, sel, paste_pos(buffer, sel, mode, false), out);
+ auto range = insert(buffer, sel, paste_pos(buffer, min, max, mode, false), out);
min = range.begin;
max = range.end > range.begin ? buffer.char_prev(range.end) : range.begin;
- });
+ }, mode == PasteMode::Append);
selections.set_main_index(old_main);
});
}