Created
February 21, 2026 10:11
-
-
Save Konfekt/cdee7ff70fe4da538ef4df65779a5e4c to your computer and use it in GitHub Desktop.
Set &findfunc to git-ls-files inside repo and fall back rg, ugrep or fd 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
| " Purpose: Fast file finding via 'findfunc', with caching and git-aware file listing. | |
| augroup vimrcFind | |
| 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. | |
| if has('win32') | |
| let s:nullerr = (&shell =~? '\v(pwsh|powershell)') ? ' 2>$null' : ' 2> nul' | |
| else | |
| let s:nullerr = ' 2> /dev/null' | |
| endif | |
| " 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 | |
| " Default file listing command used by the findfunc cache. | |
| if !exists('g:findcmd') | |
| let s:fd = executable('fd') ? 'fd' : (executable('fdfind') ? 'fdfind' : '') | |
| if !empty(s:fd) | |
| " Note: --path-separator required for Unix emulation environments on Windows, | |
| " like Cygwin or Mingw-w64, where the path separator may default to \, but Vim | |
| " thinks it's running under Unix and then wouldn't find the path for editing | |
| let g:findcmd = | |
| \ s:fd | |
| \ .. ' --type=file --path-separator=/ --hidden --follow' | |
| \ .. ' --exclude=.git --exclude=tags --ignore-file=' .. shellescape(s:ignorefile) | |
| \ .. ' --strip-cwd-prefix --color=never ""' | |
| elseif executable('rg') | |
| let g:findcmd = | |
| \ 'rg --files --path-separator=/ --hidden --follow --no-messages' | |
| \ .. ' --ignore-file=' .. shellescape(s:ignorefile) | |
| \ .. ' --no-ignore --color=never --glob=!.git --glob=!tags' | |
| elseif has('win32') | |
| let s:pwsh = executable('pwsh') ? 'pwsh' : (executable('powershell') ? 'powershell' : '') | |
| if !empty(s:pwsh) | |
| let g:findcmd = | |
| \ s:pwsh | |
| \ .. ' -NoProfile -Command' | |
| \ .. ' "Get-ChildItem . -Name -File -Recurse -Force' | |
| \ .. ' | Where-Object { $_ -NotLike ''*\.git\*'' -and $_ -NotLike ''.git\*'' -and $_ -NotLike ''tags'' }"' | |
| else | |
| let g:findcmd = '' | |
| endif | |
| elseif has('unix') | |
| let g:findcmd = 'find -L . -type f -not -path "*/.git/*" -not -name tags -print' | |
| else | |
| let g:findcmd = '' | |
| endif | |
| endif | |
| " Enable :find fuzzy completion via 'findfunc' when available. | |
| if has('patch-9.1.0810') | |
| let s:filescache = [] | |
| " See :help findfunc and :help matchfuzzy(). | |
| function! s:Find(arg, _) abort | |
| try | |
| if empty(s:filescache) | |
| if empty(get(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:nullerr) | |
| if has('win32') && g:findcmd =~? '^\s*\%(pwsh\|powershell\)\>' | |
| call map(s:filescache, 'trim(v:val)') | |
| endif | |
| endif | |
| " Clear cache after entering a buffer, since file list can be huge. | |
| autocmd vimrcFind BufEnter * ++once let s:filescache = [] | |
| endif | |
| if empty(a:arg) | return s:filescache | endif | |
| let l:max = max([0, &lines - &cmdheight - 1]) | |
| if l:max == 0 | return [] | endif | |
| return slice(matchfuzzy(s:filescache, a:arg), 0, l:max - 1) | |
| catch /^Vim:Interrupt/ | |
| return [] | |
| endtry | |
| endfunction | |
| autocmd vimrcFind CmdlineEnter : let s:filescache = [] | |
| set findfunc=<SID>Find | |
| endif | |
| " Prefer git ls-files inside a repo. | |
| if has('patch-9.1.0810') && executable('git') | |
| function! s:OutsideRepo() abort | |
| if exists('*FugitiveGitDir') | |
| return empty(FugitiveGitDir()) | |
| endif | |
| let l:_ = system('git rev-parse --is-inside-work-tree' .. s:nullerr) | |
| return v:shell_error != 0 | |
| endfunction | |
| let s:findcmd_default = get(g:, 'findcmd', '') | |
| let s:git_ls = 'git ls-files --exclude-from=' .. shellescape(s:ignorefile) .. ' --exclude-standard --cached --others' | |
| function! s:SetFindCmd() abort | |
| let g:findcmd = s:OutsideRepo() ? s:findcmd_default : s:git_ls | |
| endfunction | |
| autocmd vimrcFind VimEnter,DirChanged * call <SID>SetFindCmd() | |
| endif | |
| " Auto-pick the first match on leaving :find if none selected. | |
| if has('patch-9.1.1329') | |
| autocmd vimrcFind 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 | | |
| \ endif | |
| endif | |
| " Trigger completion automatically for :find once typing starts. | |
| if has('patch-9.0.1576') | |
| augroup vimrcWildTriggerFind | |
| autocmd! | |
| augroup END | |
| autocmd vimrcFind CmdlineChanged : | |
| \ if getcmdline() =~# '\v^\s*fin%[d]\s\S' && !exists('s:wildtrigger_active') | | |
| \ call <SID>EnableWildTrigger() | | |
| \ endif | |
| function! s:EnableWildTrigger() abort | |
| let s:wildmode_saved = &wildmode | |
| set wildmode=noselect,full | |
| autocmd vimrcWildTriggerFind CmdlineChanged : call wildtrigger() | |
| let s:wildtrigger_active = 1 | |
| autocmd vimrcWildTriggerFind CmdlineLeavePre : ++once | |
| \ unlet! s:wildtrigger_active | | |
| \ let &wildmode = s:wildmode_saved | | |
| \ autocmd! vimrcWildTriggerFind CmdlineChanged : | |
| endfunction | |
| endif |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also https://gist.github.com/Konfekt/d6bf2941abd810768992368b4f069fb3 for &grepprg