Vim Tips Wiki
Tip 656 Printable Monobook Previous Next

created 2004 · complexity advanced · author Mohit Kalra · version 5.7

Recursive mappings are fun to learn and really handy when you want to do repetitive tasks. One way to do this is by recording a macro, which can be done recursively. This is another way when you find that you are using the same editing pattern again and again. Recursion may seem a bit complicated at first but it is very intuitive once you get the hang of it. Here are two examples.

Suppose you have a file with the following contents:


You want to change the file as follows:

wc aaa.txt> aaa.log
echo "HelloWorld"
wc bbbbbb.txt > bbbbbb.log
echo "HelloWorld"
wc ccc.txt > ccc.log
echo "HelloWorld"

A simple recursive mapping that will do the job is:

:map z Iwc <Esc>lyawA><Esc>pa.log<CR>echo "HelloWorld"<Esc>jz

Now type z in the first line and everything else is magic.

Here is the breakup where {} contain the vim commands.

  1. Goto the beginning of the line and type "wc " and then come back to normal mode {Iwc <Esc>}
  2. Copy the word aaa (or bbbb or ccc). We do this by going right one character and copying the word under it. {lyaw}
  3. Goto the end of the line and append > and then come back to normal mode. {A><Esc>}
  4. Paste what we had copied {p}
  5. Append .log<CR>echo "HelloWorld" to the line. {a.log<CR>echo "HelloWorld"}
  6. Goto the next line but first we switch to the normal mode. {<Esc>j}
  7. Do steps 1 to 7 all overagain {z}

The recursion terminates when the j cannot take you one more line further. If you manually execute a command for one line, you will find it very intuitive to create recursive mappings.

Here is another example. Say you want to change:

#define myid 199
#define myid2 200
#define myid3 201


#define myid 201
#define myid2 202
#define myid3 203

The simple mapping would be:

:map z 2^Ajz

where ^A is CTRL_V+A

  1. Add 2 to the number in the line
  2. Go down one line.
  3. Do steps 1 to 3 again.



>How does one stop a recursion that starts with a search?

:set nowrapscan

See the "References" section above.

The terminating condition for such a recursive mapping is that the search should not find anything. If the wrapscan is on, the search starts from the top of the document again. So setting wrapscan to off makes sure that the search has a terminating condition.

I think nmap z /^\*\*\*\*\*k"Ay}3jz should be

nmap z /^\*\*\*\*\*<CR>k"Ay}3jz