How-to: Perform Portable Substitution Using nvim and ripgrep
Published:
Often I have to perform substitution of variables or code blocks with something
new as part of refactoring efforts. Since I am using nvim, I wanted a way to
do this without having to close nvim, but also taking advantage of highly
optimized regex search utilities like ripgrep. In this short how-to, I
provide the commands one can use to do this without ever having to close nvim.
Recently, I ran into a case where a target string I wanted to replace across a
codebase contained lots of special characters. Special characters required
painful manual escaping if I used sed.
Instead, I wanted to:
- Use
ripgrepto intelligently find matching files. - Load those files into Neovim’s argument list.
- Perform a substitution using Neovim’s built-in
%swith\V(“very nomagic”) to avoid regex escaping headaches.
The target workflow looked like this:
1
:argdo %s,\V<C-r>0,newstring,g
Where:
- The search string is yanked into the unnamed register.
\Vdisables magic pattern interpretation.argdoapplies the substitution to all files in the argument list.
The question was: how do I cleanly pipe ripgrep results into :args?
Neovim allows things like:
1
2
:args **/*.py
:args +!ls src/*.py
But I wanted to use ripgrep because it’s tailored specifically for fast
pattern matching across files in a git repository.
As an example, I was trying to replace the below string across many files:
1
"{environ['HOME']}/.cartopy_backgrounds/BlueMarble_3600x1800.png"
After some experimentation, I landed on a minimal solution that:
- Requires no
nvimconfiguration changes - Keeps everything inside
nvim - Works with any external search tool
Step 1: Start Neovim
1
$ nvim
Step 2: Use ripgrep to find matching files
Write matching filenames to a temporary file:
1
:!rg -l -F "\"{environ['HOME']}/.cartopy_backgrounds/BlueMarble_3600x1800.png\"" . --glob "*.py" > /tmp/out.txt
Explanation:
-l-> list matching files only-F-> fixed string search (no regex interpretation)--glob "*.py"-> restrict to Python files- You still have to escape the quotation marks via
\"
Step 3: Populate the argument list
1
:args `cat /tmp/out.txt`
Now all matching files are in the argument list.
Step 4: Perform the replacement
Assuming the search string is in the unnamed register (e.g. you yanked it with
y):
1
:argdo %s,\V<C-r>0,"new_text",g | update
This:
- Uses
\Vto avoid regex escaping - Replaces globally in each file
- Writes only modified files (
update)
This solution:
- Requires no plugins
- Doesn’t depend on quickfix tricks
- Doesn’t require leaving Neovim
- Lets you swap in
find,grep, or any other tool
It’s simple, explicit, and flexible.
There are likely more elegant solutions, but this approach is portable, minimal, and easy to remember.
Sometimes the most boring solution is the best one.