1
0
mirror of https://github.com/amix/vimrc synced 2025-07-10 11:44:59 +08:00

rename vim_plugins_src to vim_plugin_candinates_src and used as an plugin candinate dir

This commit is contained in:
hustcalm
2012-10-29 18:20:36 +08:00
parent b27590fbb4
commit b64930e3e7
486 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,472 @@
" lookupfile.vim: See plugin/lookupfile.vim
" Make sure line-continuations won't cause any problem. This will be restored
" at the end
let s:save_cpo = &cpo
set cpo&vim
" Some onetime initialization of variables
if !exists('s:myBufNum')
let s:windowName = '[Lookup File]'
let s:myBufNum = -1
let s:popupIsHidden = 0
endif
let g:lookupfile#lastPattern = ""
let g:lookupfile#lastResults = []
let g:lookupfile#lastStatsMsg = []
let g:lookupfile#recentFiles = []
function! lookupfile#OpenWindow(bang, initPat)
let origWinnr = winnr()
let _isf = &isfname
let _splitbelow = &splitbelow
set nosplitbelow
try
if s:myBufNum == -1
" Temporarily modify isfname to avoid treating the name as a pattern.
set isfname-=\
set isfname-=[
if exists('+shellslash')
call genutils#OpenWinNoEa("1sp \\\\". escape(s:windowName, ' '))
else
call genutils#OpenWinNoEa("1sp \\". escape(s:windowName, ' '))
endif
let s:myBufNum = bufnr('%')
else
let winnr = bufwinnr(s:myBufNum)
if winnr == -1
call genutils#OpenWinNoEa('1sb '. s:myBufNum)
else
let wasVisible = 1
exec winnr 'wincmd w'
endif
endif
finally
let &isfname = _isf
let &splitbelow = _splitbelow
endtry
call s:SetupBuf()
let initPat = ''
if a:bang != ''
let initPat = ''
elseif a:initPat != ''
let initPat = a:initPat
elseif g:lookupfile#lastPattern != '' && g:LookupFile_PreserveLastPattern
let initPat = g:lookupfile#lastPattern
endif
$
if getline('.') !=# initPat
silent! put=''
call setline('.', initPat)
endif
startinsert!
if !g:LookupFile_OnCursorMovedI
" This is a hack to bring up the popup immediately, while reopening the
" window, just for a better response.
aug LookupFileCursorHoldImm
au!
au CursorMovedI <buffer> nested exec 'doautocmd LookupFile CursorHoldI' |
\ au! LookupFileCursorHoldImm
aug END
endif
call s:LookupFileSet()
aug LookupFileReset
au!
au CursorMovedI <buffer> call <SID>LookupFileSet()
au CursorMoved <buffer> call <SID>LookupFileSet()
au WinEnter <buffer> call <SID>LookupFileSet()
au TabEnter <buffer> call <SID>LookupFileSet()
au WinEnter * call <SID>LookupFileReset(0)
au TabEnter * call <SID>LookupFileReset(0)
au CursorMoved * call <SID>LookupFileReset(0)
" Better be safe than sorry.
au BufHidden <buffer> call <SID>LookupFileReset(1)
aug END
endfunction
function! lookupfile#CloseWindow()
if bufnr('%') != s:myBufNum
return
endif
call s:LookupFileReset(1)
close
endfunction
function! lookupfile#ClearCache()
let g:lookupfile#lastPattern = ""
let g:lookupfile#lastResults = []
endfunction
function! s:LookupFileSet()
if bufnr('%') != s:myBufNum || exists('s:_backspace')
return
endif
let s:_backspace = &backspace
set backspace=start
let s:_completeopt = &completeopt
set completeopt+=menuone
let s:_updatetime = &updatetime
let &updatetime = g:LookupFile_UpdateTime
endfunction
function! s:LookupFileReset(force)
if a:force
aug LookupFileReset
au!
aug END
endif
" Ignore the event while in the same buffer.
if exists('s:_backspace') && (a:force || (bufnr('%') != s:myBufNum))
let &backspace = s:_backspace
let &completeopt = s:_completeopt
let &updatetime = s:_updatetime
unlet s:_backspace s:_completeopt s:_updatetime
endif
endfunction
function! s:HidePopup()
let s:popupIsHidden = 1
return "\<C-E>"
endfunction
function! lookupfile#IsPopupHidden()
return s:popupIsHidden
endfunction
function! s:SetupBuf()
call genutils#SetupScratchBuffer()
resize 1
setlocal wrap
setlocal bufhidden=hide
setlocal winfixheight
setlocal wrapmargin=0
setlocal textwidth=0
setlocal completefunc=lookupfile#Complete
syn clear
set ft=lookupfile
" Setup maps to open the file.
inoremap <silent> <buffer> <expr> <C-E> <SID>HidePopup()
inoremap <silent> <buffer> <expr> <CR> <SID>AcceptFile(0, "\<CR>")
inoremap <silent> <buffer> <expr> <C-O> <SID>AcceptFile(1, "\<C-O>")
" This prevents the "Whole line completion" from getting triggered with <BS>,
" however this might make the dropdown kind of flash.
inoremap <buffer> <expr> <BS> pumvisible()?"\<C-E>\<BS>":"\<BS>"
inoremap <buffer> <expr> <S-BS> pumvisible()?"\<C-E>\<BS>":"\<BS>"
" Make <C-Y> behave just like <CR>
imap <buffer> <C-Y> <CR>
if g:LookupFile_EscCancelsPopup
inoremap <buffer> <expr> <Esc> pumvisible()?"\<C-E>\<C-C>":"\<Esc>"
endif
inoremap <buffer> <expr> <silent> <Down> <SID>GetCommand(1, 1, "\<C-N>",
\ "\"\\<Lt>C-N>\"")
inoremap <buffer> <expr> <silent> <Up> <SID>GetCommand(1, 1, "\<C-P>",
\ "\"\\<Lt>C-P>\"")
inoremap <buffer> <expr> <silent> <PageDown> <SID>GetCommand(1, 0,
\ "\<PageDown>", '')
inoremap <buffer> <expr> <silent> <PageUp> <SID>GetCommand(1, 0,
\ "\<PageUp>", '')
nnoremap <silent> <buffer> o :OpenFile<CR>
nnoremap <silent> <buffer> O :OpenFile!<CR>
command! -buffer -nargs=0 -bang OpenFile
\ :call <SID>OpenCurFile('<bang>' != '')
command! -buffer -nargs=0 -bang AddPattern :call <SID>AddPattern()
nnoremap <buffer> <silent> <Plug>LookupFile :call lookupfile#CloseWindow()<CR>
inoremap <buffer> <silent> <Plug>LookupFile <C-E><C-C>:call lookupfile#CloseWindow()<CR>
aug LookupFile
au!
if g:LookupFile_ShowFiller
exec 'au' (g:LookupFile_OnCursorMovedI ? 'CursorMovedI' : 'CursorHoldI')
\ '<buffer> call <SID>ShowFiller()'
endif
exec 'au' (g:LookupFile_OnCursorMovedI ? 'CursorMovedI' : 'CursorHoldI')
\ '<buffer> call lookupfile#LookupFile(0)'
aug END
endfunction
function! s:GetCommand(withPopupTrigger, withSkipPat, actCmd, innerCmd)
let cmd = ''
if a:withPopupTrigger && !pumvisible()
let cmd .= "\<C-X>\<C-U>"
endif
let cmd .= a:actCmd. "\<C-R>=(getline('.') == lookupfile#lastPattern) ? ".
\ a:innerCmd." : ''\<CR>"
return cmd
endfunction
function! s:AddPattern()
if g:LookupFile_PreservePatternHistory
silent! put! =g:lookupfile#lastPattern
$
endif
endfunction
function! s:AcceptFile(splitWin, key)
if s:popupIsHidden
return a:key
endif
if !pumvisible()
call lookupfile#LookupFile(0, 1)
endif
let acceptCmd = ''
if type(g:LookupFile_LookupAcceptFunc) == 2 ||
\ (type(g:LookupFile_LookupAcceptFunc) == 1 &&
\ substitute(g:LookupFile_LookupAcceptFunc, '\s', '', 'g') != '')
let acceptCmd = call(g:LookupFile_LookupAcceptFunc, [a:splitWin, a:key])
else
let acceptCmd = lookupfile#AcceptFile(a:splitWin, a:key)
endif
return (!pumvisible() ? "\<C-X>\<C-U>" : '').acceptCmd
endfunction
function! s:IsValid(fileName)
if bufnr('%') != s:myBufNum || a:fileName == ''
return 0
endif
if !filereadable(a:fileName) && !isdirectory(a:fileName)
if g:LookupFile_AllowNewFiles
" Check if the parent directory exists, then we can create a new buffer
" (Ido feature)
let parent = fnamemodify(a:fileName, ':h')
if parent == '' || (parent != '' && !isdirectory(parent))
return 1
endif
endif
return 0
endif
return 1
endfunction
function! lookupfile#AcceptFile(splitWin, key)
if len(g:lookupfile#lastResults) == 0 && !s:IsValid(getline('.'))
return "\<C-O>:echohl ErrorMsg | echo 'No such file or directory' | echohl NONE\<CR>"
endif
" Skip the first match, which is essentially the same as pattern.
let nextCmd = "\<C-N>\<C-R>=(getline('.') == lookupfile#lastPattern)?\"\\<C-N>\":''\<CR>"
let acceptCmd = "\<C-Y>\<Esc>:AddPattern\<CR>:OpenFile".(a:splitWin?'!':'').
\ "\<CR>"
if getline('.') ==# g:lookupfile#lastPattern
if len(g:lookupfile#lastResults) == 0
" FIXME: shouldn't this be an error?
let acceptCmd = acceptCmd
elseif len(g:lookupfile#lastResults) == 1 || g:LookupFile_AlwaysAcceptFirst
" If there is only one file, we will also select it (if not already
" selected)
let acceptCmd = nextCmd.acceptCmd
else
let acceptCmd = nextCmd
endif
endif
return acceptCmd
endfunction
function! s:OpenCurFile(splitWin)
let fileName = getline('.')
if fileName =~ '^\s*$'
return
endif
if !s:IsValid(fileName)
echohl ErrorMsg | echo 'No such file or directory' | echohl NONE
endif
if type(g:LookupFile_LookupNotifyFunc) == 2 ||
\ (type(g:LookupFile_LookupNotifyFunc) == 1 &&
\ substitute(g:LookupFile_LookupNotifyFunc, '\s', '', 'g') != '')
call call(g:LookupFile_LookupNotifyFunc, [])
endif
call lookupfile#CloseWindow()
" Update the recent files list.
if g:LookupFile_RecentFileListSize > 0
let curPos = index(g:lookupfile#recentFiles, fileName)
call add(g:lookupfile#recentFiles, fileName)
if curPos != -1
call remove(g:lookupfile#recentFiles, curPos)
elseif len(g:lookupfile#recentFiles) > g:LookupFile_RecentFileListSize
let g:lookupfile#recentFiles = g:lookupfile#recentFiles[
\ -g:LookupFile_RecentFileListSize :]
endif
endif
let bufnr = genutils#FindBufferForName(fileName)
let winnr = bufwinnr(bufnr)
if winnr == -1 && g:LookupFile_SearchForBufsInTabs
for i in range(tabpagenr('$'))
if index(tabpagebuflist(i+1), bufnr) != -1
" Switch to the tab and set winnr.
exec 'tabnext' (i+1)
let winnr = bufwinnr(bufnr)
endif
endfor
endif
if winnr != -1
exec winnr.'wincmd w'
else
let splitOpen = 0
if &switchbuf ==# 'split' || a:splitWin
let splitOpen = 1
endif
" First try opening as a buffer, if it fails, we will open as a file.
try
if bufnr == -1
throw ''
endif
exec (splitOpen?'s':'').'buffer' bufnr
catch /^Vim\%((\a\+)\)\=:E325/
" Ignore, this anyway means the file was found.
catch
try
exec (splitOpen?'split':'edit') fileName
catch /^Vim\%((\a\+)\)\=:E325/
" Ignore, this anyway means the file was found.
endtry
endtry
endif
endfunction
function! s:ShowFiller()
return lookupfile#LookupFile(1)
endfunction
function! lookupfile#Complete(findstart, base)
if a:findstart
return 0
else
call lookupfile#LookupFile(0, 1, a:base)
return g:lookupfile#lastStatsMsg+g:lookupfile#lastResults
endif
endfunction
function! lookupfile#LookupFile(showingFiller, ...)
let generateMode = (a:0 == 0 ? 0 : a:1)
if generateMode
let pattern = (a:0 > 1) ? a:2 : getline('.')
else
let pattern = getline('.')
" The normal completion behavior is to stop completion when cursor is moved.
if col('.') == 1 || (col('.') != col('$'))
return ''
endif
endif
if pattern == '' || (pattern ==# g:lookupfile#lastPattern && pumvisible())
return ''
endif
if s:popupIsHidden && g:lookupfile#lastPattern ==# pattern
return ''
endif
let s:popupIsHidden = 0
let statusMsg = ''
if pattern == ' '
if len(g:lookupfile#recentFiles) == 0
let statusMsg = '<<< No recent files >>>'
let files = []
else
let statusMsg = '<<< Showing '.len(g:lookupfile#recentFiles).' recent files >>>'
let files = reverse(copy(g:lookupfile#recentFiles))
endif
elseif strlen(pattern) < g:LookupFile_MinPatLength
let statusMsg = '<<< Type at least '.g:LookupFile_MinPatLength.
\ ' characters >>>'
let files = []
" We ignore filler when we have the result in hand.
elseif g:lookupfile#lastPattern ==# pattern
" This helps at every startup as we start with the previous pattern.
let files = g:lookupfile#lastResults
elseif a:showingFiller
" Just show a filler and return. We could return this as the only match, but
" unless 'completeopt' has "menuone", menu doesn't get shown.
let statusMsg = '<<< Looking up files... hit ^C to break >>>'
let files = []
else
if type(g:LookupFile_LookupFunc) == 2 ||
\ (type(g:LookupFile_LookupFunc) == 1 &&
\ substitute(g:LookupFile_LookupFunc, '\s', '', 'g') != '')
let files = call(g:LookupFile_LookupFunc, [pattern])
else
let _tags = &tags
try
let &tags = eval(g:LookupFile_TagExpr)
let taglist = taglist(g:LookupFile_TagsExpandCamelCase ?
\ lookupfile#ExpandCamelCase(pattern) : pattern)
catch
echohl ErrorMsg | echo "Exception: " . v:exception | echohl NONE
return ''
finally
let &tags = _tags
endtry
" Show the matches for what is typed so far.
if g:LookupFile_UsingSpecializedTags
let files = map(taglist, '{'.
\ '"word": fnamemodify(v:val["filename"], ":p"), '.
\ '"abbr": v:val["name"], '.
\ '"menu": fnamemodify(v:val["filename"], ":h"), '.
\ '"dup": 1, '.
\ '}')
else
let files = map(taglist, 'fnamemodify(v:val["filename"], ":p")')
endif
endif
let pat = g:LookupFile_FileFilter
if pat != ''
call filter(files, '(type(v:val) == 4) ? v:val["word"] !~ pat : v:val !~ pat')
endif
if g:LookupFile_SortMethod ==# 'alpha'
" When UsingSpecializedTags, sort by the actual name (Timothy, Guo
" (firemeteor dot guo at gmail dot com)).
if type(get(files, 0)) == 4
call sort(files, "s:CmpByName")
else
call sort(files)
endif
endif
let g:lookupfile#lastPattern = pattern
let g:lookupfile#lastResults = files
endif
if statusMsg == ''
if len(files) > 0
let statusMsg = '<<< '.len(files).' Matching >>>'
else
let statusMsg = '<<< None Matching >>>'
endif
endif
let msgLine = [{'word': pattern, 'abbr': statusMsg, 'menu': pattern}]
let g:lookupfile#lastStatsMsg = msgLine
if !generateMode
call complete(1, msgLine+files)
endif
return ''
endfunction
function! lookupfile#ExpandCamelCase(str)
let pat = a:str
" Check if there are at least two consecutive uppercase letters to turn on
" the CamelCase expansion.
if match(a:str, '\u\u') != -1
let pat = '\C'.substitute(a:str, '\u\+',
\ '\=substitute(submatch(0), ".", '."'".'&\\U*'."'".', "g")', 'g')
let @*=pat
endif
return pat
endfunction
function! s:CmpByName(i1, i2)
let ileft = a:i1["abbr"]
let iright = a:i2["abbr"]
return ileft == iright ? 0 : ileft > iright ? 1 : -1
endfunc
" Restore cpo.
let &cpo = s:save_cpo
unlet s:save_cpo
" vim6:fdm=marker et sw=2

View File

@ -0,0 +1,765 @@
*lookupfile.txt* Lookup files using Vim7 ins-completion
Requires Vim 7.0
Last Change: 24-Aug-2007 @ 18:25
Author: Hari Krishna Dara (hari.vim at gmail dot com)
*lookupfile-introduction*
*lookupfile-plugin*
Lookupfile is a very simple approach to opening files by typing a pattern to
represent the file you are looking for, and selecting a file from the completion
dropdown to open in the current Vim session. It provides a consistent interface
to lookup files by various means (tags, path, buffers, external tools etc.). It
uses the new Vim7 insert-mode completion mechanism to show matching files. It
is a new tool
The default functionality of the plugin is to lookup filenames from the tag
files, by matching the pattern against tag names. However, using the standard
tags (generated by ctags) can be very slow at best, so it is recommended to use
specially generated tagfiles, that are meant only for finding the filenames. You
don't however need to generate tag files at all to use the plugin, as there are
ways to lookup files from sources other than tag files.
==============================================================================
OVERVIEW *lookupfile-overview*
|lookupfile-installation| Installing the plugin.
|lookupfile-usage| A brief usage to get you quickly started.
|lookupfile-maps| Mappings defined in the lookup window.
|lookupfile-tags| Creating index of files for a fast lookup.
|lookupfile-settings| An explanation of various configure options.
|lookupfile-extend| Features that make the plugin extensible.
|lookupfile-known-issues| A list of known issues.
|lookupfile-wishlist| Wishlist items that may be worth doing for a future
version.
|lookupfile-changes| A change list for current version from the previous
versions.
|lookupfile-acknowledgements| Acknowledgements.
==============================================================================
*lookupfile-installation*
The distribution comes as a zipfile that can be extracted straight into your
runtime directory (vimfiles/.vim). Please note that it depends on genutils
plugin that needs to be downloaded separately and installed. Also note that
the version of genutils that this plugin depends on is a newer autoload
version that is not backwards compatible with the older versions of genutils.
This means, if you have other plugins that depend on the non-autoload version
of genutils, you need to follow special instructions given in genutils such
that you can have both installed at the same time.
To install the help file, you need to run :helptags command on your runtime
doc directory.
*lookupfile-map*
*lookupfile-default-cmd*
*LookupFile-command*
*:LookupFile*
Once installed, you can optionally choose a key to be used to open the
lookupfile window. The default is <F5>. To change this value, choose a key of
your liking, say <A-S-L>, and add the below line to your vimrc: >
nmap <unique> <silent> <A-S-L> <Plug>LookupFile
<
Note that the plugin creates a mapping for the insert-mode as well, so unless
you also explicitly specify a mapping for insert mode, the default <F5> will get
mapped to invoke lookupfile in the insert-mode. >
imap <unique> <silent> <A-S-L> <C-O><Plug>LookupFile
<
The <Plug>LookupFile mapping is mapped to the :LookupFile command, which always
assumes the last :LU command you use. This means, after using |:LUWalk|,
pressing <F5> would result in executing the :LUWalk command until you type
another command. Take a look at the |LookupFile_DefaultCmd| to specify the
initial command that this map should get assigned to and
|LookupFile_EnableRemapCmd| to disable this behavior. If you want a map to
always execute a specific command, you can also create additional maps. E.g.,
if you want <F7> to always execute :LUTags, irrespective of what command you
last used, then you can define something like:
>
nnoremap <silent> <F7> :LUTags<CR>
<
You can also disable the default map completely, see
|LookupFile_DisableDefaultMap| for details.
==============================================================================
*lookupfile-usage*
To lookup a file, press the assigned key (default: F5) or use the :LookupFile
command. This will open a small window above the current window, where you can
type in a regex, and the matching filenames will be shown in the Vim7 completion
style. Selecting a matching file and pressing Enter (<CR>) will open it in the
previous window (or ^O (C-O) will open it in a split window). You can also
press <Esc> and scroll back to previous filenames to press o or O (or use
:OpenFile[!]) to open the file in the previous window or a new window,
respectively.
If you want to quickly close the [Lookup File] window without making a file
selection, you can press the same key that you assigned to open the plugin, to
also cancel the completion menu and close the window.
Note that this works only when you use the <Plug> mapping to create a mapping
(see |lookupfile-map|), not when you assign a mapping directly while disablign
the default <Plug> mapping (see |LookupFile_DisableDefaultMap|).
Note that the completion menu will be shown only when you are in the insert
mode and the cursor is at the end of the line (this is the normal Vim behavior).
Here is a summary of all the commands that the plugin defines. All commands
accept the initial pattern as an argument, and support appropriate
|command-completion| mode.
Command Lookup source ~
LUTags Lookup files from tag files. This is a like a fast GNU
find on name. It can lookup files from any Vim
compatible tag file (which includes those from ctags),
but at the moment it is advisable to generate
specialized tag files using :find command (see
|lookupfile-tags|).
LUPath Lookup files from 'path' using |globpath()|. The :find
command while being able to lookup files from 'path', it
doesn't provide any completion mechanism, and it is
clumsy when there are multiple files with the same name.
The :find command doesn't even accept a pattern.
LUBufs Lookup loaded files (buffers) using |bufname()|. This is
a great addition to whatever buffer-explorer you are
using. When there are too many buffers open, this
sometimes makes it easy to find the right buffer, by
typing part of its name.
LUWalk Lookup files using |glob()|. This works like the Emacs
ido.el, allowing you to walk up and down a path looking
for files. If you use the filename completion with :edit
command, then you will find this a lot more convenient
and faster to use.
LUArgs Lookup files from |:args| list.
LookupFile A shortcut to the last command used from above set.
It is also very easy to add new commands to or customize the plugin at various
levels. At the simplest, you can create custom command on top of the above that
either pass dynamic arguments or tmporarily change the settings (e.g., you could
have a command that will start LUPath with the 'path' temporarily changed to
find only the include header files). You can also take advantage of the the
|lookupfile-extend| features to add new commands that lookup files from a
completely new source. You can even add commands that lookup something
completely different than a file (like e.g., a spelling using spellsuggest()).
The :LookupFile and all the above commands accept an argument which is treated
as the initial pattern. Specify a bang(!) after the command to always start with
an empty line.
*:LUTags*
*lookupfile-from-tags-files*
The LUTags command provides a fast lookup of files from tags files. This works
similar to the "Open Resource" command in eclipse where you can type part of the
name and all the resources whose name has matching part are shown for selection.
To use the :LUTags command, it is recommended to generate and maintain
separate tags files containing only filenames, for this plugin to work
efficiently (see |lookupfile-tags|). Though it will work with the regular tags
files, it could be very slow (due to the current performance of |taglist()| and
might not return the right set of filenames. Configure the tag expression such
that the plugin will use the right tag files. It is any valid Vim {rhs}, the
evaluated value should be a valid 'tags' value. For a static string, use extra
quotes. Ex:
>
let g:LookupFile_TagExpr = string('./filenametags')
< or >
let g:myLookupFileTagExpr = './filenanmetags'
let g:LookupFile_TagExpr = 'g:myLookupFileTagExpr'
<
Also see |LookupFile_UsingSpecializedTags| to enable better formatting of
results once these specialized tags are generated and lookupfile is configured
to take advantage of them.
*:LUPath*
*lookupfile-find-cmd-alternative*
The LUPath command is a complete replacement for the built-in |:find| command.
The completion popup alone is a good enough reason to use this command instead
of the :find, but since it also recognizes the 'ignorecase' and 'smartcase'
settings it makes it easier to type and still be able to do exact match when
required.
*lookupfile-ido*
The LUWalk and LUBufs commands are special in that they provide features that
will be very fimilar to those who used Emacs ido lisp package.
Similar to the ido, you can quickly switch from file lookup to buffer lookup
using <C-B> and from buffer lookup to file lookup using <C-F> while in insert
mode.
*:LUBufs*
*lookupfile-buffer-cmd-alternative*
LUBufs command allows you to quickly search the already loaded buffers for a
match and open it, so it can be used in the place of the built-in |:buffer|
command and provides the same matching semantics by default. Take a look at the
settings that start with "LookupFile_Bufs_" in their name to configure the
behavior of this command. The :LUBufs command also supports an initial pattern
as an arguments and supports filename completion.
A good use case for :LUBufs command is when you have several files named
similarly (e.g., having several buffers named Makefile or build.xml is very
common). Using a traditional buffer explorer plugin, finding the right file can
become cumbersome when you have a large set of buffers opened. In this case, the
:LUBufs command can help you locate the buffer much faster, as only the buffers
that match what you specify will be shown with their path clearly visible.
*:LUWalk*
*lookupfile-walk-path*
The LUWalk command is very useful to quickly navigate or "walk" filesystem
paths. The plugin provides a popup with matches for each path component as you
type in a partial string. The matches are based on the Vim |glob()| expression
rules. The :LUWalk command also accepts the initial directory name with or
without a pattern as an argument, and supports directory name completion.
When no root is specified, the match starts from the current directory.
Pressing <Tab> before typing in any pattern will result in inserting the
directory of the last file automatically. Type an extra "/" after a directory
name to have only the directories shown in the results.
To accept the first entry in the matches, you can simply press <CR> or <C-O>,
and if the entry happens to be a directory, new matches will be shown for that
directory.
*lookupfile-recent-files*
The plugin saves a list of most recently opened files using any of the above
commands. To trigger showing this list, simply use a space by itself. For more
details, see |LookupFile_RecentFileListSize|.
==============================================================================
*lookupfile-maps*
The maps that are available in the [Lookup File] window are listed below. Some
of them are the same from |popupmenu-keys|, but have been modified to behave
slightly differently. All the below maps are applicable only when the popup menu
is visible, otherwise, they should have their default behavior.
Key mode Action ~
<CR> i Opens the selected file in the previous window/
Select the first file.
<C-Y> i Same as <CR>
<C-O> i Same as <CR>, except that the file opens in a split
window.
<Down> i Selects next file. Same as |i_CTRL-N|.
<Up> i Selects previous file. Same as |i_CTRL-P|.
<PageDown> i Selects a file several entries down.
<PageUp> i Selects a file several entries up.
<Esc> i Stops completion and insert mode, and restores
pattern.
<BS> i Stops completion, restores pattern and executes
o n Opens the current file in the previous window.
O n Same as o, except the file opens in a split window.
==============================================================================
*lookupfile-tags*
Unless you want to lookup files from alternate sources such as 'path', you
should generate special tags files for the lookup from filesystem to work well.
It is very easy to generate a tag file for an efficient lookup of filenames.
If you have Unixy tools installed, you can run the below shell command to
generate a tags file (you can put it in a shell-script and schedule it to be run
every now and then to keep this file up to date) >
(echo "!_TAG_FILE_SORTED 2 /2=foldcase/";
(find . -type f -printf "%f\t%p\t1\n" | \
sort -f)) > ./filenametags
Typically you would want to exclude generated files such as .class and
.o. You can do this easily by specifying additional expressions to
the find command (see manpage for find command). E.g., replace the find
command above with: >
find . -not -iname "*.class" -type f -printf "%f\t%p\t1\n" \
< or, with something more useful: >
find . \( -name .svn -o -wholename ./classes \) -prune -o -not -iregex '.*\.\(jar\|gif\|jpg\|class\|exe\|dll\|pdd\|sw[op]\|xls\|doc\|pdf\|zip\|tar\|ico\|ear\|war\|dat\).*' -type f -printf "%f\t%p\t1\n" \
<
==============================================================================
*lookupfile-settings*
The settings are global variables that you can set in your vimrc. All settings
are optional, as they all have default values, but it is highly recommended that
you fine tune the g:LookupFile_TagExpr setting, as per |lookupfile-tags|.
*LookupFile_DefaultCmd*
- This specifies the |lookupfile-command| that should be invoked when the
|LookupFile-command| or |lookupfile-map| is used. This defaults to ":LUTags",
but you can change it to say, ":LUWalk". The :LookupFile command always
assumes the last command that you used, so this setting only specifies the
command to be invoked for the first time.
Ex: >
let g:LookupFile_DefaultCmd = ':LUWalk'
<
*LookupFile_EnableRemapCmd*
- When this is set (the default), the :LookupFile command takes the form of
the last command that is used. Disabling this while setting
|LookupFile_DefaultCmd| allows you to configure a custom command as the
command to run when you press the <Plug>LookupFile mapping. See
|LookupFile-command| for more details.
*LookupFile_DisableDefaultMap*
- Setting this flag turns off the default maps created by the plugin such that
the user has full control on what maps to what command. >
let g:LookupFile_DisableDefaultMap = 1
<
NOTE: setting this doesn't prevent the <Plug> mapping from created, try
setting no_lookupfile_maps or no_plugin_maps for this (see |usr_41.txt|).
*LookupFile_TagExpr*
- Use g:LookupFile_TagExpr to use custom tagfiles. A valid Vim expression
resulting in a String should be used, which means "eval(g:LookupFile_TagExpr)"
should return a valid value for 'tags' setting. Once you set a value for this
setting and startup Vim, try >
echo eval(g:LookupFile_TagExpr)
< to make sure it is valid. Ex: >
let g:LookupFile_TagExpr = string('./filenametags')
<
*LookupFile_MinPatLength*
- By default g:LookupFile_MinPatLength is set to 4, which means you have to type
at least 4 characters before the lookup is triggered. This is because the
current taglist() function is too slow if the tag file is large. Depending on
the number of files you have, you may be able to set a lower value (or may
even have to increase the value) for this setting.
*LookupFile_ShowFiller*
- If you don't want the filler to be shown while the tags are being
looked up, you can disable it by setting g:LookupFile_ShowFiller to 0. If you
know for sure that the lookup never takes too long, then disabling the filler
could make the completion menu less flashy.
*LookupFile_UsingSpecializedTags*
- When you generate specialized tags as described in the |lookupfile-tags|
section, you can set g:LookupFile_UsingSpecializedTags to enabled better
formatting for showing the results.
*LookupFile_PreservePatternHistory*
- By default, the plugin leaves a copy of the pattern that you used to
lookup the file, so that you can scroll-back and find them (this is like a
history), but you can disable this behavior by setting
g:LookupFile_PreservePatternHistory to 0.
*LookupFile_PreserveLastPattern*
- By default, the lookup window is started with the last pattern, which you can
remove by quick pressing <Ctrl-U>, but if you always want to start blank, set
g:LookupFile_PreserveLastPattern to 0.
*LookupFile_LookupFunc*
*LookupFile_LookupNotifyFunc*
*LookupFile_LookupAcceptFunc*
- If you want to lookup matches yourself using an alternative procedure, you
can specify a user function that should be called by the plugin, and
by-pass the default tag based lookup. Use g:LookupFile_LookupFunc
setting to specify the name or Funcref for such a function. The function
will be called with one argument, which is the pattern typed so far. The
results will be sorted by the plugin anyway, so your function need not.
You can also set g:LookupFile_LookupNotifyFunc to be notified when a
file is selected from the matches (not called with o or O commands), and
g:LookupFile_LookupAcceptFunc to override the default handling of selection.
*LookupFile_switchbuf*
- If you have 'switchbuf' set to "split" for your quickfix commands to
always split open windows, the plugin recognizes this setting and split-opens
all files.
*LookupFile_AlwaysAcceptFirst*
- Normally when <CR> or <C-O> is pressed while the popup is visible, the first
item in the list is selected, unless there is exactly only one item matching.
This means, if you want to select the first item, you have to press it
twice. You can change this behavior to always accept the first item by
setting g:LookupFile_AlwaysAcceptFirst (like ido.el).
*LookupFile_FileFilter*
- Use the g:LookupFile_FileFilter to specify a Vim regular expression pattern
that, when matched against the filename (or path, depending on the mode)
results in filtered out. E.x: >
" Don't display binary files
let g:LookupFile_FileFilter = '\.class$\|\.o$\|\.obj$\|\.exe$\|\.jar$\|\.zip$\|\.war$\|\.ear$'
<
NOTE that the |:LUPath| and |:LUWalk| commands use the Vim functions |globpath()|
and |glob()| that recognize the Vim setting 'wildignore', so setting this in
addition to 'wildignore' will have the matches filtered by both rules.
*LookupFile_AllowNewFiles*
- Use the g:LookupFile_AllowNewFiles to specify whether entering non-existent
files should generate an error or result in getting a new buffer created.
*LookupFile_ignorecase*
*LookupFile_smartcase*
- The plugin now recognizes 'ignorecase' and 'smartcase' settings to match files
even on systems that are case-sensitive. On unix like platforms, glob()
matches patterns in a case-sensitive manner, so setting 'ignorecase' will
enable special translation of patterns so that you get case-insensitive
results. On Windows, since glob() is already case-insensitive no special
handling is required for 'ignorecase', however, when 'smartcase' is set, there
is no way to force glob() to return case-sensitive results, so a
post-processing of the results is done to drop files that would not otherwise
have matched.
*LookupFile_SortMethod*
- Use this setting to specify the sort method to use for sorting results. The
default value is "alpha", which means that they will be sorted alphabatically.
You can also set an empty value to disable sorting. See also
|LookupFile_Bufs_BufListExpr| to enable MRU sorting for |:LUBufs| command.
*LookupFile_Bufs_BufListExpr*
- Use g:LookupFile_Bufs_BufListExpr to specify an expression that returns a
|List| of buffers to display. By default this is set to an empty string, but
you can set any valid Vim expression that results in a List. If you also have
the latest version of SelectBuf (http://www.vim.org/script.php?script_id=107)
installed, a useful value that you can set here is "g:SB_MRUlist", which will
then display buffers in the MRU order. >
let g:LookupFile_Bufs_BufListExpr = 'g:SB_MRUlist'
<
You can use this setting to even specify your own global function.
*LookupFile_Bufs_SkipUnlisted*
- By default, the |:LUBufs| commands skips all unlisted buffers from results,
but if you want them to be included, reset LookupFile_Bufs_SkipUnlisted
setting.
*LookupFile_Bufs_LikeBufCmd*
- This setting impacts the behavior of |:LUBufs| command on how the pattern is
matched. By default, it matches just like the |:buffer| command, so the
pattern is treated as per the rules of |wildcard| matching against the current
|bufname()| of each buffer. Clearing this setting will cause the command to
match the pattern as a Vim regex against only the filename portion of each
buffer.
*LookupFile_UpdateTime*
- LookupFile uses |CursorHoldI| autocommand to trigger the completion and this
event doesn't get triggered unless nothing is typed for 'updatetime'
milliseconds. Since the default value for 'updatetime' is rather large, the
plugin changes this value to g:LookupFile_UpdateTime (which defaults to 300
milliseconds or 3/10th of a second) while the [Lookup File] window is active.
*LookupFile_EscCancelsPopup*
- On some systems, the mapping for <Esc> to cancel the popup could interfere
with the arrow keys, so if you want the plugin to not map <Esc> key, then
reset |LookupFile_EscCancelsPopup| setting. >
let g:LookupFile_EscCancelsPopup = 0
<
*LookupFile_SearchForBufsInTabs*
- Normally, when you seleclt a file that is already visible in a window,
LookupFile simply makes that window the current window instead of opening
the file again. Setting this flag will make LookupFile also search in other
tabs for a window that already has this file visible, and switch to that tab
to set the focus. This setting is most useful with the |LUBufs| command. >
let g:LookupFile_SearchForBufsInTabs = 1
<
*LookupFile_TagsExpandCamelCase*
- When this setting is enabled (the default), typing consecutive upper case
letters are treated as abbreviations for type names that follow the
CamelCase naming pattern (like all the java class names are) and the pattern
is translated automatically. This is modelled after the "Open Type" dialog
in eclipse and works only for the tag lookup (|LUTags| command). To disable
this feature, set it to 0 >
let g:LookupFile_TagsExpandCamelCase = 0
<
Ex:
- To match the filename VimTheSupremeEditor.txt, you could enter the pattern
in several variations such as: >
VTSE
VTSEditor
VTSEdi.*
VTS.*
VTheSE
<
NOTE: While using the CamelCase expansion, 'ignorecase' is disabled so
something like "VTSEDi.*" will not match "VimTheSupremeEditor", but will match
"VimTheSupremeEditorDictator", if it exists.
*LookupFile_RecentFileListSize*
This setting allows you to control the number of most recently used filenames
that should be rememberd by the plugin. The default size is 20, but it can be
set to 0 to not remember any and any -ve value to remember all. The list is
not persisted across Vim sessions. >
let g:LookupFile_RecentFileListSize = 30
<
See also, |lookupfile-recent-files|.
==============================================================================
*lookupfile-extend*
If you want to extend the functionality of the plugin, by creating new commands
to lookup files in different ways, you can take advantage of the
g:LookupFile_LookupFunc and lookupfile_LookupNotifyFunc settings as below:
- Create a function that can take a pattern and return file matches for it:
function! FileMatches(pattern)
let matches = []
" Find and fill up matches.
return matches
endfunction
- Create an entry function and a command:
function! MyLookup()
unlet! s:savedLookupFunc s:savedLookupNotifyFunc
let g:savedLookupFunc = g:LookupFile_LookupFunc
let g:savedLookupNotifyFunc = g:LookupFile_LookupNotifyFunc
unlet g:LookupFile_LookupFunc g:LookupFile_LookupNotifyFunc
let g:LookupFile_LookupFunc = 'FileMatches'
let g:LookupFile_LookupNotifyFunc = 'MyNotify'
LookupFile
endfunction
command! MyLookup call MyLookup()
- Define the MyNotify() function to clear the settings.
function! MyNotify()
unlet g:LookupFile_LookupFunc g:LookupFile_LookupNotifyFunc
let g:LookupFile_LookupFunc = g:savedLookupFunc
let g:LookupFile_LookupNotifyFunc = g:savedLookupNotifyFunc
endfunction
Once you follow the above steps, you can use both the default LookupFile command
as well as the new MyLookup command. The completion will behave differently
based on how you opened the lookup window.
You can also override the default action when the user presses <CR> or <C-O> to
get your function invoked, by setting the g:LookupFile_LookupAcceptFunc. The
function should have the below signature: >
" splitWin is 1 if a new window should be split.
" key is the exact key that user pressed ("\<CR>"/"\<C-O>").
function accept(splitWin, key)
<
The last pattern and the matching results for it are accessible in the global
variables g:lookupfile#lastPattern and g:lookupfile#lastResults.
You can also create ftplugin/lookupfile.vim in your vim runtime and put commands
to further customize or override the behavior of the plugin. E.g., you could put
a map such that pressing <Esc> twice in succession will close the window: >
nnoremap <buffer> <Esc><Esc> <C-W>q
inoremap <buffer> <Esc><Esc> <Esc><C-W>q
<
*lookupfile-tips*
- A pattern is a Vim regex, so you can e.g., start with an "^" to anchor the
pattern match to the start of the filename. This will also speed up the
lookup. You can also enter the extension (such as \.prop) to narrow down the
results further.
- If the filename has special characters, don't forget to protect them while
entering the pattern, or you may not find what you are looking for (or
might find too much). E.g., to find a file named "abc*xyz" (not possible
on windows), you need to enter "abc\*" as pattern. Since the pattern is
used as if 'magic' is set, unless you have the "\" itself in the
filenames, you only have to worry about those characters that are special
without needing to prefix with a "\", and these are ".", "^", "[", "*" and
"$".
- If the lookup is taking too long, you can stop it by pressing ^C. You may
still be able to see partial set of matches.
- You can use <Ctrl-J> instead of <CR> to deliberately insert a newline into
the lookup buffer.
- Pressing <Esc> after selecting a file, results in restoring the pattern. If
you actually want to cancel the completion menu, without restoring the
pattern, you can press <C-C>.
- When you want to start entering a new pattern, press <Ctrl-U> to quickly
kill the previous pattern.
- Use g:LookupFile_LookupFunc setting to modify the functionality of the
plugin. The plugin/lookupfile.vim comes with a few of alternative ways to
lookup files, such as looking up files from 'path' (see |lookupfile-usage|).
Other ideas for alternative lookup for files are:
- Use id-utils' lid to lookup files from ID database. You can e.g., use the
command "lid -R filenames -S newline -k token" to lookup for the typed
pattern as a token (there are other options for lid to treat token as regex)
- Use GNU find to find files matching the pattern, something like:
"find . -name '*pattern*'". There are a number of options for find, so this
could be made very flexible, but running find for every character typed
could be very slow.
- You can create an alternate tags file to store only directory names such
that you can lookup directory names instead of filenames. The following
command can create such a tags file: >
(echo "!_TAG_FILE_SORTED 2 /2=foldcase/";
find . -type d -printf "%f\t%p\t1\n") | \
sort -f > ./dirnametags
<
Note that this generates tag file with relative paths, which is known to
cause problem with |taglist()| function when the tag file is not in the same
directory as Vim's current directory (see |lookupfile-known-issues|. To
workaround, you can generate absolute paths, you can use "`pwd`" instead of "."
as the root.
- You can create custom commands/mappings that always start with a fixed or
computed pattern. E.g., to always start LUWalk in the root of c: drive, create
a command as: >
command! WalkRoot LUWalk c:/
<
Another useful variation of the above is to start with the directory of the
current file: >
command! WalkCur :exec "LUWalk" expand('%:p:h').'/'
<
Another example that works well with :LookupFile is to start with the current
word as pattern: >
command! CurWord :LookupFile <cword>
<
- The :LUWalk command maps your <BS> key such that it will remove a complete
directory component at a time (like ido.el). To remove only a part of the
directory name, first press <C-W> to remove the "/" and use <BS> to remove the
required number characters. You can also press <Esc> and use normal commands
to edit.
- While using :LUWalk, when no pattern is entered yet, you can press <Tab> to
show the files in the directory of the current buffer.
- While using :LUWalk, you can enter "**" after any directory in the path to
match keyword recursively under that path.
- If you want to extend the funcationality of the plugin, take a look at the
plugin/lookupfile.vim for various examples.
- Here is a sample function that you can use to lookup spellings as you type,
using spellsuggest() function. You need to first turn on 'spell' inside
lookup window for this to work. >
function! s:LookupSpell(pattern)
return spellsuggest(a:pattern)
endfunction
<
This is a dummy accept function that prevents the word from being treated as a
file and open it: >
function! s:SpellAccept(splitWin, key)
call input('SpellAccept')
endfunction
<
==============================================================================
*lookupfile-known-issues*
- Vim sometimes automatically replaces the pattern with the first filename
from the completion menu. You have to select back the original pattern using
^P.
- The taglist() function's performance (on which this plugin depends on)
seems to be bad. A newer version of Vim might accept additional arguments
for taglist() to limit the number of matches, which can speed up some of
the cases.
- If you press the <Plug>LookupFile key while making a file selection, the
completion doesn't get aborted, but instead it gets selected and the
[Lookup File] window still remains open.
- There is a bug in taglist() that returns incorrect relative paths if the
current directory of Vim is not the same as the directory in which tags file
resides. This impacts the :LookupFile command. If this is an issue for you,
you should generate the tag files with absolute paths instead of relative
paths, by giving absolute directory names.
==============================================================================
*lookupfile-wishlist*
- Allow on the fly filtering of the filenames by prompting the user for a
pattern to match (or not match) against the whole filename.
- Option to sort filenames by their extension, or by MRU.
- Save and restore matching results, for patterns that take a long time to build
(especially those that involve "**").
- Option to have separate window/buffers for each type of command (Timothy,
Guo)
==============================================================================
*lookupfile-changes*
*lookupfile-changes-1.8*
- New settings |LookupFile_EnableRemapCmd|, |LookupFile_SearchForBufsInTabs|,
|LookupFile_TagsExpandCamelCase|, |Lookupfile_RecentFileListSize|.
- Even more control on the mappings with the new setting
|LookupFile_EnableRemapCmd|.
- New feature to specify names that follow CamelCasing pattern by abbreviating
them. This works more or less like for the "Open Type" dialog in Eclipse.
For more information see, |LookupFile_TagsExpandCamelCase|.
- New feature to remember the recent files, see
|Lookupfile_RecentFileListSize|.
- Changed the message line such that the message is shown on the left side and
the pattern is shown on the right side. This prevents the more important
message from getting lost when the filenames are too long.
*lookupfile-changes-1.7*
- Bug fix: LUPath and LUArgs were broken (stoning at gmail dot com).
- Removed debugging code.
*lookupfile-changes-1.6*
*lookupfile-changes-1.5*
- LookupFile now uses CursorHoldI instead of CursorMovedI to show matches. This
means, the matches are not computed until you stop typing, which should give a
better experience. See |LookupFile_UpdateTime| for more information.
- The plugin now sets 'completefunc' such that you can now hit <C-X><C-U> to
trigger completions explicitly (instead of waiting for
g:LookupFile_UpdateTime). This is useful if you are a slow typer and so prefer
a large value for g:LookupFile_UpdateTime.
- The plugin now recognizes 'ignorecase' and 'smartcase' settings to match files
even on systems that are case-sensitive. This is mainly significant for the
commands that use |globpath()| or |glob()| which are, |:LUPath| and |:LUWalk|,
as the others already respect these settings.
- There is now a separate command called :LUTags that always does what
:LookupFile used to do, while the :LookupFile command itself now gets
dynamically assigned to the last command used. This also means, the map that
is choosen in |lookupfile-map| now invokes the last command that is used, use
|LookupFile_DefaultCmd| and |LookupFile_DisableDefaultMap| settings to control
this behavior.
- LUWalk now supports showing only directory names in the results. Just type
an extra / to filter those that are not directories (the suffix will then be
two slashes).
- The default behavior of |:LUBufs| is now to match the entire |bufname()|,
just like the |:buffer| command would do. To see the old behavior, reset
|LookupFile_Bufs_LikeBufCmd| setting.
- If you have the new version of SelectBuf also installed, you can have
|:LUBufs| sort buffers in MRU order. See, |LookupFile_Bufs_BufListExpr|.
- When tags file is not generated as per the requirements of |lookupfile-tags|,
the format of the matches doesn't look good, so by default the matches just
show full filenames. See |LookupFile_UsingSpecializedTags| to get better
formatted results.
- New settings |LookupFile_UsingSpecializedTags|, |LookupFile_SortMethod|,
|LookupFile_DefaultCmd|, |LookupFile_DisableDefaultMap|,
|LookupFile_Bufs_LikeBufCmd|, |LookupFile_Bufs_BufListExpr|,
|LookupFile_EscCancelsPopup|.
- Bug fix: exact matches were getting dropped from results (Max Dyckhoff).
- Bug fix: <BS> in |:LUWalk| right after selecting a directory match caused it
to misbehave.
- Bug fix: if tags file is not in the current directory, the opening fails. Now
:LookupFile expands the filenames explicitly so that the paths are always
valid.
- Bug fix: Unsetting |LookupFile_AllowNewFiles| didn't disable the feature.
- Bug fix: <C-E> was not hiding the popup.
- Bug fix: <S-BS> triggers the default insert-mode completion (Max Dyckhoff).
- Fixed misc. bugs in opening files.
- Workaround for <Esc> not working on some systems, allow disabling the
mapping.
- Bug fix: When there is an exising swapfile, opening the files result in an
error message (David Fishburn).
- When LookupFile_UsingSpecializedTags is set, sorting should be done on the
filename (patch by Timothy, Guo).
*lookupfile-changes-1.4*
- Fixed a bug in the initial pattern getting ignored.
- LUBufs now completes the full pathname of the buffers, so that it is less
dependent on the current directory of Vim.
- LUBufs and LUPath commands now present the matches in a better format.
- Pressing <F5> while popup is visible didn't close the lookupfile window.
*lookupfile-changes-1.3*
- New feature to create a file, if the file doesn't already exist (Ido). Can be
disabled using g:LookupFile_AllowNewFiles setting.
- Bug fix: while using LUWalk, if the first match is a directory, then selecting
files was offset by one.
*lookupfile-changes-1.2*
- g:LookupFile_AlwaysAcceptFirst setting to always accept the first
entry (the default is 0).
- g:LookupFile_FileFilter to specify a filter.
- New LUWalk command that works very similar to Emacs ido.el to quickly navigate
paths.
- All commands now accepts the initial pattern as argument. This provides
unlimited number of possibilities to create your own custom commands (see
|lookupfile-tips| for some examples).
- The g:LookupFile_MinPatLength is automatically set to 0 except for tag and
'path' lookup.
- When Lookup window is opened, the filetype is set to "lookupfile". This allows
you to create ftplugins to fine tune the behavior.
- Renamed :LUBuf command to :LUBufs.
*lookupfile-changes-1.1*
- Added LUBuf and LUPath commands.
- Renamed the prefix for all the settings from g:lookupfile_ to g:LookupFile_.
This is required to support Funcref settings.
- Now the cursor position is preserved, while opening a file that is already
loaded.
- Using genutils 2.1.
==============================================================================
*lookupfile-acknowledgements*
- Max Dyckhoff (maxd at microsoft dot com) for beta testing and reporting
numerous issues and suggesting improvements etc. The plugin is a lot
more stable, thanks to him.
I would also like to specially thank him for proof reading the first version
of this documentation.
- Eddy Zhao (eddy dot y dot zhao at gmail dot com> for suggesting several
improvements on the lines of emacs ido.el and rigorously testing them. The
LUWalk command is the result of this.
- Eddy Zhao (eddy dot y dot zhao at gmail dot com> for suggesting several
- Dane Summers (dsummersl at yahoo dot com) for feedback and doc updates.
- Timothy, Guo (firemeteor dot guo at gmail dot com) for improving the sorting
and other feedback.
vim6:tw=80:ts=8:ft=help:ai:sw=4:et

View File

@ -0,0 +1,576 @@
" lookupfile.vim: Lookup filenames by pattern
" Author: Hari Krishna Dara (hari.vim at gmail dot com)
" Last Change: 14-Jun-2007 @ 18:30
" Created: 11-May-2006
" Requires: Vim-7.1, genutils.vim(2.3)
" Version: 1.8.0
" Licence: This program is free software; you can redistribute it and/or
" modify it under the terms of the GNU General Public License.
" See http://www.gnu.org/copyleft/gpl.txt
" Download From:
" http://www.vim.org//script.php?script_id=1581
" Usage:
" See :help lookupfile.txt
if exists('loaded_lookupfile')
finish
endif
if v:version < 701
echomsg 'lookupfile: You need at least Vim 7.1'
finish
endif
if !exists('loaded_genutils')
runtime plugin/genutils.vim
endif
if !exists('loaded_genutils') || loaded_genutils < 203
echomsg 'lookupfile: You need a newer version of genutils.vim plugin'
finish
endif
let g:loaded_lookupfile = 108
" Make sure line-continuations won't cause any problem. This will be restored
" at the end
let s:save_cpo = &cpo
set cpo&vim
if !exists('g:LookupFile_TagExpr')
let g:LookupFile_TagExpr = '&tags'
endif
if !exists('g:LookupFile_LookupFunc')
let g:LookupFile_LookupFunc = ''
endif
if !exists('g:LookupFile_LookupNotifyFunc')
let g:LookupFile_LookupNotifyFunc = ''
endif
if !exists('g:LookupFile_LookupAcceptFunc')
let g:LookupFile_LookupAcceptFunc = ''
endif
if !exists('g:LookupFile_MinPatLength')
let g:LookupFile_MinPatLength = 4
endif
if !exists('g:LookupFile_PreservePatternHistory')
let g:LookupFile_PreservePatternHistory = 1
endif
if !exists('g:LookupFile_PreserveLastPattern')
let g:LookupFile_PreserveLastPattern = 1
endif
if !exists('g:LookupFile_ShowFiller')
let g:LookupFile_ShowFiller = 1
endif
if !exists('g:LookupFile_AlwaysAcceptFirst')
let g:LookupFile_AlwaysAcceptFirst = 0
endif
if !exists('g:LookupFile_FileFilter')
let g:LookupFile_FileFilter = ''
endif
if !exists('g:LookupFile_AllowNewFiles')
let g:LookupFile_AllowNewFiles = 1
endif
if !exists('g:LookupFile_SortMethod')
let g:LookupFile_SortMethod = 'alpha'
endif
if !exists('g:LookupFile_Bufs_BufListExpr')
let g:LookupFile_Bufs_BufListExpr = ''
endif
if !exists('g:LookupFile_Bufs_SkipUnlisted')
let g:LookupFile_Bufs_SkipUnlisted = 1
endif
if !exists('g:LookupFile_Bufs_LikeBufCmd')
let g:LookupFile_Bufs_LikeBufCmd = 1
endif
if !exists('g:LookupFile_UsingSpecializedTags')
let g:LookupFile_UsingSpecializedTags = 0
endif
if !exists('g:LookupFile_DefaultCmd')
let g:LookupFile_DefaultCmd = ':LUTags'
endif
if !exists('g:LookupFile_EnableRemapCmd')
let g:LookupFile_EnableRemapCmd = 1
endif
if !exists('g:LookupFile_DisableDefaultMap')
let g:LookupFile_DisableDefaultMap = 0
endif
if !exists('g:LookupFile_UpdateTime')
let g:LookupFile_UpdateTime = 300
endif
if !exists('g:LookupFile_OnCursorMovedI')
let g:LookupFile_OnCursorMovedI = 0
endif
if !exists('g:LookupFile_EscCancelsPopup')
let g:LookupFile_EscCancelsPopup = 1
endif
if !exists('g:LookupFile_SearchForBufsInTabs')
let g:LookupFile_SearchForBufsInTabs = 1
endif
if !exists('g:LookupFile_TagsExpandCamelCase')
let g:LookupFile_TagsExpandCamelCase = 1
endif
if !exists('g:LookupFile_RecentFileListSize')
let g:LookupFile_RecentFileListSize = 20
endif
if (! exists("no_plugin_maps") || ! no_plugin_maps) &&
\ (! exists("no_lookupfile_maps") || ! no_lookupfile_maps)
noremap <script> <silent> <Plug>LookupFile :LookupFile<CR>
if ! g:LookupFile_DisableDefaultMap
if !hasmapto('<Plug>LookupFile', 'n')
nmap <unique> <silent> <F5> <Plug>LookupFile
endif
if !hasmapto('<Plug>LookupFile', 'i')
inoremap <Plug>LookupFileCE <C-E>
imap <unique> <expr> <silent> <F5> (pumvisible() ? "\<Plug>LookupFileCE" :
\ "")."\<Esc>\<Plug>LookupFile"
endif
endif
endif
command! -nargs=? -bang -complete=file LookupFile :call
\ <SID>LookupUsing('lookupfile', "<bang>", <q-args>, 0)
command! -nargs=? -bang -complete=tag LUTags :call
\ <SID>LookupUsing('Tags', "<bang>", <q-args>, 0)
command! -nargs=? -bang -complete=file LUPath :call
\ <SID>LookupUsing('Path', "<bang>", <q-args>, g:LookupFile_MinPatLength)
command! -nargs=? -bang -complete=file LUArgs :call
\ <SID>LookupUsing('Args', "<bang>", <q-args>, 0)
command! -nargs=? -bang -complete=file LUBufs :call
\ <SID>LookupUsing('Bufs', "<bang>", <q-args>, 0)
command! -nargs=? -bang -complete=dir LUWalk :call
\ <SID>LookupUsing('Walk', "<bang>", <q-args>, 0)
function! s:RemapLookupFile(cmd)
let cmd = (a:cmd != '') ? a:cmd : ':LUTags'
" It is not straight-forward to determine the right completion method.
exec 'command! -nargs=? -bang -complete=file LookupFile' cmd
endfunction
call s:RemapLookupFile(g:LookupFile_DefaultCmd)
let s:mySNR = ''
function! s:SNR()
if s:mySNR == ''
let s:mySNR = matchstr(expand('<sfile>'), '<SNR>\d\+_\zeSNR$')
endif
return s:mySNR
endfun
let s:baseBufNr = 0
function! s:LookupUsing(ftr, bang, initPat, minPatLen)
let cmd = ':LUTags'
if a:ftr != 'Tags'
call s:SaveSett('LookupFunc')
call s:SaveSett('LookupNotifyFunc')
call s:SaveSett('MinPatLength')
unlet! g:LookupFile_LookupFunc g:LookupFile_LookupNotifyFunc
let g:LookupFile_LookupFunc = function(s:SNR().'Lookup'.a:ftr)
let g:LookupFile_LookupNotifyFunc = function(s:SNR().'LookupReset')
let g:LookupFile_MinPatLength = a:minPatLen
let s:baseBufNr = bufnr('%')
let cmd = ':LU'.a:ftr
endif
if g:LookupFile_EnableRemapCmd
call s:RemapLookupFile(cmd)
endif
call lookupfile#OpenWindow(a:bang, a:initPat)
if exists('*s:Config'.a:ftr)
call s:Config{a:ftr}()
endif
aug LookupReset
au!
au BufHidden <buffer> call <SID>LookupReset()
aug END
endfunction
function! s:LookupReset()
if exists('s:saved')
for sett in keys(s:saved)
unlet! g:LookupFile_{sett}
let g:LookupFile_{sett} = s:saved[sett]
endfor
unlet s:saved
endif
if exists('s:cleanup')
for cmd in s:cleanup
try
exec cmd
catch
echoerr v:exception . ', while executing cleanup command: ' . cmd
endtry
endfor
unlet s:cleanup
endif
aug ConfigIdo
au!
aug END
endfunction
function! s:SaveSett(sett)
if !exists('s:saved')
let s:saved = {}
endif
" Avoid overwriting the original value.
if !has_key(s:saved, a:sett)
let s:saved[a:sett] = g:LookupFile_{a:sett}
endif
endfunction
function! s:AddCleanup(cmd)
if !exists('s:cleanup')
let s:cleanup = []
endif
if index(s:cleanup, a:cmd) == -1
call add(s:cleanup, a:cmd)
endif
endfunction
function! s:LookupPath(pattern)
let filePat = a:pattern
let matchingExactCase = s:MatchingExactCase(filePat)
" Remove leading or trailing '*'s as we add a star anyway. This also removes
" '**' unless it is followed by a slash.
let filePat = substitute(filePat, '^\*\+\|\*\+$', '', 'g')
" On windows, the case is anyway ignored.
if !genutils#OnMS() && !matchingExactCase
let filePat = s:FilePatIgnoreCase(filePat)
endif
let fl = split(globpath(&path, (filePat != '') ? '*'.filePat.'*' : '*'),
\ "\n")
let regexPat = s:TranslateFileRegex(filePat)
" This is a psuedo case-sensitive match for windows, when 'smartcase' is
" set.
if genutils#OnMS() && matchingExactCase
set verbose=15
call filter(fl, 'v:val =~# regexPat')
set verbose=0
endif
return map(fl,
\ '{'.
\ ' "word": v:val,'.
\ ' "abbr": fnamemodify(v:val, ":t"), '.
\ ' "menu": fnamemodify(v:val, ":h"), '.
\ ' "dup": 1'.
\ '}')
endfunction
function! s:LookupArgs(pattern)
return map(filter(argv(), 'v:val =~ a:pattern'),
\ '{'.
\ ' "word":fnamemodify(v:val, ":p"), '.
\ ' "abbr": v:val, '.
\ ' "menu": substitute(v:val, a:pattern, "[&]", ""), '.
\ ' "dup": 1'.
\ '}')
endfunction
let s:bufList = [1]
function! s:LookupBufs(pattern)
let results = []
if g:LookupFile_Bufs_BufListExpr != ''
let buflist = eval(g:LookupFile_Bufs_BufListExpr)
else
" Since we need to generate the same range again and again, it is better to
" cache the list.
if s:bufList[-1] != bufnr('$')
call extend(s:bufList, range(s:bufList[-1], bufnr('$')))
endif
let buflist = s:bufList
endif
let lastBufNr = bufnr('$')
let i = 1
if g:LookupFile_Bufs_LikeBufCmd
let pattern = s:TranslateFileRegex(a:pattern)
else
let pattern = a:pattern
endif
for bufNr in buflist
if ! bufexists(bufNr)
call remove(buflist, i)
continue
endif
try
if g:LookupFile_Bufs_SkipUnlisted && ! buflisted(bufNr)
continue
endif
let fname = expand('#'.bufNr.':p')
if g:LookupFile_Bufs_LikeBufCmd
let bname = bufname(bufNr)
let dir = ''
else
let bname = fnamemodify(bufname(bufNr), ':t')
let dir = fnamemodify(bufname(bufNr), ':h').'/'
endif
if bname =~ pattern
call add(results, {
\ 'word': fname,
\ 'abbr': bname,
\ 'menu': dir.substitute(bname, pattern, '[&]', ''),
\ 'dup': 1,
\ })
endif
finally
let i = i + 1
endtry
endfor
return results
endfunction
function! s:LookupWalk(pattern)
" We will wait till '/' is typed
if a:pattern =~ '\*\*$'
return []
endif
let showOnlyDirs = 0
" Determine the parent dir.
if a:pattern =~ '//$'
let parent = strpart(a:pattern, 0, strlen(a:pattern)-1)
let filePat = ''
if parent ==# g:lookupfile#lastPattern
return filter(g:lookupfile#lastResults, 'v:val["kind"] == "/"')
endif
let showOnlyDirs = 1
else
let parent = matchstr(a:pattern, '^.*/')
let filePat = strpart(a:pattern, len(parent))
endif
let matchingExactCase = s:MatchingExactCase(filePat)
" Remove leading or trailing '*'s as we add a star anyway. This also makes
" '**' as '', but we rule this case out already.
let filePat = substitute(filePat, '^\*\+\|\*\+$', '', 'g')
" On windows, the case is anyway ignored.
if !genutils#OnMS() && !matchingExactCase
let filePat = s:FilePatIgnoreCase(filePat)
endif
"exec BPBreak(1)
let _shellslash = &shellslash
set shellslash
try
let files = glob(parent.((filePat != '') ? '*'.filePat.'*' : '*'))
catch
" Ignore errors in patterns.
let files = ''
finally
let &shellslash = _shellslash
endtry
let fl = split(files, "\<NL>")
let regexPat = s:TranslateFileRegex(filePat)
" This is a psuedo case-sensitive match for windows, when 'smartcase' is
" set.
if genutils#OnMS() && matchingExactCase
call filter(fl, 'fnamemodify(v:val, ":t") =~# regexPat')
endif
" Find the start of path component that uses any of the *, [], ? or {
" wildcard. Path until this is unambiguously common to all, so we can strip
" it off, for brevity.
let firstWildIdx = match(a:pattern, '[^/]*\%(\*\|\[\|?\|{\)')
return s:FormatFileResults(fl, firstWildIdx!=-1 ? firstWildIdx :
\ strlen(parent), regexPat, matchingExactCase, showOnlyDirs)
endfunction
function! s:FormatFileResults(fl, parentLen, matchPat, matchingCase, dirsOnly)
let entries = []
for f in a:fl
if isdirectory(f)
let suffx = '/'
else
if a:dirsOnly
continue
endif
let suffx = ''
endif
let word = f.suffx
let fname = matchstr(f, '[^/]*$')
let dir = fnamemodify(f, ':h').'/'
if dir != '/' && a:parentLen != -1
let dir = strpart(dir, a:parentLen)
else
let dir = ''
endif
"let dir = (dir == '/'?'':dir)
call add(entries, {
\ 'word': word,
\ 'abbr': fname.suffx,
\ 'menu': (a:matchPat!='') ? dir.substitute(fname,
\ (a:matchingCase?'\C':'\c').a:matchPat, '[&]', '') :
\ dir.fname,
\ 'kind': suffx,
\ 'dup': 1
\ })
endfor
return entries
endfunction
function! s:ConfigBufs()
" Allow switching to file mode.
inoremap <expr> <buffer> <C-F> <SID>IdoSwitchTo('file')
call s:AddCleanup('iunmap <buffer> <C-F>')
if g:LookupFile_Bufs_BufListExpr != ''
call s:SaveSett('SortMethod')
let g:LookupFile_SortMethod = ''
endif
endfunction
function! s:ConfigWalk()
call s:SaveSett('LookupAcceptFunc')
unlet! g:LookupFile_LookupAcceptFunc
let g:LookupFile_LookupAcceptFunc = function(s:SNR().'IdoAccept')
" Make sure we have the right slashes, in case user passed in init path
" with wrong slashes.
call setline('.', substitute(getline('.'), '\\', '/', 'g'))
inoremap <buffer> <expr> <BS> <SID>IdoBS()
inoremap <buffer> <expr> <S-BS> <SID>IdoBS()
call s:AddCleanup('iunmap <buffer> <BS>')
imap <buffer> <expr> <Tab> <SID>IdoTab()
call s:AddCleanup('iunmap <buffer> <Tab>')
inoremap <expr> <buffer> <C-B> <SID>IdoSwitchTo('buffer')
call s:AddCleanup('iunmap <buffer> <C-B>')
endfunction
function! s:IdoSwitchTo(mode)
call s:LookupReset()
if a:mode == 'buffer'
let tok = matchstr(getline('.'), '[^/]*$')
let cmd = 'LUBufs'.(tok == "" ? '!' : ' '.tok)
else
let cmd = 'LUWalk '.s:GetDefDir().getline('.')
endif
return (pumvisible()?"\<C-E>":'')."\<Esc>:".cmd."\<CR>"
endfunction
function! s:IdoAccept(splitWin, key)
let refreshCmd = "\<C-O>:call lookupfile#LookupFile(0)\<CR>\<C-O>:\<BS>"
if getline('.') !=# g:lookupfile#lastPattern && getline('.')[strlen(getline('.'))-1] == '/'
return refreshCmd
elseif getline('.') ==# g:lookupfile#lastPattern
\ && len(g:lookupfile#lastResults) > 0
\ && g:lookupfile#lastResults[0]['kind'] == '/'
" When the first entry is a directory, accept it, and trigger a fresh
" completion on that.
return "\<C-N>\<C-R>=(getline('.') == lookupfile#lastPattern)?\"\\<C-N>\":''\<CR>".refreshCmd
endif
return lookupfile#AcceptFile(a:splitWin, a:key)
endfunction
function! s:IdoBS()
if lookupfile#IsPopupHidden() == 1
return "\<BS>"
endif
if getline('.') !~ '/$'
return (pumvisible() ? "\<C-E>" : '')."\<BS>"
else
" Determine the number of <BS>'s required to remove the patch component.
let lastComp = matchstr(getline('.'), '[^/]*/$')
return (pumvisible() ? (getline('.') ==# g:lookupfile#lastPattern ?
\ "\<C-E>" : "\<C-Y>") : '') . repeat("\<BS>", strlen(lastComp))
endif
endfunction
function! s:IdoTab()
" When no pattern yet, fill up with current directory.
if !pumvisible() && getline('.') == ''
return s:GetDefDir()
else
return "\<Tab>"
endif
endfunction
function! s:GetDefDir()
return substitute(expand('#'.s:baseBufNr.':p:h'), '\\', '/', 'g').'/'
endfunction
" Convert file wildcards ("*", "?" etc. |file-pattern|) to a Vim string
" regex metachars (see |pattern.txt|). Returns metachars that work in "very
" nomagic" mode.
let s:fileWild = {}
function! s:TranslateFileWild(fileWild)
let strRegex = ''
if a:fileWild ==# '*'
let strRegex = '\[^/]\*'
elseif a:fileWild ==# '**'
let strRegex = '\.\*'
elseif a:fileWild ==# '?'
let strRegex = '\.'
elseif a:fileWild ==# '['
let strRegex = '\['
endif
return strRegex
endfunction
" Convert a |file-pattern| to a Vim string regex (see |pattern.txt|).
" No error checks for now, for simplicity.
function! s:TranslateFileRegex(filePat)
let pat = substitute(a:filePat, '\(\*\*\|\*\|\[\)',
\ '\=s:TranslateFileWild(submatch(1))', 'g')
let unprotectedMeta = genutils#CrUnProtectedCharsPattern('?,', 1)
let pat = substitute(pat, unprotectedMeta,
\ '\=s:TranslateFileWild(submatch(1))', 'g')
return (pat == '') ? pat : '\V'.pat
endfunction
" Translates the file pattern to ignore case on non-case-insensitive systems.
function! s:FilePatIgnoreCase(filePat)
return substitute(a:filePat, '\(\[.\{-}]\)\|\(\a\)',
\ '\=s:TranslateAlpha(submatch(0))', 'g')
endfunction
function! s:TranslateAlpha(pat)
if a:pat =~"^["
return substitute(substitute(a:pat, '-\@<!\a-\@!', '&\u&', 'g'),
\ '\(\a\)-\(\a\)', '\1-\2\u\1-\u\2', 'g')
else
return substitute(a:pat, '\a', '[\l&\u&]', 'g')
endif
endfunction
function! s:MatchingExactCase(filePat)
if &ignorecase
if &smartcase && a:filePat =~# '\u'
let matchingExactCase = 1
else
let matchingExactCase = 0
endif
else
if genutils#OnMS()
let matchingExactCase = 0
else
let matchingExactCase = 1
endif
endif
return matchingExactCase
endfunction
" Restore cpo.
let &cpo = s:save_cpo
unlet s:save_cpo
" vim6:fdm=marker et sw=2