Skip to content

Instantly share code, notes, and snippets.

@dancrew32
Created July 25, 2011 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dancrew32/1104884 to your computer and use it in GitHub Desktop.
Save dancrew32/1104884 to your computer and use it in GitHub Desktop.
FindFile.vim with tabnew
" vim600: set foldmethod=marker:
" $Id:$
" PURPOSE: {{{
" - FindFile: Switch to an auto-completing buffer to open a file quickly.
"
" REQUIREMENTS:
" - Vim 7.0
"
" USAGE:
" Put this file in your ~/.vim/plugin directory.
" If you are working on a project, go to the root directory of the project,
" then execute:
"
" :FindFileCache .<CR>
" or
" :FC .<CR>
"
" This will recursively parse the directory and create the internal cache.
"
" You can also put in multiple arguments in :FC:
"
" :FC /dir1 /dir2 /dir3
"
" You can add to the cache by calling :FC again. File with the same path
" will not be added to the cache twice.
"
" To find a file:
"
" :FindFile<CR>
" or
" :FF<CR>
"
" This opens a scratch buffer that you can type in the file name. Press
" <Esc> will quit the buffer, while <Enter> will select and edit the file.
"
" To clear the internal cache, do:
"
" :FindFileCacheClear<CR>
" or
" :FCC<CR>
"
"
" You can put the following lines in your ~/.vimrc in order to invoke
" FindFile quickly by hitting <C-f>:
"
" :nmap <C-f> :FindFile<CR>
"
" By default, all the *.o, *.pyc, and */tmp/* files will be ignored, in
" addition to the wildignore patterns. You can customize this by setting in
" your .vimrc:
"
" let g:FindFileIgnore = ['*.o', '*.pyc', '*/tmp/*']
"
" CREDITS:
" Please mail any comment/suggestion/patch to
" William Lee <wl1012@yahoo.com>
"
" Section: Mappings {{{1
command! -nargs=* -complete=dir FindFileCache call <SID>CacheDir(<f-args>)
command! -nargs=* -complete=dir FC call <SID>CacheDir(<f-args>)
command! FindFileCacheClear call <SID>CacheClear()
command! FCC call <SID>CacheClear()
command! FindFile call <SID>FindFile()
command! FF call <SID>FindFile()
command! FindFileSplit call <SID>FindFileSplit()
command! FS call <SID>FindFileSplit()
command! FindFileTab call <SID>FindFileTab()
command! FT call <SID>FindFileTab()
" Global Settings {{{1
if !exists("g:FindFileIgnore")
let g:FindFileIgnore = ['*.o', '*.pyc', '*/tmp/*']
endif
" Section: Functions {{{1
" File cache to store the filename
let s:fileCache = {}
" The sorted keys for the dictionary
let s:fileKeys = []
fun! CompleteFile(findstart, base)
if a:findstart
return 0
else
" TODO: We can definitely do a binary search on the keys instead of
" doing a linear match.
for k in s:fileKeys
let matchExpr = <SID>EscapeChars(a:base)
if match(k, matchExpr) == 0
call complete_add({'word': k, 'menu': s:fileCache[k], 'icase' : 1})
endif
if complete_check()
break
endif
endfor
return []
endif
endfun
fun! <SID>MayComplete(c)
if pumvisible()
return a:c
else
return "" . a:c . "\<C-X>\<C-O>"
endif
endfun
fun! <SID>FindFileSplit()
split
call <SID>FindFile()
endfun
fun! <SID>FindFileTab()
tabnew
call <SID>FindFile()
endfun
fun! <SID>FindFile()
new FindFile
setlocal buftype=nofile
setlocal bufhidden=hide
setlocal noswapfile
" Map the keys for completion:
" We are remapping keys from ascii 33 (!) to 126 (~)
let k = 33
while (k < 127)
let c = escape(nr2char(k), "\\'|")
let remapCmd = "inoremap <expr> <buffer> " . c . " <SID>MayComplete('" . c . "')"
exe remapCmd
let k = k + 1
endwhile
inoremap <buffer> <CR> <ESC>:silent call <SID>EditFile(getline("."))<CR>
inoremap <buffer> <ESC> <C-[>:silent call <SID>QuitBuff()<CR>
nnoremap <buffer> <ESC> :silent call <SID>QuitBuff()<CR>
setlocal completeopt=menuone,longest,preview
setlocal omnifunc=CompleteFile
setlocal noignorecase
startinsert
endfun
fun! <SID>CacheClear()
let s:fileCache = {}
let s:fileKeys = []
echo "FindFile cache cleared."
endfun
fun! <SID>EscapeChars(toEscape)
return escape(a:toEscape, ". \!\@\#\$\%\^\&\*\(\)\-\=\\\|\~\`\'")
endfun
fun! <SID>CacheDir(...)
echo "Finding files to cache..."
for d in a:000
"Creates the dictionary that will parse all files recursively
for i in g:FindFileIgnore
let s = "setlocal wildignore+=" . i
exe s
endfor
let files = glob(d . "/**")
for i in g:FindFileIgnore
let s = "setlocal wildignore-=" . i
exe s
endfor
let ctr = 0
for f in split(files, "\n")
let fname = fnamemodify(f, ":t")
let fpath = fnamemodify(f, ":p")
" We only glob the files, not directory
if !isdirectory(fpath)
" If the cache already has this entry, we'll just skip it
let hasEntry = 0
while has_key(s:fileCache, fname)
if s:fileCache[fname] == fpath
let hasEntry = 1
break
endif
let fnameArr = split(fname, ":")
if len(fnameArr) > 1
let fname = fnameArr[0] . ":" . (fnameArr[1] + 1)
else
let fname = fname . ":1"
endif
endwhile
if !hasEntry
let s:fileCache[fname] = fpath
let ctr = ctr + 1
endif
endif
endfor
let s:fileKeys = sort(copy(keys(s:fileCache)))
echo "Found " . ctr . " new files in '" . d . "'. Cache has " . len(s:fileKeys) . " entries."
endfor
endfun
fun! <SID>QuitBuff()
silent exe "bd!"
endfun
fun! <SID>EditFile(f)
" Closes the buffer
let fileToOpen = a:f
if has_key(s:fileCache, a:f)
let fileToOpen = s:fileCache[a:f]
else
" We attempt to find the file in the list if it is not a
" complete key
let matchExpr = <SID>EscapeChars(a:f)
for k in s:fileKeys
if match(k, matchExpr) == 0
let fileToOpen = s:fileCache[k]
break
endif
endfor
endif
if filereadable(fileToOpen)
silent exe "bd!"
silent exe "edit " . fileToOpen
echo "File: " . fileToOpen
else
echo "File " . fileToOpen . " not found. Run ':FileFindCache .' to refresh if necessary."
endif
endfun
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment