Streamlining Vim's :grep

by Noah Frederick |

Vim’s most straightforward method of global search is its :grep command, which invokes 'grepprg' (often grep or a drop-in replacement such as ag). It’s awkward that Vim dumps the output of 'grepprg' and prompts the user to return to editing by pressing Enter. It’s possible to eliminate that extraneous and disorienting step without creating a custom command by using a command-line-mode abbreviation:

cnoreabbrev <expr> grep  (getcmdtype() ==# ':' && getcmdline() =~# '^grep')  ? 'silent grep'  : 'grep'
cnoreabbrev <expr> lgrep (getcmdtype() ==# ':' && getcmdline() =~# '^lgrep') ? 'silent lgrep' : 'lgrep'

The first line breaks down like so:

  • cnoreabbrev — Define a non-recursive command-line abbreviation
  • <expr> — Interpret the right-hand side of the abbreviation as an expression instead of literally
  • grep — The string to expand
  • getcmdtype() ==# ':' — Is the context the command line (as opposed to a / or ? search)?
  • getcmdline() =~# '^grep' — Does the content of the command line begin with “grep”?
  • ? 'silent grep' — If so, expand “grep” to “silent grep”…
  • : 'grep' — …else expand “grep” to itself (i.e., do nothing)

And the second line does the same, but for :lgrep, of course.

Now, when you run :grep/:lgrep, you won’t get any visual feedback. That can be improved by automatically showing the quickfix or location list window:

augroup init_quickfix
  autocmd QuickFixCmdPost [^l]* cwindow
  autocmd QuickFixCmdPost l* lwindow
augroup END

The QuickFixCmdPost autocommand matches its pattern against the command run, so the first one will open the quickfix list window for commands not beginning with l such as :grep, and the second will open the location list window for commands beginning with l such as :lgrep.

Further Reading