16

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.

15

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
    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/ – Peter Rincker Apr 17 '15 at 16:33
7

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
6

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, privacy policy and cookie policy

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