Search code examples
emacselisp

Elisp - adding multiple insertions to buffer-undo-list (saving undo information)


Update: my original question was answered, but I'd like to know the more general approach - how can I define multiple operations which will be undone with a single C-/.

I'm trying to write a function which will automatically insert TODO comment into my code. I want this function to have an "undo option".

I figured out how to add a mark to buffer-undo-list:

(setq buffer-undo-list (cons (point) buffer-undo-list)) 

This allows me to return the point to the position from which this function was executed (if I decide to undo).

My question is: how can I add multiple insertions to buffer-undo-list? What I mean is that there are multiple (insert str) statements in my function, but I want to undo all of them together with a single C-/ (if I decide to undo).

I tried to copy exactly from other function which has this property, but this didn't work out. The code below is what I have now:

(defun insert-todo ()
  "Appednd 'TODO username: date - ' at the end of line and set point 
to where this string ends"
  (interactive)

  (setq buffer-undo-list (cons (point) buffer-undo-list))   ;; save the point for undo
  (save-excursion 
    (end-of-line)
    (setq eol (point))
    (let ((buffer-undo-list t)) ;; do not record following commands for undo    
      (insert " " comment-start (save-excursion comment-end))   
      (insert (format " TODO %s: " (getenv "USER")) (format-time-string "%d.%m.%Y") " - ") 
      (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list))))
  (end-of-line)
  )

Solution

  • Just don't touch buffer-undo-list. It's automatically updated as part of insert so it should "just work" without you doing anything special.

    The way it works is that instead of inventing new formats of undo enties that combine various modifications, the undo-log is sprinkled with boundaries and when you undo, all the entries between two boundaries get undone "in one step". A boundary is normally added after each iteration of the read-eval-print loop, so in 99% of cases, it "just works".