Skip to main content
2 of 4
added 127 characters in body
Tobias
  • 33.7k
  • 1
  • 38
  • 78

The following is a proto-type implementation of an approximation of what you want. It exploits the fact that new branches in the undo-tree are added at the left-hand side of the current node.

The key-sequence C-M-_ is bound to undo-tree-walk which walks the right-upper part of the undo tree starting at the current node.

The behavior differs from what you want if the active branch of some sub-tree on the right-hand side of the current node is not the left-most branch in that sub-tree.

You can get in such a state by non-trival undo/redo-sequences.

Just try it for yourself to see whether that is sufficient for your application.

(defvar-local undo-tree-walk
  "Possible values:
nil: not in undo/redo-chain
undo: traversing undo tree upwards
redo: traversing undo tree downwards
")

(setq undo-tree-walk nil)

(defun undo-tree-walk ()
  "Walk the right-upper part of the undo-tree starting at the current node."
  (interactive)
  (set-transient-map undo-tree-walk-map t #'undo-tree-walk-off)
  (let ((num-branches (undo-tree-num-branches)))
    (cond
     ((= num-branches 0) ; arrived at leaf
      (setq undo-tree-walk 'undo))
     ((> num-branches 1) ; 
      (let ((branch (undo-tree-node-branch (undo-tree-current buffer-undo-tree))))
    (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
          (if (>= (1+ branch) (undo-tree-num-branches))
          (progn
            (setq undo-tree-walk 'undo)
            (1- (undo-tree-num-branches)))
        (setq undo-tree-walk 'redo)
        (1+ branch))))
      ;; no state change for (= num-branches 1)
      )
     ))
  (case undo-tree-walk
   (undo
    (undo-tree-undo-1))
   (redo
    (undo-tree-redo-1))
   (t
    (setq undo-tree-walk 'undo)
    (undo-tree-undo-1)))
  (let ((curbuf (current-buffer)))
    (undo-tree-visualize)
    (switch-to-buffer-other-window curbuf)))

(defun undo-tree-walk-off ()
  "Switch `undo-tree-walk' off."
  (setq undo-tree-walk nil))

(defvar undo-tree-walk-map
  (make-sparse-keymap)
  "Keymap active while `undo-tree-walk'.")

(define-key undo-tree-walk-map (kbd "C-M-_") #'undo-tree-walk)

(global-set-key (kbd "C-M-_") #'undo-tree-walk)

Note, that I added undo-tree-visualize to the end of undo-tree-walk to display the consequences of walking the undo-tree with undo-tree-walk. Feel free to modify the code to your likings.

Note also, that I had to choose this most simple approximation of a solution for your problem because of time-restrictions.

Tobias
  • 33.7k
  • 1
  • 38
  • 78