2024-03-02 Some tips about Emacs keyboard macros

Some time ago I had to create some rather repetitive code. These days I often use multiple cursors for such things, but for some reasons this time I decided to go the traditional route and use the built-in keyboard macros. Here’s the catch, though. When you want to use keyboard macros and insert an (incremented) number for every occurrence, you can type f3 (kmacro-start-macro-or-insert-counter) while recording the macro. What I needed, though, was to insert that number twice for every execution of the macro. Typing f3 twice is no good, since every press of it increments the counter. Without giving it much thought, I tried to press C-u f3 during recording of the macro, hoping that it would do what I needed – and lo and behold, it did! As usual, Emacs commands turn out to be well thought-out and intuitive to use (once you get used to the general Emacs philosophy, that is).

After this small success, I decided to go to the manual to learn what other tricks are possible with keyboard macros. I certainly read it – I did read most of the manual, after all, but that was more than two decades ago. Emacs does not stand still, and a lot of functionality has been added since then – and it keeps being added all the time. (For example, when I first learned keyboard macros, you had to use C-x ( and C-x ) to record a macro, C-x e to execute it and C-x C-k C-i to insert the counter. These are not bad bindings, but f3 and f4 are so much simpler!)

And indeed, skimming through the relevant chapter of the manual (and pressing C-x C-k C-h – it turns out that not all macro-related commands are even documented in the manual!) revealed a few gems. One of them (I knew about) is that when you replay the macro, you can give f4 a numeric argument to tell Emacs how many times it should repeat the execution of the macro. That is useful enough, but here’s a bonus: if the argument you give is zero, it runs the macro repeatedly until it encounters an error. This is especially useful if your macro makes some change and moves to the next place to be changed – Emacs movement commands usually signal an error when you try to move past the buffer end, so this is an easy way of telling Emacs to do something “in the rest of the (visible portion of the) buffer”. (Note that giving f3 a negative argument is probably not a good idea – it will repeat the macro indefinitely without any stop condition. As of writing this, it is not documented, I’m not sure if it’s even intended and I found about it the hard way;-).)

One of the coolest thing about Emacs keyboard macros, however, is that you can have more than one of them. Much like kills, they are stored on a “ring”, and when you record a new one, the older ones are pushed down the ring instead of simply forgotten. You can then rotate the ring using C-x C-k C-p and C-x C-k C-n, effectively switching to older or newer macros as the “last macro”. If you just sometimes need the second-to-last entry on the ring and never the earlier ones, you can also use C-x C-k C-t to swap the two entries on the top of the macro ring. Of course, remembering what is in the macro ring and in what order requires some superhuman abilities, but the commands which change the top entry on the macro ring show you that top entry, so it’s not really completely blind. And while there seems to be no command to view the entire macro ring, you can say M-x kmacro-view-macro to see the definition of the macro at the head of the ring and kmacro-view-ring-2nd to see the next one. You can also use the plain old C-h v kmacro-ring to see whole ring – but without the head, which is stored in last-kbd-macro. (Interestingly, C-h v last-kbd-macro is less helpful since it is displayed in a more “internal” format. I have no idea why this works this way, but as part of the experiments while writing this blog post I recorded a macro consisting of two keystrokes, M-c M-f. When it went down the ring, it was displayed – as part of the kmacro-ring variable – this way: #f(kmacro "M-c M-f"); however, when it was at the head, C-h v last-kbd-macro showed this: [134217827 134217830]. Go figure.) And here is another nugget of gold: you can use the command kmacro-view-macro-repeat, bound to C-x C-k C-v, to see the last macro, and if you repeat it more times (and you can press just C-v to do that), Emacs shows you the subsequent macros on the ring – so, to see the third one, you can just press C-x C-k C-v C-v C-v. (Needless to say, it does not change the top entry of the ring.)

What I miss (a bit) is a way to replace the head of the macro ring instead of just appending to it. It’s not a big deal, since it is easy to remove the last macro, using C-x C-k C-d, so that if you make a mistake while recording, you can use that not to pollute the macro ring with incorrect entries. Also, if you expect to need a macro in the future, you can save it in a few ways – give it a name (C-x C-k n, the name will be usable as an M-x command) or a keybinding (C-x C-k b, either as a binding of C-x C-k followed by a digit or a capital letter or any binding – read the manual for the details). You can also save a macro to a register using C-x C-k x – and then, “jumping” to that register will replay that macro. (If you don’t know about Emacs registers, they are a pretty obscure but very useful feature I like a lot.) And if you named your macro, you can open your init file (M-x find-init-file) and say M-x insert-kbd-macro so that Emacs generates Elisp code to define your macro and give it the name you have chosen in every subsequent Emacs session. This way you can extend Emacs without any knowledge of Emacs Lisp! (Of course, if you want to extend Emacs, using Elisp is probably the best thing you can do – as usual, if you want to learn it, I recommend the Introduction to programming in Emacs Lisp by the late Robert J. Chassell and also my book, Hacking your way around in Emacs, which is sort of a “sequel” to it, meaning it covers more advanced material).

Anyway, another cool thing is that if you record a long macro and then find out you’ve made some simple mistake in it, you don’t have to record it again from scratch. You can simply edit the (last) macro, using C-x C-k C-e. Try it out, it’s insanely good! And if you press C-h m while editing a macro, you’ll see a detailed description of the Edit Macro mode.

The last thing I’d like to mention is that you can record a macro which is (sort-of) interactive. I wanted to write more about it, but it turned out that I already did;-). (It is kind of ironic that I ended that post like this: “it may be good to remember that something like this exists. Hopefully I won’t forget about it anymore!”, and indeed I forgot that I wrote that!) And by the way, if you think keyboard macros would be even better with loops and conditionals, you are definitely not alone – and in Emacs Calc they actually have them!

CategoryEnglish, CategoryBlog, CategoryEmacs