vimtricks.wiki Concise Vim tricks, one at a time.

How do I run a macro a dynamically computed number of times or interleave it with other commands?

Answer

:for i in range(1,10) | execute "normal @q" | endfor

Explanation

Using a Vimscript :for loop with execute "normal @q" lets you run a macro with a dynamically computed iteration count and interleave other Ex commands between invocations. Unlike 10@q, the count can be any Vimscript expression, and you can branch or act on each iteration.

How it works

  • :for i in range(1, N) iterates N times (Vimscript range() is exclusive of the stop value, so range(1,11) gives 1–10)
  • execute "normal @q" runs macro @q as if typed in normal mode
  • Multiple commands are separated by | on a single Ex command line
  • execute "normal! @q" (with !) uses no remapping, which can matter inside complex macros

Example

Apply macro @q once for every line in the file:

:for i in range(1, line('$')) | execute "normal @q" | endfor

Apply @q only on even-numbered iterations:

:for i in range(1, 20)
:  if i % 2 == 0 | execute "normal @q" | endif
:endfor

Run @q and advance 5 lines between each invocation:

:for i in range(1, 10) | execute "normal @q5j" | endfor

Tips

  • The standard {count}@q is simpler for fixed counts, but it stops entirely if any iteration errors; the :for approach lets you add error handling with :try/:catch
  • Combine with :g/pattern/execute "normal @q" to apply the macro only on matching lines
  • Use i (the loop variable) inside execute to build commands that vary per iteration: execute "normal " . i . "@q"

Next

How do I search for and highlight text that exceeds a specific column width like 80 or 120?