Using Macro Counters in Emacs

Today I want to discuss counters, a useful feature of keyboard macros in Emacs. They are simple in concept and usage. Personally I find them useful anytime I need to enumerate a list, such as when writing documents like these blog posts, and when I am programming.

Our Use Case

Our example in this article will be simple. We want to take this string of names

Leonardo Raphael Donatello Michelangelo

and turn it into this list:

1. Leonardo
2. Raphael
3. Donatello
4. Michelangelo

It would not take that much time to do manually. But by using counters we can create a macro that will automatically enumerate the list for us.

One Solution

Assuming the cursor (i.e. ‘point’ in Emacs terminology) is at the beginning of the string, these are the keys we press:

  1. C-x C-k C-c: Many macro-related key sequences in Emacs begin with C-x C-k. A mnemonic to help you remember this is that the names for the functions bound to those keys begin with the letter ‘k’. For example, C-x C-k C-c is bound to kmacro-set-counter. As the name implies, this command lets us set the initial value for the counter. By default the counter begins at zero; this can be useful in programming, but unless you’re Edsger Dijkstra you probably want to begin many lists with the number one. So we begin by pressing C-x C-k C-c, which will cause Emacs to prompt us for the value.

  2. Note well that we set the initial counter value before we define the macro. If we assigned the counter value as part of the macro then it would reset each time, which is rarely what we want. So now we begin defining the macro by pressing <F3>. Or if you prefer, C-x (.

  3. The first thing we want to do is insert the current value of the counter to enumerate the current item. We can pressing <F3> again to do this, or C-x C-k C-i (kmacro-insert-counter). Both will insert the counter value, our initial value of one, and then increment the counter by one. So the next time we execute the macro it will insert a two, then three, and so on.

  4. Finally we press . M-f <RET> <F4> to insert a period and space, move the point over the name, insert a newline, and then end the macro definition. Or instead of <F4> you can use C-x ) to end the macro; note the mnemonic relation to C-x (.

Now we can keep pressing <F4> (or C-x e to) execute the macro for each name.

Formatting Strings

In the previous example we manually typed the period and space after each insertion of the macro counter. We could tell Emacs to do this for us by setting the formatting string for the counter. It would not make much difference above, but it is something that I personally find useful when programming. Let’s consider the following code:

#define FOO 0
#define BAR 1
#define BAZ 2

We want to turn it into this:

#define FOO 0x0000
#define BAR 0x0002
#define BAZ 0x0004

In this example we not only change the format to hexadecimal, but we also change the values of the numbers themselves. This takes advantage of Emacs’ ability to let us only define a formatting string for the counter and to increment the counter by a value different than the default of one. These are the keys I pressed to perform these changes.

  1. First I used C-x C-k C-c to reset the counter to zero. That is the default value, but personally I think it is a good habit to always begin by setting the initial value.

  2. Then I pressed C-x C-k C-f (kmacro-set-format). This will prompt you for a formatting string, i.e. anything acceptable to format for displaying numbers. Emacs will use that format whenever you insert the macro counter. In my case I typed in 0x%04x. This format string means ‘a hexadecimal number of four digits, beginning with 0x and padded with zeros if necessary’, and I urge you to read that link to the manual to understand why, as the syntax is not complicated.

  3. Then I began defining the macro. As with the first example I prepared the initial counter value, and this time the formatting string, before defining the macro itself. I pressed C-x ( to begin the definition and then typed this: C-e <backspace> C-x C-k C-i. That sequence moves to the end of the line (C-e), backspaces over the existing number, and inserts the current value of the counter (C-x C-k C-i) using the format string. The format means Emacs inserted the string 0x0000 for the counter value of zero.

  4. When I pressed C-x C-k C-i to insert the counter that also incremented the counter value by one. However, I wanted to increment each number by two. So next I pressed C-x C-k C-a (kmacro-add-counter). This prompted for a value to add to the current counter value, and so I entered a one, which bumped it up to two when you include the initial increment from when I inserted the counter in the first place.

  5. Then I moved down to the next line and ended the macro definition while executing it twice for the remaining lines: C-x e followed by another e. If you end a macro definition with C-x e (kmacro-end-and-call-macro) Emacs will immediately execute the macro, and you can keep pressing e by itself to run the macro again and again as necessary.

There’s Even More

I hope those two examples demonstrate the basics of what you can do with keyboard macro counters. Now if you read the manual you will see that Emacs provides even more functionality, such as number registers, which you can use with macros. But personally I rarely find myself using those features. Often all I need to do is enumerate a list, possibly performing some formatting and/or incrementing by more than one each time, and the examples above cover those situations and hopefully provide an adequate explanation of how you can use counters in your own Emacs macros.


3 thoughts on “Using Macro Counters in Emacs

Add Your Thoughts

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s