In emacs, I sometimes invoke call-last-kbd-macro by mistake. When undoing I would have expected undo to undo the entire effect of the keyboard macro atomically, but that does not happen. Instead I find myself having to undo each step of the macro one at a time. How can I get emacs to return to the buffer state before the execution of the macro?
To execute the macro, press C-x e . This command executes the last macro you have defined.
Emacs Key Combinations. Note that C-x means Control-X while M-x means Meta-X where meta may mean hitting and releasing the escape key, or alt. These keys are excerpted from the Unix in a Nutshell book.
I'm afraid you can't do that with just the built-in 'undo
mechanism. The macro system in Emacs actually plays things back as though the user were actually typing in the keystrokes (or mouse events), and so the undo history (buffer-undo-list
) gets updated as normal.
Here's a suggestion of how to extend the current undo
mechanism to do what you want.
extend 'undo
to understand a new entry in the undo list, a macro-begin
marker and a macro-end
element
advise/change the macro playback to insert the markers at the beginning/end of the macro playback
have the undo
code treat all undo events between the two markers as a unit and undo them all (and add the appropriate markers on the end of the undo history so when you redo
things, they're still treated as a single block)
Caveats:
macro-begin
and macro-end
markers in the undo list.Needless to say, this is a complicated endeavor. I wish you luck.
This can be done pretty easily by overriding undo-boundary
with e.g. the noflet
package.
Given a macro definition (as generated by insert-kbd-macro
) as follows:
(fset 'my-macro
[... keys ...])
or:
(fset 'my-macro
(lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([...keys...] 0 "%d")) arg)))
Edit it as such:
(require 'noflet)
(fset 'my-macro
(lambda (&optional arg) "Keyboard macro." (interactive "p")
(undo-boundary)
(noflet ((undo-boundary ()))
(kmacro-exec-ring-item (quote ([...keys...] 0 "%d")) arg))
(undo-boundary)))
If you don't want to edit all your macro definitions, you could alternatively add a wrapper which invokes a macro given as an argument, while creating / suppressing undo boundaries as above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With