---
title: Vim Macros and You
teaser:
tags: vim
author: Josh Clayton
published_on: 2012-01-06
---

Ever get the urge to update a ton of files? I know I do. For example, I recently
changed multiple hundred coffeescript files from the syntax of

    MyGreatClass = Backbone.Model.extend(
      defaults:
        awesome: true
    )

to

    class @MyGreatClass extends Backbone.Model
      defaults:
        awesome: true

How long did it take me? A couple of minutes. Here's how.

## Ack (or Grep)

I like [ack](http://betterthangrep.com/). To find all the files I need to edit,
I'd write something like this:

    ack '^[^\s].*\=.*\.extend\($' app/assets/javascripts -l

This finds everything that doesn't start with a space, has an equals sign, and
has `.extend(` at the end of the line.

## Opening a list of files in vim

After looking over the results of ack and ensuring that everything that matched
is what I want to edit, I'll open those files in vim.

    vim $(ack '^[^\s].*\=.*\.extend\($' app/assets/javascripts -l)

## Vim Macros

If you've been using vim and haven't taken advantage of macros (especially if
you're editing a lot of files in a similar fashion), you're missing out. Open up
vim and type `:help q` to get the nitty-gritty; I'll summarize here.

To start recording a macro, press (in normal mode) q and then a letter or
number. This will record a macro to whatever register you chose (via the letter
or number).

Once you're recording a macro, anything you type will be recorded to that macro
so that it can be replayed. What I would type to change these files to the new
format would be:

    qqgg0iclass @<esc>f=cwextends<esc>2f.DGdd:wnq

Whoa, brain overload. Let's break it down:

    qq             # records the macro to the q buffer
    gg             # first line in file
    0              # first character in line
    iclass @<esc>  # inserts class @ at the cursor and returns to normal mode
    f=             # finds the first equal after the cursor
    cwextends<esc> # changes the word (=) and moves to insert mode, adds extends, and returns to normal mode
    2f.            # finds the second period after the cursor
    D              # deletes the remainder of the line
    G              # moves to the end of the file
    dd             # deletes the line
    :wn            # writes the file and moves to the next file in the list
    q              # stops recording

This should be fairly straightforward; the only thing I really want to point out
is the `:wn`. The `n` in that command moves to the next file in the list of
files you opened with vim. This is one half of what makes editing all these
files really fast.

## Replaying a Macro

Now that you have your macro, it's time to replay it. To replay a macro, press
(in normal mode) `@q` (assuming you stored your macro into the `q` register). If
you were to run that macro, it'll run it against the current file, write the
file, and move to the next. Since vim supports prefixing many commands with a
number (for the number of times to repeat the command), running `100@q` will run
that macro on the first one hundred open files that I've opened with vim.
Typically, this should be all you need to batch-edit, but if there are more
files, just run that command again (or start with a higher number). If there are
no more files to edit, vim will let you know.

Ben also mentioned recursive macros (my mind was blown) by adding `@q` right
before the last q (which will run the `q` macro before stopping recording). Just
make sure your q register is empty! This would allow you to run your macro once,
without specifying the number of times to run it, because vim will run the macro
until it's out of files. Fancy!

## Vim for fun and profit

Want to kick ass at vim? Pick up a copy of [Vim for Rails
Developers](https://workshops.thoughtbot.com/vim) and become blazing-fast! If
you want to hang out with fellow vim users to swap awesome tips like this, be
sure to head to the [Boston Vim
Meetup](http://www.meetup.com/The-Boston-Vim-Meetup/)!
