Skip to content

Instantly share code, notes, and snippets.

@Konfekt
Last active September 27, 2025 19:26
Show Gist options
  • Save Konfekt/d6bf2941abd810768992368b4f069fb3 to your computer and use it in GitHub Desktop.
Save Konfekt/d6bf2941abd810768992368b4f069fb3 to your computer and use it in GitHub Desktop.
Set &grepprg / &findfunc to git-grep / git-ls-files inside repo and fall back rg, ugrep or grep / fd, ... outside of it
" Set &grepprg to git-grep inside repo, fall back rg, ugrep 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 vimrcFindGrep
autocmd!
augroup END
if has('unix') && executable('chrt') && executable('ionice')
let s:scheduler = 'chrt --idle 0 ionice -c2 -n7 '
" " hard getting escaping right
" elseif has('win32')
" let s:scheduler = (&shell =~? '\v(^|\\)cmd\.exe$' ? '' : 'cmd.exe ') .. 'start /B /LOW '
else
let s:scheduler = ''
endif
let s:nul = ' 2> ' .. (has('win32') ? 'nul' : '/dev/null')
let s:smartcase = &ignorecase && &smartcase ? '--smart-case' : (&ignorecase ? '--ignore-case' : '--case-sensitive')
set grepformat=%f:%l:%c:%m,%f:%l:%m
if executable('rg')
let &g:grepprg = s:scheduler .. 'rg --multiline --follow --no-heading --ignore-file=' .. expand('$XDG_CONFIG_HOME/grep/ignore') .. ' --with-filename --line-number --column ' .. s:smartcase .. ' --color never $*' .. s:nul
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=' .. expand('$XDG_CONFIG_HOME/grep/ignore') .. ' --column-number ' .. s:smartcase .. ' --color=never --no-messages -- $*' .. s:nul
setglobal grepformat=%f:%l:%c:%m,%f+%l+%c+%m,%-G%f\\\|%l\\\|%c\\\|%m
elseif executable('grep')
let &g:grepprg = s:scheduler .. 'grep -rnHIsE $* --exclude=tags --exclude-dir=.git' .. s:nul
endif
if has('patch-9.1.0810') " = if exists('&findfunc')
if executable('fd')
let g:findcmd = 'fd --type file --full-path --ignore-file='..expand('$XDG_CONFIG_HOME/grep/ignore')..' --color never '..(has('win32') ? '--fixed-strings ' : '')..' ""'
elseif executable('rg')
let g:findcmd = 'rg --files --hidden --ignore-file='..expand('$XDG_CONFIG_HOME/grep/ignore')..' --no-ignore --color never --glob ""'
elseif executable('ugrep')
let g:findcmd = 'ugrep -Rl -I --ignore-files='..expand('$XDG_CONFIG_HOME/grep/ignore')..' --color=never -3 ""'
else
let g:findcmd = ''
" if has('win32')
" let g:findcmd = 'dir . /s/b/a:-d-h'
" elseif has('unix')
" let g:findcmd = 'find . -path "*/.git" -prune -o -type f -print'
" endif
endif
" See :help live-grep
func Find(arg, _)
if empty(s:filescache)
if empty(g:findcmd)
let s:filescache = globpath('.', '**', 1, 1)
call filter(s:filescache, '!isdirectory(v:val)')
call map(s:filescache, "fnamemodify(v:val, ':.')")
else
let s:filescache = systemlist(s:scheduler .. g:findcmd .. s:nul)
endif
endif
return empty(a:arg) ? s:filescache : matchfuzzy(s:filescache, a:arg)
endfunc
autocmd vimrcFindGrep CmdlineEnter : let s:filescache = []
set findfunc=Find
endif
if executable('git')
function! s:outside_repo()
if exists('*FugitiveGitDir')
return empty(FugitiveGitDir())
else
" let outside_repo = empty(finddir('.git', getcwd().';')) && empty(findfile('.git', getcwd().';'))
silent let repo = system('git rev-parse --is-inside-work-tree' .. s:nul .. ' 1>&2')
return v:shell_error != 0
endif
endfunction
let s:grepprg = &g:grepprg
let s:grepformat = &g:grepformat
let s:git_grep = &ignorecase && &smartcase && executable('git-grep') ?
\ 'git-grep' : (&ignorecase ? 'git grep --ignore-case' : 'git grep')
let s:git_grep = s:scheduler .. s:git_grep .. ' --exclude-standard --column --line-number -I --untracked --extended-regexp --no-color $*' .. s:nul
function! s:SetGrepPrg()
if s:outside_repo()
let &g:grepformat= s:grepformat
let &g:grepprg = s:grepprg
else
setglobal grepformat=%f:%l:%c:%m
let &g:grepprg = s:git_grep
endif
endfunction
autocmd vimrcFindGrep VimEnter,DirChanged * call <SID>SetGrepPrg()
if has('patch-9.1.0810') " = if exists('&findfunc')
let s:findcmd = g:findcmd
let s:git_ls = s:scheduler .. 'git ls-files . --exclude-from=' .. expand('$XDG_CONFIG_HOME/grep/ignore') .. ' --exclude-standard --cached --others' .. s:nul
function! s:SetFindCmd()
let g:findcmd = s:outside_repo() ? s:findcmd : s:git_ls
endfunction
autocmd vimrcFindGrep VimEnter,DirChanged * call <SID>SetFindCmd()
endif
endif
if has('patch-9.1.1329') " = if exists('##CmdlineLeavePre')
" See :help live-grep
" Consider an Alias such as :Alias l LiveGrep
command! -nargs=+ -complete=customlist,<SID>Grep LiveGrep call <SID>VisitFile()
func s:Grep(arglead, cmdline, cursorpos)
if match(&grepprg, '\$\*') == -1 | let &grepprg .= ' $*' | endif
let cmd = substitute(&grepprg, '\$\*', shellescape(escape(a:arglead, '\')), '')
return len(a:arglead) > 1 ? systemlist(cmd) : []
endfunc
func s:VisitFile()
let item = getqflist(#{lines: [s:selected]}).items[0]
let pos = '[0,\ item.lnum,\ item.col,\ 0]'
exe $':b +call\ setpos(".",\ {pos}) {item.bufnr}'
call setbufvar(item.bufnr, '&buflisted', 1)
endfunc
" Automatically select the first item in the completion list when leaving the
" command-line, and for `:Grep`, add the typed pattern to the command-line history:
autocmd vimrcFindGrep CmdlineLeavePre :
\ if get(cmdcomplete_info(), 'matches', []) != [] |
\ let s:info = cmdcomplete_info() |
\ if getcmdline() =~ '^\s*fin\%[d]\s' && s:info.selected == -1 |
\ call setcmdline($'find {s:info.matches[0]}') |
\ endif |
\ if getcmdline() =~# '^\s*LiveGrep\s' |
\ let s:selected = s:info.selected != -1
\ ? s:info.matches[s:info.selected] : s:info.matches[0] |
\ call setcmdline(s:info.cmdline_orig) |
\ endif |
\ endif
" autocomplete matches for :find and :LiveGrep
if has('patch-9.0.1576') " = if exists('*wildtrigger')
augroup vimrcWildTrigger
autocmd!
augroup END
autocmd vimrcFindGrep CmdlineChanged :
\ if getcmdline() =~# '\v^\s*%(fin%[d]|LiveGrep)\s\S' && !exists('s:wildtrigger') | call s:wildtrigger() | endif
function! s:wildtrigger()
let s:wildmode = &wildmode
set wildmode=noselect,full
autocmd vimrcWildTrigger CmdlineChanged : call wildtrigger()
let s:wildtrigger = 1
autocmd vimrcWildTrigger CmdlineLeavePre : ++once
\ unlet! s:wildtrigger | let &wildmode = s:wildmode |
\ autocmd! vimrcWildTrigger CmdlineChanged :
endfunction
endif
endif
@Konfekt
Copy link
Author

Konfekt commented Sep 17, 2025

@Konfekt
Copy link
Author

Konfekt commented Sep 17, 2025

See this perl script gist for smart-case capable git-grep

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment