Vim Tips Wiki
No edit summary
 
No edit summary
Tag: sourceedit
(15 intermediate revisions by 8 users not shown)
Line 1: Line 1:
  +
{{TipImported
{{review}}
 
{{Tip
 
 
|id=799
 
|id=799
  +
|previous=798
|title=Searching for files
 
  +
|next=800
|created=October 3, 2004 2:46
+
|created=October 3, 2004
 
|complexity=intermediate
 
|complexity=intermediate
 
|author=elz
 
|author=elz
|version=5.7
+
|version=7.3
 
|rating=2/2
 
|rating=2/2
  +
|category1=File Handling
|text=
 
  +
|category2=
You can add the following to you .vimrc file:
 
  +
|category3=
 
}}
  +
Vim offers several commands for searching for files by name: {{help|prefix=no|:find}}, {{help|prefix=no|:sfind}}, {{help|prefix=no|:tabfind}} on the command-line, several normal-mode commands like {{help|prefix=no|gf}}, and others. If you just enter <code>:find filename</code>, Vim will directly open the first file found in your {{help|prefix=no|'path'}} matching "filename". You can provide a count like <code>:2find filename</code> to edit the second file on the path matching the filename, but it can be difficult to figure out what order the file you're looking for might occur in your path. Vim 7.3 makes this easier, by introducing tab-completion of filenames found by the <code>:find</code> command. If you set {{help|prefix=no|'wildmenu'}}, then you can see a list of all files found by the command and select which one to edit without worrying about counts or anything else.
   
  +
You can also use external utilities like <code>find</code> on Unix-like systems to look for files. For example, if you want to populate your {{help|prefix=no|quickfix}} list with the output of a <code>find</code> command, you could add this to your [[vimrc]] file:
   
  +
<source lang="vim">
  +
" find files and populate the quickfix list
 
fun! FindFiles(filename)
  +
let error_file = tempname()
 
silent exe '!find . -name "'.a:filename.'" | xargs file | sed "s/:/:1:/" > '.error_file
 
set errorformat=%f:%l:%m
 
exe "cfile ". error_file
  +
copen
  +
call delete(error_file)
 
endfun
 
command! -nargs=1 FindFile call FindFiles(<q-args>)
  +
</source>
   
 
Then, when in normal mode, use the <code>:FindFile</code> command to search for a filename pattern. All the file names that match this pattern (under the current directory) will be displayed in the quickfix window, along with a description of each of one of them.
" find files
 
   
  +
Notice, the search is done in a recursive manner, and you can use wildcards. If your version of <code>find</code> supports it, you can do a case-insensitive search by replacing <code>-name</code> with <code>-iname</code>; otherwise you can specify multiple cases with a pattern like <code>[Ff]oo[Bb]ar.txt</code>. If you want to use a regular expression, you can call <code>find</code> with the <code>-regex</code> or <code>-iregex</code> flags instead (if supported).
fun! FindFiles()
 
   
 
The function uses some standard Unix-like utilities: find, file, sed.
let $filename = input("Enter file name to find: ")
 
   
  +
==Related plugins==
let $error_file = $HOME."/.findfile.output"
 
  +
* {{script|id=1984|text=FuzzyFinder}} (requires {{script|id=3252|text=L9 plugin}})
  +
* [http://kien.github.io/ctrlp.vim/ Ctrl-P] (temporarily expands the commandline)
  +
* {{script|id=3025|text=Command-T}} (requires Ruby support)
  +
* {{script|id=4198|text=AsyncFinder}} (requires Python support, splits open a temporary window, never locks up Vim)
   
  +
==See also==
silent! exe "!find . -iname \"".$filename."\" \| xargs file \| perl -pe 's/:/:1:/' &gt; ".$error_file
 
  +
*[[Find files in subdirectories]]
   
 
==Comments==
cfile $error_file
 
 
I use this little script. If we find an exact match (wc -l = 1), i open the file in vim. If I find more than one matches, open a list of the files. Then I can use 'gf' (gotofile) in vim to open the specific file.
   
  +
<pre>
copen
 
 
#! /bin/sh
 
## fvim: finds files and opens them in vim
 
listfile=/tmp/fvim.tmp
   
 
## Find files and store them in a list
redraw!
 
 
find . -iname "$1" > $listfile
   
 
findcount=`cat $listfile | wc -l`
endfun
 
 
if [ $findcount -ge 2 ] ; then
 
vim $listfile
 
else
 
vim `cat $listfile`
 
fi
  +
</pre>
   
nmap \f :call FindFiles()&lt;CR&gt;
 
 
 
 
Then, when in normal mode, type "\f" (or any other mapping that you prefer). This will give a prompt for a file name pattern to search for. Then, all the file names that match this pattern (under the current directory) will be displayed in the quich fix window, along with a description of each of one of them.
 
 
 
 
Notice, the search is done in a recursive manner. It is case insensitive, and you can use wildcards. If you want to use a regular expression, you can call "find" with the "-regex" or "-iregex" flags.
 
 
 
 
Background:
 
 
The function uses some standard gnu *nix utitlities: find, file.
 
 
You also need perl to be installed.
 
}}
 
 
== Comments ==
 
I made the following minor modifications to your tip in order to get rid of the dependency on perl and to make it independent from the current errorformat.
 
 
fun! FindFiles(filename)
 
let error_file = $HOME."/.findfile.output"
 
silent exe "!find . -iname '".a:filename."' \| xargs file &gt; ".error_file
 
let errorformat=&amp;errorformat
 
let winNr = winnr()
 
setlocal errorformat=%f:\ %m
 
exe "cfile ". error_file
 
copen
 
let cwinNr = winnr()
 
redraw!
 
exec winNr ."wincmd w"
 
exec "setlocal errorformat=". substitute(errorformat, ' ', '\\ ', 'g')
 
exec cwinNr ."wincmd w"
 
endfun
 
command! -nargs=1 FindFile call FindFiles(&lt;q-args&gt;)
 
 
 
'''Anonymous'''
 
, October 3, 2004 9:41
 
 
----
 
----
  +
This is what I do:
Anyway it's possible to use system commands:
 
  +
<source lang="vim">
Example:
 
  +
function! Find(...)
 
  +
if a:0 == 1
:! find foodir -iname "*bar*"
 
  +
let filename = a:1
 
  +
execute "args `find . -iname '*".filename."*' -print`"
'''Anonymous'''
 
  +
elseif a:0 == 2
, October 25, 2004 2:35
 
  +
let path = a:1
----
 
  +
let filename = a:2
I use this little script. If we find an exact match (wc -l = 1), i open the file in vim.
 
  +
execute 'args `find '.path." -iname '*".filename."*' -print`"
If I find more than one matches, open a list of the files. Then I can use 'gf' (gotofile) in vim to open the specific file.
 
  +
endif
 
  +
endfunction
&#35;! /bin/sh
 
  +
command! -nargs=+ Find call Find(<f-args>)
&#35;&#35; fvim: finds files and opens them in vim
 
  +
</source>
 
listfile=/tmp/fvim.tmp
 
 
&#35;&#35; Find files and store them in a list
 
find . -iname "$1" &gt; $listfile
 
 
findcount=`cat $listfile | wc -l`
 
if [ $findcount -ge 2 ] ; then
 
vim $listfile
 
else
 
vim `cat $listfile`
 
fi
 
 
   
'''Anonymous'''
 
, May 12, 2005 10:35
 
 
----
 
----
  +
This way the files are opened in your args list and you can use <code>:argdo</code>
<!-- parsed by vimtips.py in 0.476758 seconds-->
 
  +
<pre>
  +
" Use grep on filenames instead of relying on find's patterns.
  +
" TODO: How to hook this up with 'gf'?
  +
command! -nargs=1 FindFiles call FindFiles(<q-args>)
 
function! FindFiles(filename)
  +
let error_file=tempname()
  +
silent exe '!find . ~
  +
\|grep -Pis "'.a:filename.'" -- -
  +
\| xargs file
  +
\| sed "s/:/:1:/" > '.error_file
  +
setl errorformat=%f:%l:%m
  +
exe "cfile ". error_file
  +
copen
  +
call delete(error_file)
  +
endfunction
  +
</pre>

Revision as of 04:02, 25 January 2017

Tip 799 Printable Monobook Previous Next

created October 3, 2004 · complexity intermediate · author elz · version 7.3


Vim offers several commands for searching for files by name: :find, :sfind, :tabfind on the command-line, several normal-mode commands like gf, and others. If you just enter :find filename, Vim will directly open the first file found in your 'path' matching "filename". You can provide a count like :2find filename to edit the second file on the path matching the filename, but it can be difficult to figure out what order the file you're looking for might occur in your path. Vim 7.3 makes this easier, by introducing tab-completion of filenames found by the :find command. If you set 'wildmenu', then you can see a list of all files found by the command and select which one to edit without worrying about counts or anything else.

You can also use external utilities like find on Unix-like systems to look for files. For example, if you want to populate your quickfix list with the output of a find command, you could add this to your vimrc file:

" find files and populate the quickfix list
fun! FindFiles(filename)
  let error_file = tempname()
  silent exe '!find . -name "'.a:filename.'" | xargs file | sed "s/:/:1:/" > '.error_file
  set errorformat=%f:%l:%m
  exe "cfile ". error_file
  copen
  call delete(error_file)
endfun
command! -nargs=1 FindFile call FindFiles(<q-args>)

Then, when in normal mode, use the :FindFile command to search for a filename pattern. All the file names that match this pattern (under the current directory) will be displayed in the quickfix window, along with a description of each of one of them.

Notice, the search is done in a recursive manner, and you can use wildcards. If your version of find supports it, you can do a case-insensitive search by replacing -name with -iname; otherwise you can specify multiple cases with a pattern like [Ff]oo[Bb]ar.txt. If you want to use a regular expression, you can call find with the -regex or -iregex flags instead (if supported).

The function uses some standard Unix-like utilities: find, file, sed.

Related plugins

See also

Comments

I use this little script. If we find an exact match (wc -l = 1), i open the file in vim. If I find more than one matches, open a list of the files. Then I can use 'gf' (gotofile) in vim to open the specific file.

#! /bin/sh
## fvim: finds files and opens them in vim
listfile=/tmp/fvim.tmp

## Find files and store them in a list
find . -iname "$1" > $listfile

findcount=`cat $listfile | wc -l`
if [ $findcount -ge 2 ] ; then
 vim $listfile
else
 vim `cat $listfile`
fi

This is what I do:

function! Find(...)
   if a:0 == 1
      let filename = a:1
      execute "args `find . -iname '*".filename."*' -print`"
   elseif a:0 == 2
      let path     = a:1
      let filename = a:2
      execute 'args `find '.path." -iname '*".filename."*' -print`"
   endif
endfunction
command! -nargs=+ Find call Find(<f-args>)

This way the files are opened in your args list and you can use :argdo

" Use grep on filenames instead of relying on find's patterns.
" TODO: How to hook this up with 'gf'?
command! -nargs=1 FindFiles call FindFiles(<q-args>)
function! FindFiles(filename)
  let error_file=tempname()
  silent exe '!find . ~
    \|grep -Pis "'.a:filename.'" -- -
    \| xargs file
    \| sed "s/:/:1:/" > '.error_file
  setl errorformat=%f:%l:%m
  exe "cfile ". error_file
  copen
  call delete(error_file)
endfunction