romain.bardou.fr - blog RSS

Emacs Macros And Multiple Cursors

There is an underlying idea in my previous articles: if you have to repeat some actions often, automate the process. Previous articles focused on long-term improvements though. Is it worth it to automate a task that you will only use a few times and then never again? It is, but only if the process of automating is very cheap. This is where macros shine; or, the almost magical multiple-cursor alternative.

Macros

Emacs Macros allow you to repeat a given sequence of commands easily. It's like programming a sequence of actions, except that instead of typing code, you actually perform the actions. The sequence is recorded and you can then replay it any number of times.

For instance, in a previous article I showed how I bound a key to the following sequence: "go to end of line, delete the end of line character, delete extra space, go back to initial point". There is no decision-making involved. One can obtain a macro which behaves similarly like this:

The important key bindinds to remember are C-x (, C-x ) and C-x E. The rest is just an example.

Compared to a function, this is much easier to set up. However, this is also more limited. As far as I know: you lose the macro if you start recording another one; you can only record sequences and not include decision points or loops; and in the above example, it's not easy to "go back to initial point" so I don't do it. You can save a macro as a function, however the resulting code is rather messy.

This means that macros are well-suited to a specific task: repeating a sequence of actions that you are going to perform right away.

Fruits Using A Macro

Let's transform the following code:

Orange Apple Banana Kiwi

into:

print_endline "Orange -> ORANGE";
print_endline "Apple -> APPLE";
print_endline "Banana -> BANANA";
print_endline "Kiwi -> KIWI";

First, place the cursor on the "O" of "Orange". Then, perform the following keystrokes:

Note that in some modes which automatically indent, the Delete may not be necessary. Also, this Delete will also happen after the last fruit (Kiwi) even though there is no space; this will delete the end of line character instead. If that is a problem, just add a space after Kiwi before running the macro on it.

Tips For Emacs Macros

In the fruit example, fruits don't always have the same size. This is why we used C-Left instead of just Left Left Left Left Left Left, which would work for Orange and Banana but not for Apple and Kiwi. This kind of mistake is very easy to make with macros (much less with multiple-cursors, see below).

But C-Left usually stops at characters like hyphens (-) or underscores (_). I could not find a fruit with a hyphen in its name, so I will invent one: what if I want to apply the fruit macro to a fruit named Kiwi-berry? Luckily C-M-Left, which has a larger notion of "word", would usually work in this case. The difference between C-Left and C-M-Left depends on the current mode, so you just have to try.

Often you will want to apply a macro on several lines, one time per line. For instance, we could have put each fruit on a single line before recording our macro. It is a good habit to end the macro with Right (or Down Home) to go to the beginning of the next line, so that repeating the macro with C-x E E E actually works. Otherwise we would have to type C-x E Right C-x E Right C-x E Right to fix the cursor position between each application of the macro.

It is ofen useful to set up the text in a certain way before recording and executing a macro. For instance, if a fruit has a space in its name, like Stone fruit, we can't use C-S-Right nor C-M-S-Right to select it. If it was on its own line though, we could select it using C-S-End. I call this "preparing" for the macro.

In the Stone fruit example, even if it is on one line we can't use M-u to set the whole fruit to uppercase; it would result in STONE fruit and the cursor would be between STONE and fruit, which would break the next commands of the macro. There are several tricks to fix this:

It is usually a good idea to not record very long macros. There is often something which goes wrong in the middle. Instead, split it into several macros.

Note that C-s (search) works inside macros. If you make a macro to turn our sequence of print_endlines into the origin fruit list, you can use C-s to search for ", then C-Space to start selecting, then C-s searching for -> to select the fruit name independently of its length.

Multiple-Cursors

Multiple-Cursors is an extension for Emacs which allows to have several cursors. Each keystroke is applied to all cursors at the same time (except for a configurable set of commands, such as saving the current file). This is not a new functionality, other editors have it as well.

It is basically a way to have visible macros: you record a macro and at the same time you apply it to all cursors. This allows to notice and fix mistakes much quicker, especially when a sequence of commands works for the first item but not for some of the next ones.

The drawback is that it is not very convenient if the cursors do not fit in the current view of the buffer, i.e. if the text spans across several pages. Also, C-s (search) is not supported. Other than that, all the above tips for macros also apply to multiple-cursors.

The readme is very well written and I urge you to give it a try.