Naming my macros in Emacs


I love using macros in Emacs, they help me speed up several tasks in a regular basis. Writing a macro is a relative easy thing to do and a topic for another article.

What I want to talk about today is how and why you could name a macro.

If you don't know what a macro is, the concept is simple, it's a sequence of actions that can be recorded and reused later.

We start recording a macro by hitting C-x ( and then hit C-x ) when finished. Then we can reproduce it by pressing C-x e (and just e for consecutive repetitions).

But what if we have two or more distinctive repetitive tasks that we need to perform one after the other? Recording a macro wouldn't be effective here, since we'd be overwriting it over and over and the "record once, use multiple times" effect would be lost… unless…

Naming a macro

Emacs allows us to give a name to a macro by invoking the kmacro-name-last-macro command. Then we'll be able to access it just as we access any command in Emacs (i.e. M-x).

Now we can record an action, give it a name, then record another and give it a different name and we'll have it available until the end of our Emacs session.

But… why?

Why would I record a macro and give it a name instead of writing a proper elisp command? Why would I want to lose what I recorded at the end of the session?

Well, a macro is a tool meant for impromptu tasks, tasks that are repeated, but that we won't need later (allegedly).

For example, we'd write a macro if we wanted to convert a list of groceries from a simple text format to an HTML ordered list. This requires going into each line and adding the start and end tags from the ol. This gets repetitive, but it's something you are not gonna be using in a regular basis.

My use case

But I like to go one step further. A while ago I was presented with an HTML file that contained a very nested list of attributes in an API. I wanted to convert this into a JSON object.

So I created a macro to convert a row into a key-value pair in a different buffer.

This worked for a couple of lines, but early enough I noted a second pattern: some of those rows contained a string for the key, but a separate object for the value, which made me retrace my steps and modify what needed, so I named my first macro and wrote a second one.

And soon enough I found myself writing a third one for the cases where an array was needed as a value.

I had to do this for several files on subsequent days and I found myself hitting M-x kmacro-name-last-macro repeatedly.

On steroids

So I decided to up my game and wrote a command that, after I define a macro, I can hit M-9 and it'll name the macro for me and ask me to input a character. Say I choose a, then the next time I hit H-a, my macro will be run.

Here's the command

  (defun fdx/kmacro-name-and-assign (char)
    "Name last macro and assign a key combination"
    (interactive "c")
    (let (
          (char-s (char-to-string char))
          (macro-name (concat "fdx/last-macro-" (char-to-string char)))
          (key (concat "H-" (char-to-string char)))
          )
      (kmacro-name-last-macro (intern macro-name))
      (global-set-key (kbd key) (intern  macro-name))
      (message key)))

You'd probably be asking yourself "but why marry with the Hyper key instead of asking for a keybinding" and my answer is that, if you read my article about why I use Hyper, you'll know that I'm trying to force myself to use it as sort of a wildcard in order not to override default keybindings. This is a completely personal choice, feel free to modify the code above if it's not your preferred approach.

Try it out and save yourselves a great amount of work!

Saluti.