Using dmenu to open files quickly in Vim
I've been using the FuzzyFinder plugin for Vim for quite some time. It’s an invaluable part of my development toolbox. I've tried a handful other fuzzy style file finders, but FuzzyFinder always has been the most reliable.
There’s one problem though, it’s slow. At work our codebase is tens of thousands of files and sadly FuzzyFinder chokes. Plagued with slow initial scanning and lagging your typing as it searches.
This is where dmenu comes into play. dmenu is a neat little program for Linux that provides a keyboard operated menu for selecting an item from a list. It’s really easy to operate, just pipe in the list of items and dmenu will pop up letting you pick one.
With a little bit of Vim script added to our .vimrc
we can add dmenu support:
" Strip the newline from the end of a string
function! Chomp(str)
return substitute(a:str, '\n$', '', '')
endfunction
" Find a file and pass it to cmd
function! DmenuOpen(cmd)
let fname = Chomp(system("git ls-files | dmenu -i -l 20 -p " . a:cmd))
if empty(fname)
return
endif
execute a:cmd . " " . fname
endfunction
Here I've opted to use git ls-files
to get the list of files to search from.
All my projects use git, and this is a quick way to get the list of files
without any build artifacts.
If you want to include every file from the current directory, git ls-files
can easily be replaced with find .
.
I call dmenu
with a couple flags worth noting. The -i
flag makes dmenu do
case insensitive search, which I find useful. -l 20
is used to show the
completion menu vertically (with 20 lines), which is much easier to read with
long strings like file paths. Finally, I pass the command I want Vim to execute
on the search result to the prompt of dmenu using -p
.
I pass the command to the function so I can have two shortcuts for opening a file either in the current buffer or a new tab:
map <c-t> :call DmenuOpen("tabe")<cr>
map <c-f> :call DmenuOpen("e")<cr>
Ctrl-t will give me the file in a new tab, and Ctrl-f will give me the file in the current buffer.
And that’s it! Your Vim file searching is now powered by dmenu. Ultra fast and ultra responsive.
dmenu’s string matching
dmenu’s matching isn’t exactly fuzzy, but it’s pretty good and it’s fast. The
string you type is matched literally against each file starting anywhere, this
means hello/world
would match paths like hello/world
, things/hello/world
and files/hello/world.rb
.
dmenu splits what you type by spaces, and uses each part as a pattern. The
string hello world
would match anything that contains both hello
and
world
. This is great for narrowing down a too broad search.