Without plugins like ctrlp and NERDTree, what would be the most efficient way to find and open files deep in a project tree?

Setting the path to **/* results in useless files in .git and other hidden directories, so that appears to be out of the question.

Is there a way to set the path in a smart manner, so that it only includes files in git ls-files or something?

3 Answers 3


Here are the relevant parts of my setup:

  • enable the wildmenu,

    set wildmenu
  • make filename-completion skip these files and directories,

    set wildignore+=*.swp,*.bak
    set wildignore+=*.pyc,*.class,*.sln,*.Master,*.csproj,*.csproj.user,*.cache,*.dll,*.pdb,*.min.*
    set wildignore+=*/.git/**/*,*/.hg/**/*,*/.svn/**/*
    set wildignore+=*/min/*
    set wildignore+=tags,cscope.*
    set wildignore+=*.tar.*
  • make it case-insensitive,

    set wildignorecase
  • list files and let the user choose with the wildmenu,

    set wildmode=list:full
  • add the directory of the current file and every directory under the working directory to Vim's path,

    set path=.,**

    WARNING! The path option is extremely useful. The value above — .,** — works for me but the languages I use don't have a standard library. The proper value depends entirely on your needs.

  • a bunch of :find mappings, the uppercase variants start the search from the directory of the current file for better performance,

    nnoremap ,f :find *
    nnoremap ,F :find <C-R>=expand('%:p:h').'/**/*'<CR>
    nnoremap ,s :sfind *
    nnoremap ,S :sfind <C-R>=expand('%:p:h').'/**/*'<CR>
    nnoremap ,v :vert sfind *
    nnoremap ,V :vert sfind <C-R>=expand('%:p:h').'/**/*'<CR>

And here is how it looks like:


  • 1
    Wow, these are some great mappings and settings. Thank you for the detailed answer.
    – user489
    Mar 14, 2015 at 18:04

See :h :command-completion-custom

We can adapt the last example to complete only files listed by git.

command! -nargs=1 -bang -complete=customlist,GitFindComplete
      \ GitFind edit<bang> <args>

function! GitFindComplete(ArgLead, CmdLine, CursorPos)
  let search_pattern = "*" . a:ArgLead . "*"
  let shell_cmd = "git ls-files " . shellescape(search_pattern)
  return split(system(shell_cmd), "\n")

Now you can use auto-completion to open the files listed by git:

:GitFind ome_f<Tab>

Note that in a custom completion function, we must do more than simply list the files which could be completed. We must also filter the list relative to the current commandline argument ArgLead. In this example, we ask git to do the filtering for us, by passing it the argument wrapped in * wildcards.

  • This is an excellent trick
    – user489
    Mar 17, 2015 at 6:23

My method include the following shell function in ~/.bash_profile:

vimf() {
  vim $(find . -name $1)

Then to open any file deep in the project tree, just type:

vimf some_file.c

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.