Have you ever wished that Vim would report your position as you navigate through search matches? For example, by saying: ‘match 2 out of 5’.
That’s not a feature provided by Vim’s search command, but it is a feature supplied by the quickfix list. We can use the :vimgrep
command to populate the quickfix list with search results from the current file:
:vimgrep /{pattern}/ %
The %
character is a special symbol, which represents the filepath of the active buffer.
The {pattern}
field behaves more or less as you would expect. You can supply any pattern that would work with Vim’s standard search command.
Searching for the last pattern
You can search for the last pattern in your search history by running:
:vimgrep /<C-r>// %
On the command line, <C-r>/
(that is: CTRL-R
followed by /
) will insert the last search pattern.
Specifiying the set of files for vimgrep
to search
When running the vimgrep
command, we have to specify at least one file for the command to search inside. We could provide:
- one or more filepaths (separated by whitespace)
- a wildcard
- a backtick expression
- the
##
symbol, representing the arglist
The first three from this list should look familiar if you’ve watched Vimcast #42 - Populating the arglist.
The special ## symbol is expanded to represent each of the files from the arglist. It’s really handy in this context. Suppose that we wanted to search the same set of files for one pattern, then another pattern, and so on. It would be a drag to have to specify the same set of files again and again:
:vim /pattern1/ `find . -type f` :vim /pattern2/ `find . -type f` :vim /pattern3/ `find . -type f`
We can avoid this repetition by populating the arglist with the set of files we want to work with, then using the special symbol ##
(double hash) to reference the arglist:
:args `find . -type f` :vim /pattern1/ ## :vim /pattern2/ ## :vim /pattern3/ ##
Not having to think about which files you’re dealing with frees you up to focus on the more interesting part of the vimgrep
command: the pattern.
For more ideas on how to specify the set of files for vimgrep
to look inside, check out these articles on ack -f
and git ls-files
.
Navitating the quickfix list
The results from the vimgrep
command are collected in the quickfix list. We can traverse them with the following commands:
Ex command | unimpaired map | effect |
---|---|---|
:cprev[ious] |
[q |
reverse through quickfix list |
:cnext |
]q |
advance through quickfix list |
:cfirst |
[Q |
go to start of quickfix list |
:clast |
]Q |
go to end of quickfix list |
The square-bracket mappings are not built-in to Vim, but are added by Tim Pope’s unimpaired plugin (which I recommend).
Vimgrep: pros, cons, and alternatives
I reach for vimgrep
when I want to use Vim’s built-in regex engine. I love being able to test my regular expression in one buffer using the search command, then use the same pattern without modification to search across the entire project. For me, that convenience is the killer feature of vimgrep
.
On the downside, vimgrep
isn’t as quick as some of the alternatives out there. If you want to search a large codebase and get results fast, then you’d be better off using an external tool like git-grep
, ack
or the silver searcher. All of these external tools integrate with the quickfix list, and you can find Vim plugins for each of them:
- fugitive provides the
:Ggrep
command - Ack.vim provides the
:Ack
command - ag.vim provides the
:Ag
command
The downside to using these external tools it that each uses a different regex syntax from Vim’s.
Further reading
:help quickfix
:help :vimgrep
:help :_%
:help :_##
:help :substitute
:help :global
:help c_CTRL-R
:help quote/
- Practical Vim - chapter 12: Matching Patterns and Literals
- Practical Vim - chapter 16: Compile code and navigate errors with the quickfix list
- Practical Vim - chapter 17: Search project-wide with grep, vimgrep, and others
- unimpaired.vim