2010/07/30

Advanced Vim: Recording & Editing Macros

Recording and Playing Macros

Macros are incredibly useful, as they allow you to automate certain annoying repetitive tasks. Let's jump right in.

You record macros by giving the qx command in normal (command) mode. Instead of x, you can pick any lowercase letter, so you can also give the command qb (record macro to register b) or qq (record macro to register q). This lower case letter identifies the register in which the macro will be recorded. If you record a macro in register b, you can play that macro by typing @b.

Enough of this boring talk, let's see an example I frequently use. Suppose you have some code that looks like this:

somefunction(paramA, paramB, paramC, paramD, paramE)
The parameters for this function have grown in size, maybe the line even exceeds 80 columns and you'd like each of the parameters to be on their own line. What I'd do is this (don't literally type [ENTER] or [ESC] but press the [ENTER] or [ESC] key).

qc                   Record the macro in register c
  f,                 Place the cursor right on the next comma
    a[ENTER]         Insert After the current character and press ENTER
            [ESC]q   Leave insert mode and stop recording	    
Place the cursor somewhere on the line you want to affect, before the first comma and press 4@c. This will execute the macro in register c four times. If you did everything correct this should give you something like

somefunction(paramA,
               paramB,
               paramC,
               paramD,
               paramE)
If either your Vim build doesn't support any auto indentation or there just isn't any for the current filetype, all of new lines will be misaligned and you will have to reindent manually (you can of course press TAB while recording macros, so repeatedly pressing tab after you hit [ENTER] while recording the macro would solve this problem but wouldn't work for lines of code that are indented either more or less). The macro will stay in register c until you either close your session or overwrite register c.

Editing recorded macros

Finally I can get to the advanced (and actually moderately interesting) part of this post. You probably know that one of the other places Vim uses registers is in it's clipboard management. If you want to yank (copy) a word into register a you give the "ayw (be sure to note the first character is actually a "! The double quote character at the start of a command tells Vim the next character will be a register.) command. To yank a line into register p, give the "pyy command. If you want to paste the contents of register a, you can do that by giving the "ap command.

Now here's the real kicker: the registers for copy paste and the registers for macros are the same registers! Think about that for a minute.

Back to our example, what if you suddenly realize you need to put a backslash at the end of every line (after every comma) so the compiler will know to look at the next line for the rest of this statement. You could re-record the entire macro, but if the macro was longer this wouldn't be too practical. The preferred course of action is to paste your macro right into the text you're writing, edit it and yank it back into its register.

We once again have the line

somefunction(paramA, paramB, paramC, paramD, paramE)
First, paste your macro by typing "cp (remember how we stored our macro in register c?). This will give you

f,a^M^[
The ^M is another way of writing the [ENTER] we pressed and ^[ is another way of writing [ESC]. We'd like to type a \ just before every newline (so right before ^M in our macro). So change the text we just pasted from register c to

f,a \^M^[
and put it back in register c by putting your cursor on the first character of the macro and typing "cy$ (yank everything to the end of the line into register c). Once again position yourself before the first comma and press 4@c

somefunction(paramA, \
                 paramB, \
                 paramC, \
                 paramD, \
                 paramE)
Perfect!

No comments:

Post a Comment