CtrlP is a popular Vim plugin for jumping to files & buffers by typing a fragment of the path or filename. Its fuzzy-find is a little too fuzzy for my taste. We can fix that with a custom match function!
Per CtrlP documentation:
Example:
let g:ctrlp_match_func = { 'match': 'Function_Name' }
Structure of the function:
function! Function_Name(items, str, limit, mmode, ispath, crfile, regex)
" Arguments:
" |
" +- a:items : The full list of items to search in.
" |
" +- a:str : The string entered by the user.
" |
" +- a:limit : The max height of the match window. Can be used to limit
" | the number of items to return.
" |
" +- a:mmode : The match mode. Can be one of these strings:
" | + "full-line": match the entire line.
" | + "filename-only": match only the filename.
" | + "first-non-tab": match until the first tab char.
" | + "until-last-tab": match until the last tab char.
" |
" +- a:ispath : Is 1 when searching in file, buffer, mru, mixed, dir, and
" | rtscript modes. Is 0 otherwise.
" |
" +- a:crfile : The file in the current window. Should be excluded from the
" | results when a:ispath == 1.
" |
" +- a:regex : In regex mode: 1 or 0.
return list_of_matched_items
endfunction
So, I’m going to replace the default fuzzy-matcher with a dumb grep
. Notice that I’m disabling regexes with the --fixed-strings
flag. First, we’ll define the function:
function! MyCtrlpMatch(lItems, szSearch, nHeight, szMode, bIsPath, szCurFile, bRegex)
" EARLY EXIT ON EMPTY SEARCH STRING
if strlen(a:szSearch) > 0
" SYSTEM `grep` SEEMS TO BE FAR FASTER THAN BUILT-INS
let szCmd = 'grep --ignore-case --fixed-strings ' . shellescape(a:szSearch)
let lRet = systemlist(szCmd, join(a:lItems, "\n"))
" CAP LARGE RESULTS TO 1K ITEMS
let nResults = len(lRet)
if nResults > 1000
return lRet[0:999]
elseif nResults > 0
return lRet
endif
endif
return []
endfunction
Now we have to tell CtrlP to use this function instead of the default:
let g:ctrlp_match_func = { 'match': 'MyCtrlpMatch' }
I also recommend enabling lazy updates to debounce keystrokes. No point re-filtering on every single keypress as you type. 300 milliseconds feels right for me, but you may need to experiment a little.
let g:ctrlp_lazy_update = 300
Roll it all up into your vimrc
, and let it rip!