(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)
(when (eq buffer-undo-list t)
(user-error "No undo information."))
(unless undo-tree-mode
(user-error "`undo-tree-walk' should only be used with `undo-tree-mode'."))
(undo-list-transfer-to-tree)
(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)