Making FuzzyFinder vim plugin really convenient (a-la TextMate “Go to file”)

I really like the FuzzyFinder vim plugin. In short, it allows to search quickly for files, tags, buffers, etc using fuzzy logic.

I especially like it for its ability to find files recursively using simple patterns. However, by default FuzzyFinder is not really convenient because it searches for files relative to the current working directory in vim. And what I want is to be able to search for files recursively relative to some project’s root directory at any moment from any buffer.

Of course, it’s possible in FuzzyFinder to use “../../**”-alike patterns in order to make it search recursively starting from upper directories. But it’s quite boring. It’s especially painful for those folks(me included) who have vim settings which change the vim cwd to the one where the opened file resides.

Some folks may suggest using the Project plugin which allows to setup the global cwd for each project. But that’s too much of a hassle to my humble opinion. There should be a simpler way :)

The idea is simple:

  • put FuzzyFinder file search options into some configuration file in the root of the project(.fuzzyfinder for example)
  • find this special configuration file by going “up” from the current directory in a loop until the file is found
  • parse configuration file settings
  • invoke the FuzzyFinder with proper settings

Here is the vim script with ProjectFuzzyFind() function which implements the described above algorithm(put it into your .vimrc):

function! ProjectFuzzyFind()
  let origcurdir = getcwd()
  let curdir = origcurdir
  let prevdir = ""
 
  while curdir != prevdir
    if filereadable(".fuzzyfinder")
      break
    endif
    cd ..
    let prevdir = curdir
    let curdir = getcwd()
  endwhile
 
  if filereadable(".fuzzyfinder")
    let items = readfile(".fuzzyfinder")
    let files = []
    for n in items
      let files += split(glob(curdir . "/" . n), "\n")
    endfor
 
    call fuf#givenfile#launch('', 0, '>', files)
  endif
endfunction

Let’s add a convenient mapping for this function as well:

map ,p :call ProjectFuzzyFind()<CR>
let g:fuf_maxMenuWidth = 150

Now whenever you trigger ,p in the normal mode you should see a FuzzyFinder autocompletion menu for your project’s files. The above snippet also sets bigger than default autocompletion menu width which can be very handy for long file names.

You are probably wondering how exactly the .fuzzyfinder file should look like? Here is the sample from my current project:

client/src/**
server/src/**
*

As you can see you can use file glob masks(even recursive!). This file must be placed in the root of the project and its file paths must be relative to the root directory of the project. I’m also thinking of adding support for file paths exclusion, this should not be hard to implement.

Please note, this script was tested with FuzzyFinder-3.5, the most stable version as of this writing.

Leave a Reply