91

Is there any way to search a directory recursively for a file (using wildcards when needed) in Vim? If not natively, is there a plugin that can handle this?

Kara
  • 6,115
  • 16
  • 50
  • 57
mat-mcloughlin
  • 6,492
  • 12
  • 45
  • 62

15 Answers15

122

You can use wildcards with the :edit command. So,

:e **/test/Suite.java

will open test/Suite.java no matter where it is in the current directory hierarchy. This works with tab-completion so you can use [tab] to expand the wildcards before opening the file. See also the wildmode option for a way to browse through all possible extensions instead.

Another trick is to use

:r! find . -type f

to load a list of all files in the current directory into a buffer. Then you can use all the usual vim text manipulation tools to navigate/sort/trim the list, and CTRL+W gf to open the file under the cursor in a new pane.

David Winslow
  • 8,472
  • 1
  • 31
  • 27
  • 1
    +1 I never tried the wildcard in edit command. That works really well with the wildmode as well. So you can type :e **/Suite and all have the list of possible files – mb14 Aug 25 '10 at 08:38
  • I, in turn, had not tried wildmode with wildcard expansion. I updated my answer with a mention. – David Winslow Aug 25 '10 at 12:30
  • 7
    Be very careful with large file collections with complex directory structure. This command can hang your vim for very long time. With my codebase it's been searching for 20 minutes already. What complicates matters is that there is no way to stop it. I tried the usual Ctrl+C and Ctrl+Break. Procmon shows that vim is still searching for my file. So the solution is not for everyone :( – evpo Sep 22 '15 at 02:13
  • 1
    @evpo I had the same problem. I solved it by giving the first part of the path in the search to reduce the number of folders :e dir/**/File.java. Then it took less than a second. – user79878 Oct 05 '17 at 19:43
  • 1
    how the crap did I not know about this? I've been using vim for more than 20 years. Just amazing – Bradley Jan 29 '19 at 10:00
  • 2
    OMG THIS IS AWESOME! – dansch Oct 10 '19 at 02:29
  • For windows users `:r! dir path_to_folder /B /S` – jabellcu Nov 12 '19 at 15:04
63

There is a find command. If you add ** (see :help starstar) to your 'path' then you can search recursively:

:set path

will show you your current path, add ** by doing something like

:set path+=**

then you can just type

:find myfile.txt

and it opens magically!

If you add the set command to your .vimrc it'll make sure you can do recursive search in future. It doesn't seem to search dot directories (.ssh for example)

Stephen Paulger
  • 5,204
  • 3
  • 28
  • 46
24

I'd recommend ctrlp.vim. It's a very good plugin, ideal to work inside large projects. It has search by file name or full path, regexp search, automatic detection of the project root (the one with the .git|hg|svn|bzr|_darcs folder), personalized file name exclusions, and many more.

Just press <c-p> and it will open a very intuitive pane where you can search what you want:

enter image description here

It's possible to select and open several files at once. It also accepts additional arbitrary commands, like jump to a certain line, string occurrence or any other Vim command.

Repo: https://github.com/kien/ctrlp.vim

Victor Schröder
  • 6,738
  • 2
  • 42
  • 45
  • 5
    kien/ctrlp.vim seems to be unmaintained. There seems to be consensus to use the ctrlpvim/ctrlp.vim fork, which appears to be actively maintained: https://github.com/ctrlpvim/ctrlp.vim – Damien Sep 22 '15 at 03:12
  • 5
    fzf is very similar to ctrlp. It is faster and sorts results better. It also works outside of Vim, but has great built in Vim support: https://github.com/junegunn/fzf – still_dreaming_1 May 25 '16 at 17:15
6

vim as a builtin find command (:help find) but only open the first found file. However you can use this amazing plugin : FuzzyFinder which does everything you want and even more

mb14
  • 22,276
  • 7
  • 60
  • 102
  • 1
    `:sf ` is a short, useful command. It runs the `find` command and splits the screen with the file found. No split if the file is not found. Use `Ctrl-W` to navigate between the splits. – amit kumar Mar 15 '22 at 07:43
4

You can browse the file system with :ex ., but I do not know how to search recursively (I am a Vim novice — I have been using it only ten years).

There are a few popular file browsers plug-ins:

See also this thread on SuperUser.

Community
  • 1
  • 1
Paul Ruane
  • 37,459
  • 12
  • 63
  • 82
3

Command-T lets you find a file very fast just by typing some letters. You can also open the file in a new tab, but it need vim compiled with ruby support.

Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
2

You can use ! to run shell commands :

:! find . -name *.xml
Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114
1

vim has bild in commands named grep, lgrep, vimgrep or lvimgrep that can do this

here is a tutorial on how to use them http://vim.wikia.com/wiki/Find_in_files_within_Vim#Recursive_Search

you can also use an external command like find or grep from vim by executing it like this

:!find ...
Nikolaus Gradwohl
  • 19,708
  • 3
  • 45
  • 61
  • How can grep, lgrep, vimgrep or lvimgrep can do this? They search in a file not for a file. – kroiz Apr 20 '17 at 07:28
  • for example by using :grep test **/*.java – Nikolaus Gradwohl Apr 20 '17 at 11:23
  • won't this look for the word test in files names .java? Could you please explain? I could not get it to work. – kroiz Apr 22 '17 at 05:34
  • @kroiz, yes `:grep test */.java` will search for the word `test` in all `.java` files. `:!find` will use the `find` shell command to find for files. The `find` shell command is pretty powerful, if you combine it with pcre or extended regex – alpha_989 Mar 04 '18 at 21:14
1

Quickfix-like result browsing

Usage:

Find my.regex

Outcome:

  • a new tab opens
  • each line contains a relative path that matches a grep -E regex
  • hit:
    • <enter> or <C-w>gf to open the file on the current line in a new tab
    • gf to open the file on the current tab and lose the file list

Find all files instead:

Find

Alternative methods:

Code:

function! Find(cmd)
  let l:files = system(a:cmd)
  if (l:files =~ '^\s*$')
    echomsg 'No matching files.'
    return
  endif
  tabedit
  set filetype=filelist
      set buftype=nofile
  " TODO cannot open two such file lists with this. How to get a nice tab label then?
  " http://superuser.com/questions/715928/vim-change-label-for-specific-tab
  "file [filelist]
  put =l:files
  normal ggdd
  nnoremap <buffer> <Enter> <C-W>gf
  execute 'autocmd BufEnter <buffer> lcd ' . getcwd()
endfunction
command! -nargs=1 Find call Find("find . -iname '*'" . shellescape('<args>') . "'*'")
command! -nargs=1 Gfind call Find('git ls-files | grep -E ' . shellescape('<args>'))
command! -nargs=1 Gtfind call Find('git rev-parse --show-toplevel && git ls-files | grep -E ' . shellescape('<args>'))
command! -nargs=1 Locate call Find('locate ' . shellescape('<args>'))
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
1

Depending on your situation (that is, assuming the following command will find just a single file), perhaps use a command like:

:e `locate SomeUniqueFileName.java`

This will cause Vim to open, in the current tab (the e command) a file that is the result of running (in this example),

locate SomeUniqueFileName.java

Note that the magic here is the backticks around the command, which will convert the output from the shell command into text usable in the Vim command.

Byron Katz
  • 492
  • 5
  • 10
1

You don't need a plugin only for this function, below code snippet is enough.

function! FindFiles()
    call inputsave()
    let l:dir = input("Find file in: ", expand("%:p:h"), "dir")
    call inputrestore()
    if l:dir != ""
        call inputsave()
        let l:file = input("File name: ")
        call inputrestore()
        let l:nf = 'find '.l:dir.' -type f -iname '.l:file.' -exec grep -nH -m 1 ".*" {} \;'
        lexpr system(l:nf)
    endif
endfunction
nnoremap <silent> <leader>fo :call FindFiles()<CR>
brook hong
  • 573
  • 6
  • 13
1

Run:

:args `find . -name '*xml'`

Vim will run the shell command in backticks, put the list of files to arglist and open the first file. Then you can use :args to view the arglist (i.e. list the files found) and :n and :N to navigate forward and bacwards through the files in arglist. See https://vimhelp.org/editing.txt.html#%7Barglist%7D and https://vimhelp.org/editing.txt.html#backtick-expansion

Eugene Prikazchikov
  • 1,794
  • 1
  • 13
  • 11
0

You can find files recursively in your "path" with this plugin. It supports tab completion for the filename as well.

lomilomi26
  • 33
  • 3
0

I am surprised no one mentioned Unite.vim yet.

Finding files (fuzzily or otherwise) is just the very tip of the iceberg of what it can do for a developer. It has built in support for ag, git, and a myriad of other programs/utilities/vim plugins. The learning curve can be a bit steep, but i cannot imagine my life without it. User base is big, and bugs are fixed immediately.

minusf
  • 1,204
  • 10
  • 10
  • these types of answers don't age well :} there was a huge explosion of fuzzy finders for vim/neovim... – minusf May 24 '22 at 07:31
0

ag tool and corresponding Ag vim plugin solves this problem perfectly:

To find a file using some pattern use:

AgFile! pattern

It will open quickfix window with results where you can choose.

You can add vim keybinding to call this command using selected word as a pattern.

nnoremap <silent> <C-h> :AgFile! '<C-R><C-W>'<CR>
vnoremap <silent> <C-h> y :AgFile! '<C-R>"'<CR>
aGlacier
  • 127
  • 6