October 17, 2016 by Alex Korling
Leveraging Emacs macros to make powerful changes to your code
Today I want to talk a little about a really nice feature in Emacs.
That feature is keyboard macros. The work by recording your actions on
the keyboard and then replaying those actions. These macros can then be
C-u to run the following command, in this case the
just recorded macro, num number of times.
The most recent task I used macros for is while extending some functionality
in Erlang. I needed to add a lot of function clauses for a set of some fifteen
new patterns, and use those to translate, from the pattern to a one value, and vice versa.
There was already functionality for this. All I had to do was to replicate
the two functions for all the new patterns.
Lets say that we start out with the following list of defined items.
-define(THING_ONE, 1). -define(THING_TWO, 2). -define(THING_THREE, 3). -define(THING_FOUR, 4). -define(THING_FIVE, 5). -define(THING_SIX, 6). -define(THING_SEVEN, 7). -define(THING_EIGHT, 8). -define(THING_NINE, 9). -define(THING_TEN, 10). -define(THING_ELEVEN, 11). -define(THING_TWELVE, 12).
I then needed to transform that into the following form:
to_value(?THING_ONE) -> 1111; to_value(?THING_TWO) -> 2222; ... to_value(?THING_TWELVE) -> 1212.
As well as this format:
to_macro(1111) -> ?THING_ONE; to_macro(2222) -> ?THING_TWO; ... to_macro(1212) -> ?THING_TWELVE.
This is really straight forward by combining rectangles and keyboard
First use put your cursor right after the first
-define( and then press
C-x SPC to enable rectangle mode. Mark all of the definitions so that your
selection looks like this:
THING_ONE, 1 THING_TWO, 2 THING_THREE, THING_FOUR, THING_FIVE, THING_SIX, 6 THING_SEVEN, THING_EIGHT, THING_NINE, THING_TEN, 1 THING_ELEVEN THING_TWELVE
Copy the region with
M-w and paste it where you want to define your
To get rid of the trailing commas and numbers you select the region again and run
M-x replace-regex with
,.* as your pattern. Voila! You now have a pristine region to work with.
Do a rectangle select on the first column of the values and then use
M-x string-insert-rectangle to insert
to_value(? at the start of all the lines.
You rectangle select again to mark the last column in your partial function
definition. Now do the same
M-x string-insert-rectangle and insert
) -> ;.
Now you need to do some manual work to insert all the values for the function and you’re done with the first function.
Now for the exciting part where we leverage keyboard macros.
Copy the whole
to_value function and paste it. Create a region for it and
M-x % to replace
to_macro(?THING_ONE ) -> 1111; to_macro(?THING_TWO ) -> 2222; ... to_macro(?THING_TWELVE) -> 1212.
To get rid of all the extra white space we’ll mark the entire function and do
M-x replace-regexp with the pattern
\b\s-*) and replace it with
Now we’ll record a macro:
- Start with your cursor on the first row. Press
C-x (to start to record the macro.
C-sand search to the first
?press back arrow so that the cursor is on top of the
?. Then we press
C-SPCto create a region for the parameter by using
C-sagain to search to the first
). Remember to use back arrow again to get the selection just right.
C-wto kill/cut it.
C-sto search for
>, and press right arrow. Paste item we just cut by using
- Create a region and press
C-eto select to the end of the line. Press left arrow to deselect the semi-colon. Cut the region with
C-rto search backward and search for
)press RET and
C-yto paste. Now press down,
C-a, and stop recording with
C-x ). Now we can use
C-x eto execute our macro. Did you notice that it did the exact same thing that you did and ended up with the cursor on the third function clause? Now we can replace the rest by using
C-u 10 C-x e. Emacs will execute the macro another ten times.