32

One thing I often do (but rely on the command line to do) is searching/grepping in multiple files.

Is there a way to display search results for all the open buffers?

Ideally, I'd like to have a new split buffer containing result location and snippet much like grep does. For example (/statistics):

models/statistics.php: /*! \file   statistics.php
controllers/stats.php: $this->load->model('statistics');
controllers/stats.php: // Query statistics...
controllers/stats.php: $num_exams = $this->statistics->countExams();

As a bonus, I'd like to be able to search for the term under the cursor, pretty much like gd does.

1

4 Answers 4

25

You can use :vimgrep /pattern/ {files} to populate the quickfix list with matching patterns. The problem is that :vimgrep files option doesn't directly allow for buffers. You can use:

%   Is replaced with the current file name.       *:_%* *c_%*
#   Is replaced with the alternate file name.     *:_#* *c_#*
#n  (where n is a number) is replaced with        *:_#0* *:_#n*
    the file name of buffer n.  "#0" is the same as "#".     *c_#n*
##  Is replaced with all names in the argument list   *:_##* *c_##*
    concatenated, separated by spaces.  Each space in a name
    is preceded with a backslash.
#<n (where n is a number > 0) is replaced with old    *:_#<* *c_#<*
    file name n.  See |:oldfiles| or |v:oldfiles| to get the
    number.                         *E809*
    {only when compiled with the |+eval| and |+viminfo| features}

Another option is to write a script that generates a file list from :buffers. Per this SO post with a slight tweek we get:

function! BuffersList()
  let all = range(0, bufnr('$'))
  let res = []
  for b in all
    if buflisted(b)
      call add(res, bufname(b))
    endif
  endfor
  return res
endfunction

function! GrepBuffers (expression)
  exec 'vimgrep/'.a:expression.'/ '.join(BuffersList())
endfunction

command! -nargs=+ GrepBufs call GrepBuffers(<q-args>)

You can now call :GrepBufs <expression> and get the standard :vimgrep output but using the buffers instead.

Update If you would like to call GrepBuffers using the value under the cursor add this new mapping.

nnoremap <leader>z :call GrepBuffers("<C-R><C-W>")<CR>

When you are in normal mode type <leader>z and you'll :vimgrep the cursor word over your open buffers.

1
  • 2
    In single line form: command! -bang -nargs=+ Bufgrep execute 'vimgrep<bang><args> ' . join(map(filter(range(1, bufnr('$')), 'buflisted(v:val)'), '"#".v:val'), ' '). Usage: :Bufgrep/foo/ Commented Apr 17, 2015 at 16:33
13

Searching in only opened buffers is nice, but there may come a time where you want to search across an entire project. It can be faster and easier than you think!

Searching across a project

  • grep is the Unix standard search tool. Worth mentioning due to its ubiquity. Already integrated into Vim via :grep command. e.g. :grep -r 'foo'. See :h :grep.
  • Ack is faster than regular grep because it skips VCS directories, binary files, and can search for specific type of filetypes like --perl. For Vim integration see Ack.vim
  • Ag the Silver Surfer is a code-searching tool similar to ack, but faster. Vim plugin: Ag.vim
  • git grep searches a repository very quickly. Fugitive.vim provides :Ggrep.
  • Ripgrep is even faster than Ag and git grep. Can be used with :grep as well.

I recommend both ripgrep, Ag, and git grep as they are all super fast. I have searched over 4700+ in less than a 1 second. It's pretty hard to beat ripgrep.

To test out one of these alternatives without a plugin or you simply don't want a plugin you can set your 'grepprg' option accordingly. e.g. set grepprg=ag\ --vimgrep or set grepprg=rg\ --vimgrep. See :h 'grepprg' and :h 'grepformat' for more information. Now you can search via :grep. e.g. :grep 'foo'.

As a final fallback you can use :vimgrep as it is available on all systems that Vim is available. See :h :vimg for more help.

QuickFix List

As most of these options use the quickfix list I suggest you use some more friendly mappings to transverse the quickfix list. I use Tim Pope's unimpaired plugin which uses ]q and [q for :cnext and :cprev respectively. Some people like the quickfix to open after a search is performed then add the following to your ~/.vimrc file: autocmd QuickFixCmdPost *grep* cwindow. You can also manually open the QuickFix list via :copen.

Want even faster "searches"?

You are going to need to use some tool that uses a prebuilt indexes like ctags, cscope, or GNU global.

  • Vim has built in ctag support via :tag, <c-]>, and many other commands and options. See :h tags. Also may want to read Effortless Ctags with Git or look into the Gutentags plugin
  • Cscope support is also built in and can be used via :cscope command. See :h cscope

More help

I would start with this nice Vimcast episode: Search multiple files with :vimgrep.

For more Vim help see the documentation:

:h grep
:h :vimgrep
:h :grep
:h 'grepprg'
:h 'grepformat'
:h quickfix
:h :cnext
:h tags
:h cscope
10

Commands :bufdo and :vimgrepadd

This answer is based on https://stackoverflow.com/a/11976158/1057593.

However, I wanted add a few bits. Again the basic command is

:bufdo vimgrepadd pattern %

If your quickfix list is not empty, you probably want to clear it first. This can be done with :cexpr

:cexpr []

Mappings to cycle through matches

vim-unimpaired provides the mappings ]q and [q to cycle through the matches.

Workflow with the command line history

It is a convenient workflow to enter the search pattern separately with /pattern. This allows you to use a generic command from your command line history using the current search pattern. This would look like

/pattern
:bufdo vimgrepadd // %

A typical new buffer wide search would be

/pattern2
:bufdo<up><up>...

I have added following mappings to my vimrc to use <C-N> and <C-P> instead of the arrow keys to stay with my hands on the home row

cmap <C-P> <Up>
cmap <C-N> <Down>

Note searching the command line history q: with /bufdo<CR> interferes with using the current search pattern. You could use :keepp /bufdo<cr>.

For more details on the command line history see the help pages :h history and :h cmdline-window and https://vim.fandom.com/wiki/Using_command-line_history.

You can add to the reusable command :copen to immediately see the quickfix list in the following way:

:execute "bufdo vimgrepadd // %" | copen

The proposal from stackoverflow :bufdo vimgrepadd // % | copen opened several unintended windows in my case.

And with :cexpr [] the reusable command would become

:execute "cexpr [] | bufdo vimgrepadd // %" | copen
7

My GrepCommands plugin defines variants of the built-in :vimgrep command which target all arguments, listed buffers, windows in the current tab page or all tab pages for its search. Basically, a robust plugin implementation of @jecxjo's answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.