summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Altmanninger <aclopte@gmail.com>2022-12-22 18:09:45 +0100
committerJohannes Altmanninger <aclopte@gmail.com>2022-12-27 18:24:55 +0100
commit516759bb2fd95d02134bc84130bf9060e0354310 (patch)
treeaad2a7fdebaf054c2c0165b790e3228b95ba6825
parent8427379a5dfcf35af35fd5a7b26803e8727476e6 (diff)
Make selection undo skip over entries that are nop after buffer change
After buffer modification - in particular after deletion - adjacent selection history entries may correspond to the same effective selection when applied to the current buffer. This means that we sometimes need to press <c-h> multiple times to make one visible change. This is not what the user expects, so let's keep walking the selection history until we hit an actual change. Alternatively, we could minimize the selection history after buffer changes but I think that would make the it worse after content undo+redo.
-rw-r--r--src/context.cc37
-rw-r--r--test/normal/selection-undo/fold-redundant-entries/cmd1
-rw-r--r--test/normal/selection-undo/fold-redundant-entries/in4
-rw-r--r--test/normal/selection-undo/fold-redundant-entries/out3
-rw-r--r--test/normal/selection-undo/fold-redundant-entries/script2
5 files changed, 31 insertions, 16 deletions
diff --git a/src/context.cc b/src/context.cc
index 3a0aadb4..0c1b8aad 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -225,24 +225,29 @@ void Context::SelectionHistory::undo()
if (in_edition())
throw runtime_error("selection undo is only supported at top-level");
kak_assert(not empty());
+ SelectionList old_selections = selections();
HistoryId next;
- if constexpr (backward)
- next = current_history_node().parent;
- else
- next = current_history_node().redo_child;
- if (next == HistoryId::Invalid)
- throw runtime_error(backward ? "no selection change to undo" : "no selection change to redo");
- auto select_next = [&, next] {
- HistoryId previous_id = m_history_id;
- m_history_id = next;
+ do
+ {
if constexpr (backward)
- current_history_node().redo_child = previous_id;
- };
- Buffer& destination_buffer = history_node(next).selections.buffer();
- if (&destination_buffer == &m_context.buffer())
- select_next();
- else
- m_context.change_buffer(destination_buffer, { std::move(select_next) });
+ next = current_history_node().parent;
+ else
+ next = current_history_node().redo_child;
+ if (next == HistoryId::Invalid)
+ throw runtime_error(backward ? "no selection change to undo" : "no selection change to redo");
+ auto select_next = [&, next] {
+ HistoryId previous_id = m_history_id;
+ m_history_id = next;
+ if constexpr (backward)
+ current_history_node().redo_child = previous_id;
+ };
+ Buffer& destination_buffer = history_node(next).selections.buffer();
+ if (&destination_buffer == &m_context.buffer())
+ select_next();
+ else
+ m_context.change_buffer(destination_buffer, { std::move(select_next) });
+ }
+ while (selections() == old_selections);
}
void Context::SelectionHistory::forget_buffer(Buffer& buffer)
diff --git a/test/normal/selection-undo/fold-redundant-entries/cmd b/test/normal/selection-undo/fold-redundant-entries/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/normal/selection-undo/fold-redundant-entries/cmd
@@ -0,0 +1 @@
+
diff --git a/test/normal/selection-undo/fold-redundant-entries/in b/test/normal/selection-undo/fold-redundant-entries/in
new file mode 100644
index 00000000..94ebaf90
--- /dev/null
+++ b/test/normal/selection-undo/fold-redundant-entries/in
@@ -0,0 +1,4 @@
+1
+2
+3
+4
diff --git a/test/normal/selection-undo/fold-redundant-entries/out b/test/normal/selection-undo/fold-redundant-entries/out
new file mode 100644
index 00000000..239c8675
--- /dev/null
+++ b/test/normal/selection-undo/fold-redundant-entries/out
@@ -0,0 +1,3 @@
+2
+3
+here4
diff --git a/test/normal/selection-undo/fold-redundant-entries/script b/test/normal/selection-undo/fold-redundant-entries/script
new file mode 100644
index 00000000..456f92f2
--- /dev/null
+++ b/test/normal/selection-undo/fold-redundant-entries/script
@@ -0,0 +1,2 @@
+ui_out -ignore 4
+ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "gjgkxd<c-h>ihere<esc>" ] }'