Unleash the power of Vim Macros in 5 minutes

January 27, 2020
Contact Us
Weekly Shorts are topics we discuss in our weekly remote meeting related to recent work we have done with our customers
Unleash the power of Vim Macros in 5 minutes

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.

What

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.

Why

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);

How

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:

Recording

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

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

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.

Executing

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>.

Reading

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").

Changing

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.

Combining

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".

When

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. Tweet me your thoughts  to @omergsr.

Unleash the power of Vim Macros in 5 minutes
Omer Hamerman
Senior Software Operations Architect
Omer is an experienced software operations engineer and open source contributor. He is always willing to go the extra mile to help our clients improve their software delivery. Omer gets the job done quickly, and is clear-cut and sharp throughout, delivering almost any job on the spot. When he’s not helping our clients achieve scalable and resilient infrastructure, you’ll find him rock climbing and bouldering. He is passionate about beautiful code, cybersecurity and doing things right the first time. He is a keen writer of blog posts and a speaker at meetups.