Vim 101: A Gentle Introduction to Macros

You're working hard, and it's been a long day. You glance at the clock: 13:59. Is it still that early? Rushing to finish the latest bug fix, you accidentally hit some keys, then Vim displays an ominous message:

recording

Recording? Recording what?! Can I keep working or do I need to restart Vim? How do I make this thing go away!

I can understand some trepidation towards Vim's macro system, and a lot of people on IRC have asked me about it over the years. I stumbled with it a bit at first as well, back in the early days when I was struggling to install Red Hat 5.2 on my PC at university.

The road to macro mastery begins with a simple step: if you see a word in Vim, it's probably documented somewhere, so type :help recording to see what this status message means.

q{0-9a-zA-Z"}   Record typed characters into register {0-9a-zA-Z"}
                (uppercase to append).  The 'q' command is disabled
                while executing a register, and it doesn't work inside
                a mapping and :normal.  {Vi: no recording}

q               Stops recording.  (Implementation note: The 'q' that
                stops recording is not stored in the register, unless
                it was the result of a mapping)  {Vi: no recording}

So, pressing q again in Normal mode will stop recording. The next time you see recording, you'll know you've just started recording a macro and this can be stopped by pressing q again. No need to quit Vim or bug me on IRC!

Recording Macros

The documentation above mentions registers. Read Vim 101: Registers for more on this subject. A register that stores a macro contains all of the editing operations performed during recording, and the resulting value can actually be viewed and edited. The exact key presses are recorded, including Normal mode motion commands and Visual selections.

Most people use the register q to record macros, because it's easy to double tap the q key to start recording and then store in q. The pattern is as follows:

  1. Press qq to start recording and save the macro to register q
  2. Enter some commands
  3. Press q to stop recording

When I first thought about macros in editors, I imagined they'd be recorded using some kind of binary format that represents the exact motions of the keyboard and mouse, but Vim keeps things extremely simple and flexible. Typing :reg q will show the macro exactly as it was typed -- it's as simple as that!

Playing Back a Macro

To use the macro you've just recorded, type @q. This actually executes the contents of the register, so technically it's not a special macro command. It just happens that executing a register is an elegant solution to implementing macros.

This command accepts a numerical argument, so typing 3@q will execute the q register three times. Since macros can include pretty much anything, I often find myself using / to search for the next occurrence of the pattern I want to operate on, so the macro can be run multiple times without having to type additional navigation operations.

Typing @@ will repeat the last @, so once it's been executed successfully it can be repeated as needed. This is a good way of ensuring operations are being performed as expected.

Example

Let's say we're working with a programming language where function calls can omit brackets. Our house style is to omit brackets, but a new developer has left them in:

fun1(a)
fun2(a, b)
fun3(a, b, c)

In reality this would be mixed with lots of code, and potentially code that should use brackets. To safely automate this mundane editing task we can use macros.

  1. Type qq to start recording a new macro to the register q
  2. Press 0 to move to the start of the line, then f( to move to the bracket, r to replace it with a space, f) to move to the closing bracket, and x to delete it
  3. Type q to end recording
  4. Now move to a line where brackets have been used and type @q to replace them

The macro could actually contain a search to move to a line with the incorrect style.

This example could also be performed with a regular expression, but in cases where it's hard to express edits with a regular expression then macros are indispensable.

blog comments powered by Disqus