From 516759bb2fd95d02134bc84130bf9060e0354310 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 22 Dec 2022 18:09:45 +0100 Subject: [PATCH] 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 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. --- src/context.cc | 37 +++++++++++-------- .../selection-undo/fold-redundant-entries/cmd | 1 + .../selection-undo/fold-redundant-entries/in | 4 ++ .../selection-undo/fold-redundant-entries/out | 3 ++ .../fold-redundant-entries/script | 2 + 5 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 test/normal/selection-undo/fold-redundant-entries/cmd create mode 100644 test/normal/selection-undo/fold-redundant-entries/in create mode 100644 test/normal/selection-undo/fold-redundant-entries/out create mode 100644 test/normal/selection-undo/fold-redundant-entries/script 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": [ "gjgkxdihere" ] }'