Speeding up Selecta in Vim


I like using Selecta as a fuzzy file opener in Vim. It doesn’t do any caching, so I never have to remember to flush the cache after generating a migration in Rails.

The downside is that if you work on a larger project, it can get kinda pokey. Selecta’s Vim functionality relies on find to populate the file list. If we tell find to ignore directories, it gets a lot faster. Here’s how many files the default find command returns.

><((°> find . -type f | wc -l

That’s a lot! Let’s see if we can cut it down. I’m using a pretty typical Rails project as an example.

><((°> ls
Gemfile           README.md         coverage          spec
Gemfile.lock      Rakefile          db                tmp
Guardfile         app               lib               vendor
Procfile          bin               log
Procfile.dev      config            public
Procfile.jobs.dev config.ru         script

Logfiles are handy, but I never open them in Vim. If I need to see something, I’ll tail it in the terminal. I also don’t care about tmp. We’ll exclude hidden directories too, just for good measure. Let’s cut those out of the find command.

find . \( -path ./log -o -path ./tmp -o -path './.*' \) -prune -o -type f -print | wc -l

Woah! We just excluded 10,865 files! That oughta speed things up a bit. But first I’ll slow down and explain the command.

Now we just have to put it in our config. Here’s what the old Vim mapping looked like:

nnoremap <leader>f :call SelectaCommand("find * -type f", "", ":e")<cr>

Here’s the new one:

let find_cmd = "find . \( -path ./log -o -path ./tmp -o -path './.*' \) "
           \ . "-prune -o -type f -print"
nnoremap <leader>t :call SelectaCommand(find_cmd, "", ":e")<cr>

This is also an example of how to set a variable and concatinate a string in VimL.

Now, this isn’t totally optimal. I’d like to set up some directories that Selecta should ignore on a per-project basis. But it’ll do for now.

Also, Vim isn’t the only place that Selecta is useful! You can use it any place that you can pipe input into a command. This post has a bunch of other nifty examples.

© 2021 JamesGecko