VIM: FuzzyFinder usage, tips, gotchas - how can one make use of this plugin?
Asked Answered
A

7

25

http://www.vim.org/scripts/script.php?script_id=1984

You can launch FuzzyFinder by following commands:

     Command           Mode ~
    |:FufBuffer|     - Buffer mode (|fuf-buffer-mode|)
    |:FufFile|       - File mode (|fuf-file-mode|)
    |:FufDir|        - Directory mode (|fuf-dir-mode|)
    |:FufMruFile|    - MRU-File mode (|fuf-mrufile-mode|)
    |:FufMruCmd|     - MRU-Command mode (|fuf-mrucmd-mode|)
    |:FufBookmark|   - Bookmark mode (|fuf-bookmark-mode|)
    |:FufTag|        - Tag mode (|fuf-tag-mode|)
    |:FufTaggedFile| - Tagged-File mode (|fuf-taggedfile-mode|)
    |:FufJumpList|   - Jump-List mode (|fuf-jumplist-mode|)
    |:FufChangeList| - Change-List mode (|fuf-changelist-mode|)
    |:FufQuickfix|   - Quickfix mode (|fuf-quickfix-mode|)
    |:FufLine|       - Line mode (|fuf-line-mode|)
    |:FufHelp|       - Help mode (|fuf-help-mode|)

So I just recently found out about FuzzyFinder. For anyone who's used this for quite awhile, can you demonstrate how you actually use these commands in combination, any mappings you make, any gotchas that one should know while using this?

Apogeotropism answered 12/12, 2009 at 20:29 Comment(0)
S
13

FuzzyFinder on itself is pretty useless to me. I use it in combination with FuzzyFinder-TextMate and a Ruby library that traverses all files and subdirectories to find a file, much like the Cmd+T option for TextMate on a Mac. You can see it in action here.

Unfortunately, it takes some effort to get it to work since the original author stopped maintaining the script. There are still some people regularly posting updates to github though. You will need two scripts, fuzzyfinder_textmate.vim and fuzzy_file_finder.rb.

The latest versions work without a problem in combination with Vim FuzzyFinder 2.22.3. Your Vim has to be compiled with Ruby support otherwise it will not work. The blog of the original author contains more information on how to use it properly. Alternatively, have a look at my Vim setup to see how it can be used. The setup defines two keymappings ,s and ,e to fuzzy find a file and open it in a new window or the current window respectively:

function IdeFindTextMate()
  let g:FuzzyFinderOptions.Base.key_open = '<CR>'
  let g:FuzzyFinderOptions.Base.key_open_split = '<C-j>'
  exe "FuzzyFinderTextMate"
endfunction

function IdeSplitFindTextMate()
  let g:FuzzyFinderOptions.Base.key_open = '<C-j>'
  let g:FuzzyFinderOptions.Base.key_open_split = '<CR>'
  exe "FuzzyFinderTextMate"
endfunction

let mapleader = ","
map <silent> <leader>e :call IdeFindTextMate()<CR>
map <silent> <leader>s :call IdeSplitFindTextMate()<CR>

Update:

Right now I use the excellent Command-T plugin instead of FuzzyFinder. Have a look at this superuser answer of mine for the reasons why.

Sublime answered 13/12, 2009 at 17:13 Comment(7)
I wish there was a script like this without the ruby requirement (i.e. python)Government
FuzzyFinder has always handled subdirectories for me. Is this a config issue, or have I misunderstood the shortfall @Ton references?Perplex
At the time I checked (three years ago), you needed to type part of the path to reach a file in a subdirectory. Maybe this has changed since then?Sublime
@TonvandenHeuvel you really improve my lifeThibodeaux
I've been using fuzzy finder for many years, haven't updated in all that time, and I only ever need to type part of the filename OR path in order to display all files for which the full pathname matches what was typed.Perplex
... i.e. I can just type the start of the filename, and immediately see files in subdirectories. I have bound a key to :FufFile **/ Perhaps the trailing punctuation is important?Perplex
Your link to 'this' has fallen victim to SO's overzealous "delete anything that isn't what we envisage" police. I have also recently lost some comprehensive answers I wrote, presumably because they were in response to questions that were subsequently deleted. My commiserations.Perplex
C
10

A bit late to the party, but I'd like to add that the latest version of FuzzyFinder has a new command: :FufCoverageFile, which does exactly what you'd want, i.e.:

>CoverageFile>appcontr
  20: app/controllers/application_controller.rb
  22: app/views/layouts/application.html.erb
Cureall answered 18/9, 2011 at 19:54 Comment(2)
Also worth noting the g:fuf_coveragefile_globPatterns variable can be updated to include path/patterns you want to search using FufCoverageFile. I use FufCoverageFile and FufBuffer almost every minute ;)Boden
How do you navigate between results? I don't want to use arrows and tab doesn't seem to navigate forwardDeft
M
7

In addition to Kris' answer, you probably want to map the '**/' immediately in your .vimrc file like this:

map ,f :FufFile **/<CR>

So you just need to type :

,fTest 

to find all matches of Test in all subdirectories!

HTH

Menefee answered 8/2, 2012 at 21:46 Comment(0)
L
6

I use :FufFile mapped to ,b and start by typing **/ followed by the first few characters of the string I'm looking for.

This provides a list of all matching files which include your string.

e.g

,b
**/doc
    13: app/models/document.rb
    75: test/fixtures/documents.yml
    82: test/unit/document_test.rb
Liturgist answered 1/4, 2011 at 22:33 Comment(2)
I would also add that I, personally, think the Command-T plugin is much easier to use since you simply type <leader>t and start typing characters. git.wincent.com/command-t.git/blob_plain/HEAD:/README.txtLiturgist
Using fuzzyfinder, I just press <leader>t and start typing characters. I might have had to tweak the config when I installed it years ago. (rummages...) Yep, my .vimrc has lines like "nnoremap <Leader>f :FufFile **/<cr>". I have a line like this for each fuzzyfind mode I use (File, Buffer, Tag)Perplex
P
6

First install the latest fuzzy finder script. Then...

Config

Tweak some config in your .vimrc:

" Truth be told, I don't remember what these do, but I must have
" found them necessary back when I installed fuzzyfinder years ago
let s:slash = '[/\\]'
let s:startname = '(^|'.s:slash.')'
let s:endname = '($|'.s:slash.')'

" directories and extensions to ignore when listing files
" these contain a lot of Python-isms, yours will probably vary
let s:extension = '\.bak|\.dll|\.exe|\.o|\.pyc|\.pyo|\.swp|\.swo'
let s:dirname = 'build|deploy|dist|vms|\.bzr|\.git|\.hg|\.svn|.+\.egg-info'
let g:fuf_file_exclude = '\v'.'('.s:startname.'('.s:dirname.')'.s:endname.')|(('.s:extension.')$)'
let g:fuf_dir_exclude = '\v'.s:startname.'('.s:dirname.')'.s:endname

" limit number of displayed matches
" (makes response instant even on huge source trees)
let g:fuf_enumeratingLimit = 60

and I define some shortcut keys to activate it:

nnoremap <Leader>f :FufFile **/<cr>
nnoremap <Leader>b :FufBuffer<cr>
nnoremap <Leader>t :FufTag<cr>

and restart Vim to re-read the .vimrc config.

Find file / buffer

Now I can press <leader>f to see a list of files in the current directory and subdirs. Start typing and the list is filtered to just those that (fuzzy)match what you type. Use cursor keys to select a match and enter to open that file. The first time you activate this in a very large new project, it might take a second to cache the filenames.

Similarly, when you have a few buffers open, press <leader>b to select from a list of open buffers.

Find tag

Best of all is tag matching (i.e. go to a function, class, method, etc.) First we have to generate a tagfile though.

If you're not used to tags files, this might seem like a hassle to have to do it manually. Be aware that many tools use tags files, for example Vim itself will read them to enable 'go to definition', see that link at the end of this answer, so learning about them is perhaps more valuable than you might expect.

Install the latest ctags (http://ctags.sourceforge.net/) and make sure it's on your PATH so you can invoke it from the command line. Recent versions are much improved for languages like Python. Then define a keystroke in .vimrc to make it easy to re-run it on your project, and blow away fuzzyfinder's cache at the same time:

noremap <f12> :silent !ctags -R --languages=python .<cr>:FufRenewCache<cr>

or on Windows:

noremap <f12> :!start /min ctags -R --languages=python .<cr>:FufRenewCache<cr>

(the /min is a Windows-specific way to run the command in the background so that Vim doesn't lock up while indexing very large projects)

Restart vim, and pressing f12 will now scan every file in the current dir and subdirs, and create an index of all defined functions, classes, etc. ctags parses many programming languages. The output goes to a file called 'tags'. It makes sense to run this in your project root (use Vim's :pwd and :cd to make sure that's where you are) so that the tags file contains everything in your project.

So now you can press <leader>t to see a listing of all the classes, functions, methods, etc in yourproject. As above, start typing, and the list gets filtered down to just those that match what you type. Use cursors and enter to select one, and Vim will go to the file/line where that tag is defined.

Gotchas

If a tag is defined more than once in your project, (e.g. a class with the same name as a function) then fuzzyfinder will offer a menu so you can choose which one you want to jump to. This can be a bit annoying, because by default, ctags produces too many tag definitions for Python files. It lists not just the definition of classes, methods and function, but all the places any symbol is defined within a source file. This includes the creation of variables, and the places where a symbol is imported from somewhere else. This means that a symbol which is defined in one file and imported in a second file will have two definition locations, which means you'll always be presented with a menu instead of simply jumping directly to the class definition. You can fix this by creating a ctags options file in ~/.ctags, telling it not to generate tags for 'include' statments, and to skip some directories:

--python-kinds=-i
--exclude=build
--exclude=dist

When you change your source code, your tags file will be out of date. If you create new classes/functions/methods/etc then to jump to them you'll have to re-run ctags as shown above. It's surprising how infrequently this matters though.

I found that <leader>b would pause for a second before working, which was annoying. Turned out the reason is that there's another mapping defined for <leader>bd defined by my BClose plugin, and Vim was waiting to see whether or not I pressed the subsequent d before deciding which key mapping to invoke. I never use that, so I disabled it using this in my .vimrc:

autocmd VimEnter * nunmap <Leader>bd

BTW, now that you're generating tagfiles for your project, it's easy to also enable a keystroke to do 'go to definition' of the symbol under your text cursor. See my blog post about it: https://www.tartley.com/go-to-definition-in-vim-for-python-using-ctags-on-windows

Perplex answered 24/6, 2013 at 13:43 Comment(0)
E
4

Here are the mapping I use (they're not mine, though I'm really used to them now) :

let g:fuf_modesDisable = []
let g:fuf_mrufile_maxItem = 1000
let g:fuf_mrucmd_maxItem = 400
let g:fuf_mrufile_exclude = '\v\~$|\.(bak|sw[po])$|^(\/\/|\\\\|\/mnt\/)'
nnoremap <silent> <C-n>      :FufBuffer<CR>
nnoremap <silent> <C-p>      :FufFileWithCurrentBufferDir<CR>
nnoremap <silent> <C-f><C-p> :FufFileWithFullCwd<CR>
nnoremap <silent> <C-f>p     :FufFile<CR>
nnoremap <silent> <C-f><C-d> :FufDirWithCurrentBufferDir<CR>
nnoremap <silent> <C-f>d     :FufDirWithFullCwd<CR>
nnoremap <silent> <C-f>D     :FufDir<CR>
nnoremap <silent> <C-j>      :FufMruFile<CR>
nnoremap <silent> <C-k>      :FufMruCmd<CR>
nnoremap <silent> <C-b>      :FufBookmarkDir<CR>
nnoremap <silent> <C-f><C-t> :FufTag<CR>
nnoremap <silent> <C-f>t     :FufTag!<CR>
noremap  <silent> g]         :FufTagWithCursorWord!<CR>
nnoremap <silent> <C-f><C-f> :FufTaggedFile<CR>
nnoremap <silent> <C-f><C-j> :FufJumpList<CR>
nnoremap <silent> <C-f><C-g> :FufChangeList<CR>
nnoremap <silent> <C-f><C-q> :FufQuickfix<CR>
nnoremap <silent> <C-f><C-l> :FufLine<CR>
nnoremap <silent> <C-f><C-h> :FufHelp<CR>
nnoremap <silent> <C-f><C-b> :FufAddBookmark<CR>
vnoremap <silent> <C-f><C-b> :FufAddBookmarkAsSelectedText<CR>
nnoremap <silent> <C-f><C-e> :FufEditInfo<CR>
nnoremap <silent> <C-f><C-r> :FufRenewCache<CR>

I mainly use : for last opened files to change buffers (and I removed all buxexplorer plugins) p to browse files/directories

Ernaline answered 19/9, 2011 at 7:32 Comment(2)
Thanks for the mappings. <C-f> is one of several pagedown keys for me but it's good to have this as a starting point.Germicide
This is maybe not the place, but now I've switched to Unite.vim and FZF which are both really good.Ernaline
M
1

OK, after using vim fuf for 12+ years, I finally find the answer: "how to exclude an folder when search files between node_module folder" : (answer copied from @Jonathan )

" Truth be told, I don't remember what these do, but I must have
" found them necessary back when I installed fuzzyfinder years ago
let s:slash = '[/\\]'
let s:startname = '(^|'.s:slash.')'
let s:endname = '($|'.s:slash.')'

" directories and extensions to ignore when listing files
" these contain a lot of Python-isms, yours will probably vary
let s:extension = '\.bak|\.dll|\.exe|\.o|\.pyc|\.pyo|\.swp|\.swo'
let s:dirname = 'build|deploy|dist|vms|\.bzr|\.git|\.hg|\.svn|.+\.egg-info'
let g:fuf_file_exclude = '\v'.'('.s:startname.'('.s:dirname.')'.s:endname.')|(('.s:extension.')$)'
let g:fuf_dir_exclude = '\v'.s:startname.'('.s:dirname.')'.s:endname

" limit number of displayed matches
" (makes response instant even on huge source trees)
let g:fuf_enumeratingLimit = 60
Mucor answered 30/3, 2022 at 23:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.