vim, git, aws and other three-letter words

Software Development Notes

Vim: better ways to handle macros

The @ command

The @ command is better known as a command to execute macros. But it is more generic, and it can execute Vim commands from any Vim register.

Here is what the help says:

@ @{0-9a-z".=*+} Execute the contents of register {0-9a-z".=*+} [count] times. Note that register '%' (name of the current file) and '#' (name of the alternate file) cannot be used.

And a good quote about what @ can do from the Stack Overflow post:

The @ command is probably the most obscure vi command.

@ executes the contents of a register as if it were a vi or ex command.

Example: I often use: :r!locate … to find some file on my system and read its name into my document. From there I delete any extraneous hits, leaving only the full path to the file I'm interested in.

Rather than laboriously Tab-ing through each component of the path (or worse, if I happen to be stuck on a machine without Tab completion support in its copy of vi) I just use:

  • 0i:r (to turn the current line into a valid :r command), it becomes something like :r /path/to/file
  • "cdd (to delete the line into the "c" register) and
  • @c execute that command.

So we execute the :r /path/to/file command with @c and the file content is inserted into the current buffer.

It is interesting that instead of using the file name completion in the minibuffer, we build the file name in the regular Vim buffer and then use that file name to read the file content.

:r!locate *.org

Manage macros in a regular buffer

In practice, it allows using the regular Vim buffer to edit and execute commands. The command buffer : is limited and less convenient, so instead you can prepare the command in one buffer and run it in another (or prepare, delete to the register and run in the same buffer).

For example: do "cdd or "cyy on the line below and then @c to add // to all lines.

:% norm I//

This also means that instead of recording a macro, you can type it out and then execute it. Or you can record it, paste and edit it, then execute it.

For example:

  • qa - start recording into register a
  • q - stop recording
  • "ap - paste the macro, edit it
  • "ayy - yank it back into register a
  • @a - execute

The contents of the register can also be inserted with Ctrl-R [a-z] in insert mode (Ctrl-R a in the example above).

The norm command

Note that the :norm command is often a good alternative to macros (or the more recent Neovim multicursors).

For example, as shown above, the :% norm I// command adds // at the beginning of each line and :% norm A! appends ! to each line.

Combined with globals (:g and :v), this becomes a fast and flexible way to apply similar edits in the file.

Using globals with norm

For example, :g/^For/norm A! adds ! at the end of each line that starts with For:

  • :g - the global command
  • /^For/ - find all lines that start (the ^ in Vim is the start of the line) with For
  • norm A! - execute A! on matching lines
    • A means "append": it starts insert mode at the end of the line
    • ! inserts the "!"

Similarly, :v can be used to apply commands to lines that do not match the pattern. For example, :v/^For/norm A! adds ! at the end of each line that does not start with For.

Tags: vim