summaryrefslogtreecommitdiff
path: root/src
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 /src
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.
Diffstat (limited to 'src')
-rw-r--r--src/context.cc37
1 files changed, 21 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)