Search code examples
vimfzf

How to run FZF in vim in a directory where the directory path comes from a function?


I'd like to run fzf file finder (inside vim) on a custom directory, but the directory name varies at runtime.

For e.g., say, vim is started at the root of project directory. The subdirectories look like:

$ tree -ad
.
├── docs
├── .notes
│   ├── issue_a
│   └── new_feature
├── README
├── src
└── tests

Every time I create a branch, I also create a directory in .notes/BRANCH_NAME where I store notes, tests results, etc. The .notes directory itself is ignored by git.

I'd like to run FZF on the .notes/BRANCH_NAME directory. The branch name will come from a function (say using https://github.com/itchyny/vim-gitbranch).

I am able to run fzf on the .notes directory by :FZF .notes, but I don't know how to run it on the branch directory within .notes.

Thanks!

Edit: Added what I'd tried:

I tried saving the output of gitbranch#name() to a variable and then use it to call fzf#run(), but didn't quite work:

function! NotesDir()
    let branch=gitbranch#name()
    let ndir=".notes/" . branch
    call fzf#run({'source': ndir})
endfunction
command! NotesDir call NotesDir()

When I run :NotesDir while on branch issue_a, I see fzf window with an error:

>   < [Command failed: .notes/issue_a]

.notes/issue_a indicates that ndir variable has the correct notes directory path, but I couldn't figure out how to pass it to fzf.


Solution

  • Looking at the documentation for fzf#run(), it looks like source could be either a string, interpreted as a shell command to execute, or a list, used as-is to populate the plugin's window.

    So your mistake was passing a path as source, which was interpreted as an external command, instead of either an external command or a list of paths.

    It also says that you should at least provide a sink but some examples don't have it so YMMV.

    If I am reading that section correctly, the following approaches should work:

    " with a string as external command
    call fzf#run({'source': 'find ' .. ndir, 'sink': 'e'})
    
    " with a list
    let list = globpath('.', ndir, O, 1)
               \ ->map({ _, val -> val->fnamemodify(':.')})
    call fzf#run({'source': list, 'sink': 'e'})
    

    NOTE: I don't use that plugin so this is not tested.