15

I'm using grep to find function occurrences in a project.

:grep "set_val" *

Goes out of vim and outputs:

code.py:68:        self._device.set_val('Level', new_level)
code.py:84:        self._device.set_val("Mode", "Remote")
Press ENTER or type command to continue

I press enter and am at code.py:68 which is the first occurrence.

How do I move to other occurrences?

1 Answers1

33

:grep/:vimgrep both use the quickfix list to store locations. As you have noticed vim will automatically jump to the first occurrence (use ! to avoid this behavior). Simply use :cnext to go to the next location in the quickfix list.

Quickfix commands

  • :cnext/:cprevious to navigate the quickfix forwards and backwards in the quickfix list
  • :cfirst/:clast to jump to the start and end of the quickfix list
  • Use :copen to open the quickfix window. Use <cr> to jump to an entry
  • Use :cclose to close the quickfix window
  • Use :cc to display the current error.
  • :colder/:cnewer to jump older/newer quickfix lists

I would recommend you create mappings for :cnext and :cprevious. I personally use unimpaired.vim which provides ]q & [q mappings for :cnext and :cprevious.

If you want the quickfix window to open automatically put the following in your vimrc:

augroup autoquickfix
    autocmd!
    autocmd QuickFixCmdPost [^l]* cwindow
    autocmd QuickFixCmdPost    l* lwindow
augroup END

There is a Vimcasts episode about this topic: Search multiple files with :vimgrep.

Project-wide Search and Replace

If you are using :grep/:vimgrep as way to do a project-wide search and replace then I suggest you use :cdo/:cfdo (in Vim 7.4.980+).

:grep 'foo'
:cfdo %s/foo/bar/g|w

If your version of Vim does not have :cdo/:cfdo put the following commands in your vimrc file to provide :Cdo/:Cfdo alternative commands.

if !exists(':cdo')
  command! -nargs=1 -complete=command Cdo try | sil cfirst |
        \ while 1 | exec <q-args> | sil cn | endwhile |
      \ catch /^Vim\%((\a\+)\)\=:E\%(553\|42\):/ |
      \ endtry

  command! -nargs=1 -complete=command Cfdo try | sil cfirst |
        \ while 1 | exec <q-args> | sil cnf | endwhile |
      \ catch /^Vim\%((\a\+)\)\=:E\%(553\|42\):/ |
      \ endtry
endif

Using an alternative program for :grep

Sometimes grep isn't quite good enough for your search needs. You can change your :grep program via the 'grepprg' setting (may also need to change 'grepformat' as well). Personally I use ripgrep by adding the following to my vimrc file as instructed in rg's man page:

set grepprg=rg\ --vimgrep
set grepformat^=%f:%l:%c:%m

Note: May want to use -S flag, e.g. set grepprg=rg\ -S\ --vimgrep, to use "smart case" searching (case insensitive searching when all lowercase letters).

Now :grep will use rg to search. e.g. :grep foo -t js.

Her are a few alternative grep programs to look into: ack, ag, ripgrep, and git grep (Fugitive.vim provides :Ggrep wrapper)

For more help see:

:h :grep
:h 'grepprg'
:h quickfix
:h :cnext
:h :copen
:h :ccl
:h :cc
:h :colder
:h :cdo
:h :cfdo
Peter Rincker
  • 15,854
  • 1
  • 36
  • 45
  • Thanks for the great answer. Your code for automatically opening the quickfix window works, but for me it opens and I have to then use commands to jump to it (ctr+w and down arrow). Can I add a line to automatically jump the cursor into the quickfix window after it automatically opens? Thank you. -Asaf – Asaf Jan 10 '18 at 23:04
  • Using :cwindow/:copen inside the QuickFixCmdPost autocmd event will restore the current buffer after firing. You can add :wincmd b or whatever window command you want to the autocmd, but the window will be restored. This is alluded to in :h autocmd-use. If you think about it this behavior makes sense as you might have multiple autocmd's attached to an event, all of which have certain assumptions like the current buffer. I imagine the way to force the issue would be to wrap this into your quickfix command. e.g. :command! Grep -nargs=+ grep <args> | cwindow – Peter Rincker Jan 10 '18 at 23:24