DEV Community

Cover image for Unleash the power of Vim Macros in 4 minutes

Unleash the power of Vim Macros in 4 minutes

Omer Hamerman
Originally published at ・4 min read

In my first Vim post I had a long discussion with one of the readers over macros. He just couldn't get his head around the idea. As I was doing my best to explain, I realized that specific examples don't always go all the way in demonstrating an idea.

This post will cover the what's and the why's as well as the practical way of doing things, but thanks to my fellow reader, it would also try to illustrate use-cases and situations; the how.


Vim's documentation calls this "Recording", which essentially is exactly what it does. Vim records a set of commands into a register, and then allows their execution and manipulation. A recorded macro can be executed once, or as many times as requested by prefixing it with the number of repetitions. It can be combined with other recorded macros by assigning multiple macros in a certain order into a new macro of its own. A macro can be read, edited, and written as well since it's just a representation of characters saved into a register in the memory.


Macro recordings are a powerful tool to have under your belt as a Vim user. Developers tend to stumble upon repetitive work quite frequently. Knowing "how to handle" such repetitiveness is not only time saving but also enjoyable as you perfect your process. As a side effect, being able to "beat" the challenge keeps you in your flow of work and doesn't throw you into the occasional frustration that is usually part of doing something over and over fifty times.
You'll be thankful the next time each line starting with a | would require another | after the third space (a real scenario batteling markdown tables);


98% of all Vim macros ever recorded (I totally made the number up) required two steps: recording and execution. The rest involved actually reading the sequence and even changing it, let's follow them by descending order of importance:


A recording is started with q followed by a register. The most common and closest register is obviously "q" itself so, qq will start recording into register q, and Vim will show the mode recording @q.
Here's an example of recording the sequence required to complete the task in the paragraph above (each line starting with a | would require another | after the third space):

qqf nna| <ESC>q
Enter fullscreen mode Exit fullscreen mode

Let's review each of 11 moves:

  1. q - record
  2. q - save the recording into register "q"
  3. f - find
  4. - space (followed by "find", space being the target)
  5. n - go to the next result
  6. n - go to next result (again, since we're going for the third space)
  7. a - start inserting after the current cursor location
  8. | - insert a pipe
  9. - insert a space
  10. <ESC> - back to normal mode
  11. q - stop recording

We now have a sequence of operations ready to be executed on the next line starting with |. The last 5 words imply there's a more efficient way in regard to the number of keystrokes required. Let's create a sequence that would be able to repeat itself, meaning, it should end where the next execution should start. One way to do that is this:

/^|qqf nna| <ESC>nq
Enter fullscreen mode Exit fullscreen mode

The additions here are a prefix of /^| which means: search (/) for all lines starting (^) with |, and a suffix of n just before the end of recording (q) meaning "jump to the next search result". The record now doesn't require any extra keystrokes in between executions other than the Vim "repeat" command (which we'll get to know in the next section), or providing a number of required repetitions to the execution command.


Execution of a recorded sequence is done with @ followed by the target register; @q would execute the contents of register "q". @@ is a shortcut, as it reads the last register's contents (2nd @) and runs it (1st @). Another useful combination is Vim's repetition command ., which comes in handy when executing a sequence, then moving to another location where it's required (assuming there was no better option of recording), then using . saves a keystroke and replaces the @<register>.


As with any register, contents are available with :reg (or :reg q in the specific example), and can be pasted from with "qp ("paste from register q").


After reading and pasting, the sequence can be manipulated in any way, and the sequence which is essentially a string of characters, can be saved back into the register for further use with: "q followed by where the text is.


Macros can be combined or "concatenated": if a certain sequence is recorded into register q and another to w, one may want to read them both, maybe concatenate the strings and resave them to one register so they can be run together. A better and quicker solution would be to start recording a new macro to a new register e as an example, and then simply execute both sequences in the desired order: "e@q@w - "record into register e, the sequence in register q followed by the one in register w".


The simple answer to when should anyone use a macro, is either when you can't find a better alternative e.g. a regex-based search and replace, a normal search (/) and repeat (.) combination, OR when it's the quicker way, as simple as that. Vim's concept of "least keystrokes to result" is something to live by and remember; the least amount of effort put into a given result the better. Better flow, better focus and overall satisfaction of the user, because at the end of the day that's what Vim is all about: productivity.

Thank you for reading this far!
My name is Omer, and I am an engineer at ProdOps — a global consultancy that delivers software in a Reliable, Secure and Simple way by adopting the DevOps culture. Let me know your thoughts in the comments below, or connect with me directly on Twitter @omergsr. Clap if you liked it, it helps me focus my future writings.

Discussion (0)