Learn Vim at your own pace with my self-study Core Vim Course.

Learn more

Learn Vim at your own pace with my self-study Core Vim Course.

Project-wide find and replace

#45

Run time:

Vim doesn’t have a built-in command for project-wide find and replace operations, but we can perform this task by combining primitive Ex commands such as :substitute, :argdo, and :vimgrep. We’ll look at two possible strategies: first using the arglist, then the quickfix list.

Shownotes

In the video, I find all occurrences of Vimcasts.com and change them to Vimcasts.org. I show two different ways of doing it. This builds on material that was introduced in episodes 41, 42, 43, and 44.

Strategy #1 - run :substitute across all project files

The first strategy is to populate the arglist with all of the files in the project, then run the substitute command against them all:

:args *.txt
:argdo %s/Vimcasts\.\zscom/org/ge
:argdo update

This may mean that the substutite command runs in buffers that don’t contain a match.

Strategy #2 - run :substitute across project files that contain a match

The second strategy breaks the substitute command into two steps: find all matches, then run the substitute command only in those buffers that contain a match. Here are the steps:

:args *.txt
:vimgrep /Vimcasts\.\zscom/g ##
:Qargs
:argdo %s/Vimcasts\.\zscom/org/ge
:argdo update

This uses a custom :Qargs command to prune the arglist of buffers that don’t contain a match.

The :Qargs helper command

The custom :Qargs command sets the arglist to contain each of the files referenced by the quickfix list. You add it to Vim by copying these lines into your vimrc file:

command! -nargs=0 -bar Qargs execute 'args' QuickfixFilenames()
function! QuickfixFilenames()
  " Building a hash ensures we get each buffer only once
  let buffer_numbers = {}
  for quickfix_item in getqflist()
    let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
  endfor
  return join(map(values(buffer_numbers), 'fnameescape(v:val)'))
endfunction

Or you could install the vim-qargs plugin from github. Credit where due: I adapted this code from a Stack Overflow solution posted by Dr Al.

Proposal: :cdo

Vim needs a :cdo {cmd} command. It would behave like the :argdo and :bufdo commands, except that it would iterate through the quickfix list. The :cdo {cmd} command would work as follows:

:cfirst
:{cmd}
:cnfile
:{cmd}
etc.

If such a command existed, then we could refine Strategy #2, removing the :Qargs step:

:args *.txt
:vimgrep /Vimcasts\.\zscom/g ##
:cdo %s/Vimcasts\.\zscom/org/ge
:cdo update

UPDATE on June 2nd, 2013, Yegappan submitted a patch to add native :cdo and :ldo commands to Vim’s core.

:cdo implementations in the wild

Henrik Nye created a :Qdo command in his fork of my Qargs plugin. This takes the slightly dirty approach of populating the arglist from the contents of the quickfix list, then using the built-in :argdo command to iterate over the resulting arglist. Of course, this has the side-effect that it changes the contents of the arglist. That’s tolerable, but not ideal. Henrik has written up how to use :Qdo for project wide search and replace.

Peter Jaros created vim-cdo, which includes :Cdo as well as :Ldo for operating on the location list. Peter’s plugin differs slightly from the formula I described above, because it effectively uses :cnext instead of :cnfile.

Further reading

Comments

Level-up your Vim

Training

Boost your productivity with a Vim training class. Join a public class, or book a private session for your team.

Drew hosted a private Vim session for the shopify team that was one of the best workshops I have ever attended.

John Duff, Director of Engineering at Shopify

Publications

Make yourself a faster and more efficient developer with the help of these publications, including Practical Vim (Pragmatic Bookshelf 2012), which has over 50 five-star reviews on Amazon.

After reading it, I've switched to vim as my default editor on a daily basis with no regrets. ★★★★★

Javier Collado

Learn to use Vim efficiently in your Ruby projects

In association with thoughtbot, one of the most well respected Rails consultancies in the world, I've produced a series of screencasts on how to make navigating your Ruby projects with Vim ultra-efficient. Along the way, you’ll also learn how to make Ruby blocks a first-class text object in Vim. This lets you edit Ruby code at a higher level of abstraction. Available to buy from thoughtbot..