Monday, April 27, 2009

Vim Update Many Files

Here's a really nice Vim trick I learned today and have already used twice.

I'll demonstrate it with an example. I wanted to go through all my .cs files and fix the formatting (they all had 4 spaces per tab and I wanted to update them to 2 spaces per tab).

First, I opened Vim and set the current directory to the root of my source folder.
:cd C:\blah\blah\source\code

Next, I told Vim to pull in all my .cs projects in the entire source tree.
:args .\**\*.cs

** means to go recursively down 30 directories (you can set the max depth, default is 30. Try :help ** for more).
Finally, I told it I wanted it to format each file, from beginning to end, using the "equalsprg" and then to save it.
:argdo exe "normal gg=G" | w

To break this down:
  • :argdo tells it to run the specified command on all "args", or all open files
  • exe tells it to execute the given command
  • normal runs the :normal command, which allows you to execute normal mode commands like motions, etc
  • gg goes to the top of the file, = formats the file, G goes to the end of the file
  • | chains commands together
  • w writes the file
Pretty awesome I thought.

Another common use of :argdo is to run a search and replace across many files. Open the files you want either with the :args command or from the command line. Then do:
:argdo %s/matchon/replacewith/ge | w

If this would require you to open a ridiculous number of files, most of which wouldn't have matches, then you should use the :vimgrep command instead. This will put only files that match your regex on the quickfix list. You can then move through them with :cnext and execute any commands you want. The downside here is that you have to execute your command over and over in each file.