Better Fuzzy Search with Ctrl-P in Vim
For those familiar with Sublime Text and have since moved to vim you probably miss the Cmd+P feature that allowed you to find a file in your working directory through a fuzzy match. The two main plugin contenders for fuzzy file finding in vim would arguably be Ctrl-P and Command-T. Personally I perfer Ctrl-P because it does not have a compiled extension and it offers a few niceties such as MRU and buffer switcher. Here’s a gif of it in action:

A common technique when using Ctrl-P is to set it up to use it in conjuction with the_silver_searcher as detailed in this blog by Thoughtbot. However, I noticed that often the order of the results are not quite up to par with Command-T or Sublime.
“Fixing” results from Ag and Ctrl-P
To get a better fuzzy finder with silver searcher and Ctrl-P the solution lies with another vim plugin called matcher. This plugin does require a compiled executable, which is kind of a drag in light of my above requirements. But, it is much easier to compile than the Command-T extension IMHO.
To get it set up with vim and silver searcher:
- Clone the repo and or install it with your vim plugin manager.
- Navigate into the repo folder and run
makeand thenmake install - Open up your Vimrc and add the following
" The Silver Searcher
if executable('ag')
" Use ag over grep
set grepprg=ag\ --nogroup\ --nocolor
" Use ag in CtrlP for listing files. Lightning fast and respects .gitignore
let g:ctrlp_user_command = 'ag %s -l --nocolor -g ""'
endifThis should already be there if you are using silver searcher, but I’m including it for clarity.
Then add the following (slightly modified from the README on the matcher repo):
if executable('matcher')
let g:ctrlp_match_func = { 'match': 'GoodMatch' }
function! GoodMatch(items, str, limit, mmode, ispath, crfile, regex)
" Create a cache file if not yet exists
let cachefile = ctrlp#utils#cachedir().'/matcher.cache'
if !( filereadable(cachefile) && a:items == readfile(cachefile) )
call writefile(a:items, cachefile)
endif
if !filereadable(cachefile)
return []
endif
" a:mmode is currently ignored. In the future, we should probably do
" something about that. the matcher behaves like "full-line".
let cmd = 'matcher --limit '.a:limit.' --manifest '.cachefile.' '
if !( exists('g:ctrlp_dotfiles') && g:ctrlp_dotfiles )
let cmd = cmd.'--no-dotfiles '
endif
let cmd = cmd.a:str
return split(system(cmd), "\n")
endfunction
endClose vim or re-source the .vimrc and you should be good to go! Happy fuzzy
matching!