From e0d33f51b36c9f0be7ae2467dab455d211bbf561 Mon Sep 17 00:00:00 2001 From: Olivier Perret Date: Mon, 17 Apr 2023 10:25:51 +0200 Subject: Switch undo storage from a tree to a plain list Whenever a new history node is committed after some undo steps, instead of creating a new branch in the undo graph, we first append the inverse modifications starting from the end of the undo list up to the current position before adding the new node. For example let's assume that the undo history is A-B-C, that a single undo has been done (bringing us to state B) and that a new change D is committed. Instead of creating a new branch starting at B, we add the inverse of C (noted ^C) at the end, and D afterwards. This results in the undo history A-B-C-^C-D. Since C-^C collapses to a null change, this is equivalent to A-B-D but without having lost the C branch of the history. If a new change is committed while no undo has been done, the new history node is simply appended to the list, as was the case previously. This results in a simplification of the user interaction, as two bindings are now sufficient to walk the entire undo history, as opposed to needing extra bindings to switch branches whenever they occur. The and bindings are now free. It also simplifies the implementation, as the graph traversal and branching code are not needed anymore. The parent and child of a node are now respectively the previous and the next elements in the list, so there is no need to store their ID as part of the node. Only the committing of an undo group is slightly more complex, as inverse history nodes need to be added depending on the current position in the undo list. The following article was the initial motivation for this change: https://github.com/zaboople/klonk/blob/master/TheGURQ.md --- src/normal.cc | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'src/normal.cc') diff --git a/src/normal.cc b/src/normal.cc index 02cea4ef..e3220521 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -2009,29 +2009,6 @@ void redo(Context& context, NormalParams params) throw runtime_error("nothing left to redo"); } -template -void move_in_history(Context& context, NormalParams params) -{ - Buffer& buffer = context.buffer(); - size_t timestamp = buffer.timestamp(); - const int count = std::max(1, params.count); - const int history_id = (size_t)buffer.current_history_id() + direction * count; - const int max_history_id = (int)buffer.next_history_id() - 1; - if (buffer.move_to((Buffer::HistoryId)history_id)) - { - auto ranges = compute_modified_ranges(buffer, timestamp); - if (not ranges.empty()) - context.selections_write_only() = std::move(ranges); - - context.print_status({ format("moved to change #{} ({})", - history_id, max_history_id), - context.faces()["Information"] }); - } - else - throw runtime_error(format("no such change: #{} ({})", - history_id, max_history_id)); -} - template void undo_selection_change(Context& context, NormalParams params) { @@ -2362,8 +2339,6 @@ static constexpr HashMap { {'u'}, {"undo", undo} }, { {'U'}, {"redo", redo} }, - { {alt('u')}, {"move backward in history", move_in_history} }, - { {alt('U')}, {"move forward in history", move_in_history} }, { {ctrl('h')}, {"undo selection change", undo_selection_change} }, { {ctrl('k')}, {"redo selection change", undo_selection_change} }, -- cgit v1.2.3