Vim, cfdo, Ale and RipGrep

January 25, 2018

Twice a year I have to do a project wide find and replace, and this involves remembering what :argsdo is, wait, no, it’s something else, god what is it - then trying to crawl through the evolution of project find-and-replace in vim on StackOverflow until I finally arrive at :cdo.

This time I have learned it once and for all. The most common work flow is:

:Rg/Ag/Ack <search-term>
:cdo %s/match/pattern/ge | update

This will populate all results into a quickfix window, then iterate over each line matched, run the %subsitute command, globally (all matches), and suppress any errors. It will then pipe an update (:w) once it has completed.

An improvement over :cdo is using :cfdo which acts on the file, not the line, this is beneficial if you are changing multiple matches in the same file.

:Rg/Ag/Ack <search-term>
:cfdo %s/match/pattern/ge | update


I highly recommend using ale, but it comes with a caveat if you wish to use it alongside :cfdo and friends. As discussed in the issue I filed, you cannot have ale populate the quick fix window if you are using :xdo. The easiest way to make this work is with these settings:

let g:ale_set_loclist = 1
let g:ale_set_quickfix = 0

If you are married to using quick fix, there are two workarounds.

:cfdo %s/match/replace/ge | noau update
:cfdo %s/match/replace/ge

[1] - Disabling autocmd has potential side effects that are esoteric to each individual’s .vimrc.

[2] - This introduces another “command” that breaks the one-liner wonderfulness. Though, anecdotally, I have noticed this method can execute significantly faster than piping update.


While investigating this issue I stumbled across ripgrep - an insanely fast improvement of ack/the silver searcher, developed in Rust.

I cannot understate how amazingly fast this is. Although out of the box it works just fine, you may find the syntactical sugar provided by vim-ripgrep to be worth the install.

« return home