summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Altmanninger <aclopte@gmail.com>2025-05-10 21:39:28 +0200
committerMaxime Coste <mawww@kakoune.org>2025-05-11 10:08:43 +1000
commit3dac6e28ef2baaf01924a6b71310fc18d0a3c17e (patch)
tree1be732452f6631b1c91a69816ac1ce10b97521b9
parent23ea6e6a5230a62fc4c183b1898efb550db0c347 (diff)
Use linewise paste only if register is missing no trailing newline
We use linewise paste if any of the pasted register elements has a trailing newline. As shown in the previous patch, this leads to awkward situations where insertion positions from <a-P> are not monotonically increasing. This complicated behavior is questionable. The root cause is that linewise paste may insert some strings that don't have a trailing newline. This leads to weird cases of GIGO, especially when using <a-P> when the last element is missing a trailing newline. Simplify the implementation by not activating linewise paste in that case. Instead of special-casing the last element, try to simplify the behavior further by using line-wise paste only if *all* elements are properly terminated. I can't think of a real-world case where the existing behavior would be desired. A regression test shows a change in behavior. Might be less weird now. The added test case is a copy except it uses "P" instead of "p" (the extra newline is because "d" deletes the last newline in the buffer which gets added back implicitly). (I think the list of register elements is never empty, so this should never cause a trivial linewise paste. Even if so, that would be fine because inserting nothing is a nop either way.) Fixes #5312
-rw-r--r--src/normal.cc8
-rw-r--r--src/selection.cc18
-rw-r--r--test/normal/paste-all-before-missing-newline/out4
-rw-r--r--test/normal/paste-before-multiple-selections/cmd1
-rw-r--r--test/normal/paste-before-multiple-selections/in1
-rw-r--r--test/normal/paste-before-multiple-selections/out2
-rw-r--r--test/regression/1053-crash-on-deletion-and-paste/out3
7 files changed, 20 insertions, 17 deletions
diff --git a/src/normal.cc b/src/normal.cc
index ba5b6e06..d2318865 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -716,7 +716,7 @@ void paste(Context& context, NormalParams params)
{
const char reg = params.reg ? params.reg : '"';
auto strings = RegisterManager::instance()[reg].get(context);
- const bool linewise = any_of(strings, [](StringView str) {
+ const bool linewise = all_of(strings, [](StringView str) {
return not str.empty() and str.back() == '\n';
});
@@ -741,7 +741,6 @@ void paste_all(Context& context, NormalParams params)
{
const char reg = params.reg ? params.reg : '"';
auto strings = RegisterManager::instance()[reg].get(context);
- bool linewise = false;
String all;
Vector<ByteCount> offsets;
for (auto& str : strings)
@@ -749,11 +748,12 @@ void paste_all(Context& context, NormalParams params)
if (str.empty())
continue;
- if (str.back() == '\n')
- linewise = true;
all += str;
offsets.push_back(all.length());
}
+ const bool linewise = all_of(strings, [](StringView str) {
+ return not str.empty() and str.back() == '\n';
+ });
if (offsets.empty())
throw runtime_error("nothing to paste");
diff --git a/src/selection.cc b/src/selection.cc
index f893f21f..99b21c3e 100644
--- a/src/selection.cc
+++ b/src/selection.cc
@@ -394,18 +394,18 @@ void SelectionList::for_each(ApplyFunc func, bool may_append)
}
else
{
+ ForwardChangesTracker changes_tracker;
for (size_t index = 0; index < m_selections.size(); ++index)
{
- ForwardChangesTracker changes_tracker;
- func(index, m_selections[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()));
+
+ func(index, sel);
+
changes_tracker.update(*m_buffer, m_timestamp);
- for (size_t i = index + 1; i < m_selections.size(); ++i)
- {
- auto& sel = m_selections[i];
- 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()));
- }
}
}
diff --git a/test/normal/paste-all-before-missing-newline/out b/test/normal/paste-all-before-missing-newline/out
index aef9f4e9..bfb1058b 100644
--- a/test/normal/paste-all-before-missing-newline/out
+++ b/test/normal/paste-all-before-missing-newline/out
@@ -1,5 +1,5 @@
+dab
-
-ddabc
+dc
diff --git a/test/normal/paste-before-multiple-selections/cmd b/test/normal/paste-before-multiple-selections/cmd
new file mode 100644
index 00000000..668c56ab
--- /dev/null
+++ b/test/normal/paste-before-multiple-selections/cmd
@@ -0,0 +1 @@
+xSo<ret>dP
diff --git a/test/normal/paste-before-multiple-selections/in b/test/normal/paste-before-multiple-selections/in
new file mode 100644
index 00000000..323fae03
--- /dev/null
+++ b/test/normal/paste-before-multiple-selections/in
@@ -0,0 +1 @@
+foobar
diff --git a/test/normal/paste-before-multiple-selections/out b/test/normal/paste-before-multiple-selections/out
new file mode 100644
index 00000000..39113f99
--- /dev/null
+++ b/test/normal/paste-before-multiple-selections/out
@@ -0,0 +1,2 @@
+foobar
+
diff --git a/test/regression/1053-crash-on-deletion-and-paste/out b/test/regression/1053-crash-on-deletion-and-paste/out
index 24717027..c5f86129 100644
--- a/test/regression/1053-crash-on-deletion-and-paste/out
+++ b/test/regression/1053-crash-on-deletion-and-paste/out
@@ -1,4 +1,3 @@
-o
-f
+of
o
bar