Last active
April 2, 2026 20:18
-
-
Save Konfekt/d6bf2941abd810768992368b4f069fb3 to your computer and use it in GitHub Desktop.
Set &grepprg to git-grep inside repo and fall back rg, ugrep or grep outside of it
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| " Set &grepprg to rg, ugrep, git grep or grep otherwise. | |
| " Assumes a global ignore file `$XDG_CONFIG_HOME/grep/ignore`; create it by, | |
| " say `touch ~/.config/grep/ignore` to ensure its existence. | |
| augroup vimrcGrep | |
| autocmd! | |
| augroup END | |
| " Scheduling niceness on Linux. | |
| let s:scheduler = (has('unix') && executable('chrt') && executable('ionice')) | |
| \ ? 'chrt --idle 0 ionice -c2 -n7 ' | |
| \ : '' | |
| " stderr to null, respecting common Windows shells. | |
| let s:nullerr = has('win32') | |
| \ ? ((&shell =~? '\v(pwsh|powershell)') ? ' 2>$null' : ' 2> nul') | |
| \ : ' 2> /dev/null' | |
| " let s:xdg_config = !empty($XDG_CONFIG_HOME) ? expand($XDG_CONFIG_HOME) : expand('~/.config') | |
| " let s:ignorefile = s:xdg_config .. '/grep/ignore' | |
| let s:ignorefile = expand($XDG_CONFIG_HOME) .. '/grep/ignore' | |
| if !filereadable(s:ignorefile) | |
| call mkdir(fnamemodify(s:ignorefile, ':h'), 'p') | |
| call writefile(['.git', 'tags', '!tags/'], s:ignorefile) | |
| endif | |
| let s:case_flag = &ignorecase | |
| \ ? (&smartcase ? '--smart-case' : '--ignore-case') | |
| \ : '--case-sensitive' | |
| setglobal grepformat=%f:%l:%c:%m,%f:%l:%m | |
| if executable('rg') | |
| let &g:grepprg = s:scheduler | |
| \ .. 'rg --multiline --follow --no-heading' | |
| \ .. ' --ignore-file=' .. shellescape(s:ignorefile) | |
| \ .. ' --with-filename --line-number --column' | |
| \ .. ' ' .. s:case_flag | |
| \ .. ' --color=never $*' | |
| \ .. s:nullerr | |
| elseif executable('ugrep') | |
| " From https://github.com/Genivia/ugrep#using-ugrep-within-vim | |
| let &g:grepprg = s:scheduler | |
| \ .. 'ugrep -R -n --ignore-binary --ungroup --tabs=1' | |
| \ .. ' --ignore-files=' .. shellescape(s:ignorefile) | |
| \ .. ' --column-number' | |
| \ .. ' ' .. s:case_flag | |
| \ .. ' --color=never --no-messages -- $*' | |
| \ .. s:nullerr | |
| setglobal grepformat=%f:%l:%c:%m,%f+%l+%c+%m,%-G%f\\\|%l\\\|%c\\\|%m | |
| elseif executable('git') | |
| let cmd = (&ignorecase && &smartcase && executable('git-grep')) | |
| \ ? 'git-grep' | |
| \ : (&ignorecase ? 'git grep --ignore-case' : 'git grep') | |
| let &g:grepprg = s:scheduler | |
| \ .. cmd | |
| \ .. ' --no-index --no-recurse-submodules--exclude-standard --column --line-number -I --untracked --extended-regexp --no-color $*' | |
| \ .. s:nullerr | |
| elseif executable('grep') | |
| let &g:grepprg = s:scheduler | |
| \ .. 'grep -rnHIsE ' .. (&ignorecase ? '-i ' : '') | |
| \ .. '$* --exclude=tags --exclude-dir=.git' | |
| \ .. s:nullerr | |
| endif | |
| " Vimgrep completion and jump to selected match. | |
| if has('patch-9.1.1329') | |
| let s:selected = '' | |
| function! s:BuildGrepCmd(args) abort | |
| if empty(a:args) | |
| return '' | |
| endif | |
| let args = shellescape(escape(a:args, '\')) | |
| return (&grepprg =~# '\$\*') ? substitute(&grepprg, '\$\*', args, '') : (&grepprg .. ' ' .. args) | |
| endfunction | |
| function! s:CompleteLiveGrep(arglead, cmdline, cursorpos) abort | |
| let args = trim(matchstr(strpart(a:cmdline, 0, a:cursorpos), '\v^\s*Vimgrep\s+\zs.*$')) | |
| if strlen(args) < 2 | |
| return [] | |
| endif | |
| let cmd = s:BuildGrepCmd(args) | |
| if empty(cmd) | |
| return [] | |
| endif | |
| let out = systemlist(cmd) | |
| let l:max = &lines - &cmdheight - 1 | |
| return l:max > 0 ? out[: l:max - 1] : [] | |
| endfunction | |
| function! s:VisitFile() abort | |
| let item = getqflist(#{lines: [s:selected]}).items[0] | |
| execute 'buffer' item.bufnr | |
| call setpos('.', [0, item.lnum, item.col, 0]) | |
| call setbufvar(item.bufnr, '&buflisted', 1) | |
| endfunction | |
| function! s:CaptureLiveGrepSelection() abort | |
| let info = cmdcomplete_info() | |
| if empty(get(info, 'matches', [])) || getcmdline() !~# '^\s*Vimgrep\s' | |
| return | |
| endif | |
| let s:selected = info.matches[info.selected >= 0 ? info.selected : 0] | |
| call setcmdline(info.cmdline_orig) | |
| endfunction | |
| function! s:Vimgrep(args) abort | |
| if !empty(s:selected) | |
| call s:VisitFile() | |
| return | |
| endif | |
| let cmd = s:BuildGrepCmd(a:args) | |
| if empty(cmd) | |
| return | |
| endif | |
| let out = systemlist(cmd) | |
| if !empty(out) | |
| let s:selected = out[0] | |
| call s:VisitFile() | |
| endif | |
| endfunction | |
| command! -nargs=+ -complete=customlist,<SID>CompleteLiveGrep Vimgrep call <SID>Vimgrep(<q-args>) | |
| nnoremap q<space> :<c-u>Vimgrep<space> | |
| autocmd vimrcGrep CmdlineEnter : let s:selected = '' | |
| " Store selected completion item on leaving the command-line and restore the typed command. | |
| autocmd vimrcGrep CmdlineLeavePre : call <SID>CaptureLiveGrepSelection() | |
| " Trigger completion automatically for :Vimgrep once typing starts. | |
| if has('patch-9.0.1576') | |
| augroup vimrcWildTriggerGrep | |
| autocmd! | |
| augroup END | |
| function! s:DisableWildTrigger() abort | |
| unlet! s:wildtrigger_active | |
| let &wildmode = s:wildmode_saved | |
| augroup vimrcWildTriggerGrep | |
| autocmd! | |
| augroup END | |
| endfunction | |
| function! s:EnableWildTrigger() abort | |
| let s:wildmode_saved = &wildmode | |
| set wildmode=noselect,full | |
| let s:wildtrigger_active = 1 | |
| augroup vimrcWildTriggerGrep | |
| autocmd! | |
| autocmd CmdlineChanged : call wildtrigger() | |
| autocmd CmdlineLeavePre : ++once call <SID>DisableWildTrigger() | |
| augroup END | |
| endfunction | |
| autocmd vimrcGrep CmdlineChanged : | |
| \ if getcmdline() =~# '\v^\s*Vimgrep\s\S' && !exists('s:wildtrigger_active') | | |
| \ call <SID>EnableWildTrigger() | | |
| \ endif | |
| endif | |
| endif |
Author
Author
See this perl script gist for smart-case capable git-grep
Author
See also https://gist.github.com/Konfekt/cdee7ff70fe4da538ef4df65779a5e4c for &findfunc
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also https://gist.github.com/andlrc/c8e1a3b9c1ec5c761111ea0e49bda6c4