Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active February 7, 2024 22:56
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Integralist/8d01300efcd2006c69e8b9492c0eada8 to your computer and use it in GitHub Desktop.
Save Integralist/8d01300efcd2006c69e8b9492c0eada8 to your computer and use it in GitHub Desktop.
[vim search and replace content using native vim cdo and cfdo commands] #vim #replace #macro #quickfix

There are two 'types' to be aware of with a quickfix window:

  1. entry: the actual line content (e.g. :grep foo will show a specific line that matched within a file).
  2. file: the actual file itself (e.g. the path to the file that contained the match).

To replace content using vim (via the quickfix window) you need to choose whether you want to apply the change via the quickfix 'entry' or via the 'file' as a whole.

If you use cdo, then your 'action' (i.e. how you're going to replace content) will be applied to every entry in the quickfix window.

If you use cfdo, then your action will be applied to each file in the quickfix window.

tl;dr

Using cdo is more straight forward, but cfdo is probably more efficient/performant.

Difference?

To understand the difference, let's consider an example scenario:

We have quickfix window that has two files:

  1. example1.txt
  2. example2.txt

The file example1.txt shows up multiple times, while example2.txt only shows up once.

The file example1.txt shows up multiple times because we searched for a phrase such as foo and that phrase happened to appear multiple times within example1.txt, while it only appeared once within example2.txt.

If you wanted to replace foo with bar using a subtitution like s/foo/bar/, and you used cdo, then all occurences of foo would be replaced because the substitution would be executed across each entry in the quickfix window. But if you used cfdo then the substitution would only be applied once to the file because you didn't use % (e.g. :%s/foo/bar/ meaning apply the substitution across the entire buffer) so only the first line of the file would have the substitution applied.

You could still use cfdo but you would need to specify %.

NOTE: I've found that my quickfix window is updated frequently/dynamically when using certain build tools (e.g. vim-go with gopls), in this case I'm better off using cfdo with %s/foo/bar/e | update which will write the buffer once, rather than the multiple times compared to cdo with s/foo/bar/e | update. It's also much more efficient using cfdo as it won't write the buffer multiple times.

Examples

To execute a substitution for every 'entry' listed in the quickfix window use cdo:

:cdo s/v2/v3/ | update

To execute a macro for every 'file' listed in the quickfix window, you would still use cdo and not cfdo! This is interesting because you might expect the macro to execute across the entire file, but remember that macros only execute once and if you need them to be executed multiple times then you need to tell them to execute across a 'range' (e.g. the entire buffer or a section of lines). So by using cdo instead it means you can rely on the macro being executed against every instance of the thing you're searching for (even if it appears multiple times within a file).

:cdo execute "norm @q" | update
@juanramirezc2
Copy link

Awesome notes 👏 Now I understand the difference between cdo and cfdo.
Thank you

@miltonkowalewski
Copy link

👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment