Selecta is a fuzzy selector. You can use it for fuzzy selection in the style of Command-T, ctrlp, etc. You can also use it to fuzzy select anything else: command names, help topics, identifiers; anything you have a list of.
I wrote it to select things from vim, but it has no dependency on vim at all. Its interface is dead simple:
- Pass it a list of choices on stdin.
- It will present a pretty standard fuzzy selection interface to the user (and block until they make a selection or kill it).
- It will print the user's selection on stdout.
For example, you can say:
cat $(ls *.txt | selecta)
which will prompt the user to fuzzy-select one of the text files in the current directory, then print the contents of whichever one they choose. It looks like this:
Selecta does not:
- Read from or write to the disk.
- Know about any editors (including vim).
- Know what it's searching.
- Perform any actions on the item you select.
It supports these keys:
- ^W to delete the word before the cursor
- ^N to select the next match
- ^P to select the previous match
- ^C to quit without selecting a match
Selecta requires Ruby 1.9 or better.
For now, copy the selecta
script to your path. ~/bin is a great place for it.
If you don't currently have a ~/bin, just do mkdir ~/bin
and add
export PATH="$HOME/bin:$PATH"
to your .zshrc, .bashrc, etc.
Selecta is not installable as a gem! Gems are only good for
application-specific tools. You want Selecta available at all times. If it were
a gem, it would sometimes disappear when you said rvm use
.
There's no actual vim plugin yet. It may not end up needing one; we'll see. For now, you can just stick this in your .vimrc:
" Run a given vim command on the results of fuzzy selecting from a given shell
" command. See usage below.
function! SelectaCommand(choice_command, vim_command)
try
silent! exec a:vim_command . " " . system(a:choice_command . " | selecta")
catch /Vim:Interrupt/
" Swallow the ^C so that the redraw below happens; otherwise there will be
" leftovers from selecta on the screen
endtry
redraw!
endfunction
" Find all files in all non-dot directories starting in the working directory.
" Fuzzy select one of those. Open the selected file with :e.
map <leader>f :call SelectaCommand("find * -type f", ":e")<cr>
Won't this be slow?
Nope: startup and termination together burn about 23 ms of CPU on my machine (a mid-2011 MacBook Air). File finding may be slow, but, speaking of that...
What about caching, selecting only certain file types, etc.?
Those are different problems. This is just a simple fuzzy finding user interface. It could be combined with caching, etc. I don't use caching myself, prefering to keep repos small, so no-caching was a design requirement.
What do you mean it can find things other than files?
Suppose you use ctags, and want to fuzzy-select from them. This shell command will give you a list of tags:
awk '{print $1}' tags | sort -u | grep -v '^!'
(The grep removes the tag file headers.)
Now that we have a tag list, we can use the Vim function from earlier. The Vim
command will be :tag
, to jump to whichever tag we select. The shell command
above will generate the options. Putting those together:
" Find all tags in the tags database, then open the tag that the user selects
command! SelectaTag :call SelectaCommand("awk '{print $1}' tags | sort -u | grep -v '^!'", ":tag")
map <leader>t :SelectaTag<cr>
Now, when you hit <leader>t
, it will prompt you to fuzzy-select a
function/class/whatever, then will jump to the definition of that object.