Tell Vim what external command to use for grepping
set grepprg=ag\ --vimgrep
This is not strictly necessary for what we are trying to do but it's a cheap and non-negligible upgrade to the built-in
Perform the search in a sub-shell
function! Grep(args) let args = split(a:args, ' ') return system(join([&grepprg, shellescape(args), len(args) > 1 ? join(args[1:-1], ' ') : ''], ' ')) endfunction
We could simply use
:grep, with the appropriate
grepprg, but the present solution has a huge advantage: the external command is not executed in the current shell so we don't have to put up with annoying screen flashes and
<CR>s. The implementation of
:getexpris also simpler than
:grep's so it is considerably faster.
Create a command to populate the quickfix list (and another one for the location list) with the output of the function above
command! -nargs=+ -complete=file_in_path -bar Grep cgetexpr Grep(<q-args>) command! -nargs=+ -complete=file_in_path -bar LGrep lgetexpr Grep(<q-args>)
Open the location/quickfix window automatically if there are valid entries in the list
We define a self-clearing group so that our autocommands don't needlessly pile up if we re-
augroup quickfix autocmd! " our autocommands here augroup END
We add two autocommands:
- one to execute
- another one to execute
:cwindowopens the quickfix window if there are valid entries in the quickfix list and
:lwindowdoes the same for the location wlist and the location window.
We need both if we don't want to lose the flexibility of the original commands we are trying to replace.
augroup quickfix autocmd! autocmd QuickFixCmdPost cgetexpr cwindow autocmd QuickFixCmdPost lgetexpr lwindow augroup END
Note that this snippet can be easily generalized to cover every quickfix command.
- one to execute
|set grepprg=ag\ --vimgrep|
|let args = split(a:args, ' ')|
|return system(join([&grepprg, shellescape(args), len(args) > 1 ? join(args[1:-1], ' ') : ''], ' '))|
|command! -nargs=+ -complete=file_in_path -bar Grep cgetexpr Grep(<q-args>)|
|command! -nargs=+ -complete=file_in_path -bar LGrep lgetexpr Grep(<q-args>)|
|autocmd QuickFixCmdPost cgetexpr cwindow|
|autocmd QuickFixCmdPost lgetexpr lwindow|
This is amazing, thank you! The
Very nice version of the quickfix list. I use a much simpler version, as I often grep for multiple words. The code looks like this:
My understanding of vimscript is not that great, so what is it you gain by having a more convoluted command and not being able to grep for more than one word. What am I missing?
I rarely grep for multiple words but I often grep in specific files. The command as it is satisfies that specific need but I should look for a more generic solution.
FWIW I use the following which makes multiple words and files (including
function! Grep(args) let args = split(a:args) if len(args) > 1 && !empty(glob(args[-1])) let cmdline = shellescape(join(args[0:-2])) . ' ' . expand(args[-1]) else let cmdline = shellescape(a:args) endif return system(&grepprg . ' ' . cmdline) endfunction