How do I search for a pattern across multiple files and navigate the results?
Answer
:vimgrep /pattern/ **/*.ext | copen
Explanation
The :vimgrep command searches for a regex pattern across multiple files and populates the quickfix list with every match. Combined with :copen, you get an interactive results window that lets you jump between matches across your entire project — all without leaving Vim.
How it works
:vimgrep /pattern/ **/*.extrecursively searches all files matching the glob for the given pattern**means recursive descent into subdirectories*.extis a file glob — use**/*.py,**/*.js,**/*etc.| copenchains the quickfix window open immediately after the search completes- Each entry in the quickfix list shows the file, line number, and matching text
Example
Find every TODO comment in your JavaScript project:
:vimgrep /TODO/ **/*.js | copen
The quickfix window opens at the bottom:
src/app.js|12| // TODO: add error handling
src/utils.js|45| // TODO: refactor this function
tests/helper.js|8| // TODO: add more test cases
Press <CR> on any line to jump to that match. Use :cnext and :cprev to step through results without returning to the quickfix window.
Tips
- Use
:cn(:cnext) and:cp(:cprev) to step forward and backward through results :cfirstand:clastjump to the first and last match- Use
:cdo s/old/new/g | updateto run a substitution on every matched line across all files - Use
:cfdo %s/old/new/g | updateto run the substitution on every matched file instead - Add
jto suppress the automatic jump to the first match::vimgrep /pattern/j **/*.py - For faster searches on large codebases, use
:grepwith an external tool likerg(ripgrep)::set grepprg=rg\ --vimgrepthen:grep pattern - The quickfix list persists until replaced — use
:colderand:cnewerto navigate between previous quickfix lists - Use
:lvimgrepfor a per-window location list instead of the global quickfix list