+ ((or (eq def 'undo) (eq def 'undo-all))
+ (if (null stack)
+ (progn
+ (message "Nothing to undo")
+ (ding 'no-terminate)
+ (sit-for 1))
+ (let ((stack-idx 0)
+ (stack-len (length stack))
+ (num-replacements 0)
+ search-string
+ next-replacement)
+ (while (and (< stack-idx stack-len)
+ stack
+ (null replaced))
+ (let* ((elt (nth stack-idx stack)))
+ (setq
+ stack-idx (1+ stack-idx)
+ replaced (nth 1 elt)
+ ;; Bind swapped values
+ ;; (search-string <--> replacement)
+ search-string (nth (if replaced 4 3) elt)
+ next-replacement (nth (if replaced 3 4) elt)
+ search-string-replaced search-string
+ next-replacement-replaced next-replacement)
+
+ (when (and (= stack-idx stack-len)
+ (null replaced)
+ (zerop num-replacements))
+ (message "Nothing to undo")
+ (ding 'no-terminate)
+ (sit-for 1))
+
+ (when replaced
+ (setq stack (nthcdr stack-idx stack))
+ (goto-char (nth 0 elt))
+ (set-match-data (nth 2 elt))
+ (setq real-match-data
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (looking-at search-string)
+ (match-data t (nth 2 elt)))
+ noedit
+ (replace-match-maybe-edit
+ next-replacement nocasify literal
+ noedit real-match-data backward)
+ replace-count (1- replace-count)
+ real-match-data
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (looking-at next-replacement)
+ (match-data t (nth 2 elt))))
+ ;; Set replaced nil to keep in loop
+ (when (eq def 'undo-all)
+ (setq replaced nil
+ stack-len (- stack-len stack-idx)
+ stack-idx 0
+ num-replacements
+ (1+ num-replacements))))))
+ (when (and (eq def 'undo-all)
+ (null (zerop num-replacements)))
+ (message "Undid %d %s" num-replacements
+ (if (= num-replacements 1)
+ "replacement"
+ "replacements"))
+ (ding 'no-terminate)
+ (sit-for 1)))
+ (setq replaced nil last-was-undo t)))