Support user extensions

* Search for and perform actions on anything you want, not just files, buffers and MRU.
  Check out the 'extensions' branch for more details and how-to.
* <F5> now also removes deleted files from MRU list.
* Slight sorting change.
This commit is contained in:
Kien N 2011-10-23 17:38:03 +07:00
parent b44a699d22
commit 0319703514
5 changed files with 175 additions and 110 deletions

View File

@ -3,7 +3,7 @@
" Description: Full path fuzzy file, buffer and MRU file finder for Vim.
" Author: Kien Nguyen <github.com/kien>
" License: MIT
" Version: 1.5.5
" Version: 1.5.6
" =============================================================================
if v:version < '700' "{{{
@ -16,6 +16,7 @@ func! s:opts()
\ 'g:ctrlp_by_filename' : ['s:byfname', 0],
\ 'g:ctrlp_clear_cache_on_exit' : ['s:cconex', 1],
\ 'g:ctrlp_dotfiles' : ['s:dotfiles', 1],
\ 'g:ctrlp_extensions' : ['s:extensions', []],
\ 'g:ctrlp_highlight_match' : ['s:mathi', [1, 'Identifier']],
\ 'g:ctrlp_jump_to_buffer' : ['s:jmptobuf', 1],
\ 'g:ctrlp_match_window_bottom' : ['s:mwbottom', 1],
@ -57,6 +58,12 @@ func! s:opts()
let s:maxhst = g:ctrlp_max_history
unl g:ctrlp_max_history
endif
let s:mru = g:ctrlp_mru_files
if !empty(s:extensions)
for each in s:extensions
exe 'ru autoload/ctrlp/'.each.'.vim'
endfor
endif
endfunc
cal s:opts()
@ -74,7 +81,7 @@ endfunc
func! ctrlp#clearallcaches()
let cache_dir = ctrlp#utils#cachedir()
if isdirectory(cache_dir) && match(cache_dir, '.ctrlp_cache') >= 0
let cache_files = split(globpath(cache_dir, '*.txt'), '\n')
let cache_files = split(globpath(cache_dir, '*.txt', 1), '\n')
cal filter(cache_files, '!isdirectory(v:val)')
for each in cache_files | sil! cal delete(each) | endfor
endif
@ -84,7 +91,7 @@ endfunc
func! ctrlp#reset()
cal s:opts()
cal ctrlp#utils#opts()
if g:ctrlp_mru_files | cal ctrlp#mrufiles#opts() | endif
if s:mru | cal ctrlp#mrufiles#opts() | endif
" Clear user input
let s:prompt = ['','','']
unl! s:cline
@ -269,18 +276,18 @@ func! s:Open(name)
let s:winnr = bufwinnr('%')
let s:bufnr = bufnr('%')
" Store global options
let s:CtrlP_magic = &magic
let s:CtrlP_to = &to
let s:CtrlP_tm = &tm
let s:CtrlP_sb = &sb
let s:CtrlP_hls = &hls
let s:CtrlP_im = &im
let s:CtrlP_report = &report
let s:CtrlP_sc = &sc
let s:CtrlP_ss = &ss
let s:CtrlP_siso = &siso
let s:CtrlP_mfd = &mfd
let s:CtrlP_gcr = &gcr
let s:glb_magic = &magic
let s:glb_to = &to
let s:glb_tm = &tm
let s:glb_sb = &sb
let s:glb_hls = &hls
let s:glb_im = &im
let s:glb_report = &report
let s:glb_sc = &sc
let s:glb_ss = &ss
let s:glb_siso = &siso
let s:glb_mfd = &mfd
let s:glb_gcr = &gcr
let s:prompt = ['', '', '']
if !exists('s:hstry')
let hst = filereadable(s:gethistloc()[1]) ? s:gethistdata() : ['']
@ -307,18 +314,18 @@ endfunc
func! s:Close()
try | bun! | catch | clo! | endtry
" Restore global options
let &magic = s:CtrlP_magic
let &to = s:CtrlP_to
let &tm = s:CtrlP_tm
let &sb = s:CtrlP_sb
let &hls = s:CtrlP_hls
let &im = s:CtrlP_im
let &report = s:CtrlP_report
let &sc = s:CtrlP_sc
let &ss = s:CtrlP_ss
let &siso = s:CtrlP_siso
let &mfd = s:CtrlP_mfd
let &gcr = s:CtrlP_gcr
let &magic = s:glb_magic
let &to = s:glb_to
let &tm = s:glb_tm
let &sb = s:glb_sb
let &hls = s:glb_hls
let &im = s:glb_im
let &report = s:glb_report
let &sc = s:glb_sc
let &ss = s:glb_ss
let &siso = s:glb_siso
let &mfd = s:glb_mfd
let &gcr = s:glb_gcr
" Cleaning up
cal s:unmarksigns()
let g:ctrlp_lines = []
@ -344,8 +351,8 @@ func! s:Renderer(lines, pat) "{{{
" Output to buffer
if !empty(nls)
setl cul
" Sort if not type 2 (MRU)
if index([2], s:itemtype) < 0
" Sort if not MRU
if ( s:mru && s:itemtype != 2 ) || !s:mru
let s:compat = a:pat
cal sort(nls, 's:mixedsort')
unl s:compat
@ -650,9 +657,14 @@ func! s:PrtSelectJump(char,...)
endfunc
func! s:PrtClearCache()
if s:itemtype == 0
cal ctrlp#clearcache()
cal s:SetLines(s:itemtype)
cal s:BuildPrompt(1)
elseif s:mru && s:itemtype == 2
let g:ctrlp_lines = ctrlp#mrufiles#list(-1, 1)
cal s:BuildPrompt(1)
endif
endfunc
func! s:PrtExit()
@ -782,8 +794,9 @@ func! s:ToggleByFname()
endfunc
func! s:ToggleType(dir)
let len = 1 + g:ctrlp_mru_files
let s:itemtype = s:walker(len, s:itemtype, a:dir)
let ext = exists('g:ctrlp_ext_vars') ? len(g:ctrlp_ext_vars) : 0
let max = 1 + s:mru + ext
let s:itemtype = s:walker(max, s:itemtype, a:dir)
cal s:Type(s:itemtype)
endfunc
@ -827,12 +840,12 @@ func! ctrlp#SetWorkingPath(...)
sil! exe 'chd!' a:1
retu
endif
if match(expand('%:p'), '^\<.\+\>://.*') >= 0
if match(expand('%:p', 1), '^\<.\+\>://.*') >= 0
\ || !s:pathmode || !l:pathmode
retu
endif
if exists('+acd') | let &acd = 0 | endif
let path = expand('%:p:h')
let path = expand('%:p:h', 1)
let path = exists('*fnameescape') ? fnameescape(path) : escape(path, '%#')
sil! exe 'chd!' path
if s:pathmode == 1 || l:pathmode == 1 | retu | endif
@ -849,35 +862,16 @@ func! ctrlp#SetWorkingPath(...)
endif
for marker in markers
let found = s:FindRoot(getcwd(), marker, 0, 0)
if getcwd() != expand('%:p:h') || found | break | endif
if getcwd() != expand('%:p:h', 1) || found | break | endif
endfor
endfunc
"}}}
func! s:AcceptSelection(mode,...) "{{{
let [md, prt] = [a:mode, s:prompt]
let str = prt[0] . prt[1] . prt[2]
if md == 'e' && !s:itemtype
if str == '..'
" Walk backward the dir tree
cal s:parentdir(getcwd())
cal s:SetLines(s:itemtype)
cal s:PrtClear()
retu
elseif str == '?'
" Use ? for help
cal s:PrtExit()
let hlpwin = &columns > 159 ? '| vert res 80' : ''
exe 'bo vert h ctrlp-mappings' hlpwin '| norm! 0'
retu
endif
endif
" * AcceptSelection {{{
func! ctrlp#acceptfile(mode, matchstr)
let [md, matchstr] = [a:mode, a:matchstr]
" Get the full path
let matchstr = matchstr(getline('.'), '^> \zs.\+\ze\t*$')
if empty(matchstr) | retu | endif
let filpath = s:itemtype ? matchstr : getcwd().s:lash.matchstr
" If only need the full path
if exists('a:1') && a:1 | retu filpath | endif
cal s:PrtExit()
let bufnum = bufnr(filpath)
let norwins = s:normbuf()
@ -894,7 +888,6 @@ func! s:AcceptSelection(mode,...) "{{{
endif
" Switch to existing buffer or open new one
let filpath = escape(filpath, '%#')
" If the file's already opened
if exists('jmpb') && buftab[0] " In a tab
exe 'norm!' buftab[1].'gt'
exe buftab[0].'winc w'
@ -909,7 +902,7 @@ func! s:AcceptSelection(mode,...) "{{{
let cmd = 'new'
elseif md == 'v' || s:splitwin == 3 " In new ver split
let cmd = 'vne'
elseif md == 'e'
else
let cmd = 'e'
" If there's at least 1 normal buffer
if norwin
@ -930,8 +923,41 @@ func! s:AcceptSelection(mode,...) "{{{
if !empty('tail')
sil! norm! zOzz
endif
endfunc
func! s:AcceptSelection(mode)
if a:mode == 'e'
let prt = s:prompt
let str = prt[0] . prt[1] . prt[2]
if str == '..' && !s:itemtype
" Walk backward the dir tree
cal s:parentdir(getcwd())
cal s:SetLines(s:itemtype)
cal s:PrtClear()
retu
elseif str == '?'
" Use ? for help
cal s:PrtExit()
let hlpwin = &columns > 159 ? '| vert res 80' : ''
sil! exe 'bo vert h ctrlp-mappings' hlpwin '| norm! 0'
retu
endif
endif
" Get the selected line
let matchstr = matchstr(getline('.'), '^> \zs.\+\ze\t*$')
if empty(matchstr) | retu | endif
" Branch it
let rhs = s:mru ? '0\|1\|2' : '0\|1'
if s:itemtype =~ rhs
cal ctrlp#acceptfile(a:mode, matchstr)
else
let id = s:itemtype - 2 - s:mru
let acpt_func = g:ctrlp_ext_vars[id][1]
cal call(acpt_func, [a:mode, matchstr])
endif
ec
endfunc "}}}
endfunc
"}}}
" ** Helper functions {{{
" Sorting {{{
@ -969,7 +995,6 @@ func! s:matchlens(str, pat, ...)
let lens = exists('a:2') ? a:2 : {}
let nr = exists('a:3') ? a:3 : 0
if match(a:str, a:pat, st) != -1
let start = match(a:str, a:pat, st)
let str = matchstr(a:str, a:pat, st)
let len = len(str)
let end = matchend(a:str, a:pat, st)
@ -999,27 +1024,38 @@ endfunc
func! s:mixedsort(s1, s2)
let cmatlen = s:compmatlen(a:s1, a:s2)
let ctime = s:comptime(a:s1, a:s2)
let clen = s:complen(a:s1, a:s2)
let rhs = s:mru ? '0\|1\|2' : '0\|1'
if s:itemtype =~ rhs
let ctime = s:comptime(a:s1, a:s2)
let cword = s:compword(a:s1, a:s2)
retu 3 * cmatlen + 3 * ctime + 2 * clen + cword
let mxsrt = 6 * cmatlen + 3 * ctime + 2 * clen + cword
else
let mxsrt = 2 * cmatlen + clen
endif
retu mxsrt
endfunc
"}}}
" Statusline {{{
func! s:statusline(...)
let itemtypes = [
let types = [
\ ['files', 'fil'],
\ ['buffers', 'buf'],
\ ['mru files', 'mru'],
\ ]
if !g:ctrlp_mru_files
cal remove(itemtypes, 2)
if !s:mru
cal remove(types, 2)
endif
let max = len(itemtypes) - 1
let next = itemtypes[s:walker(max, s:itemtype, 1, 1)][1]
let prev = itemtypes[s:walker(max, s:itemtype, -1, 1)][1]
let item = itemtypes[s:itemtype][0]
if exists('g:ctrlp_ext_vars')
for each in g:ctrlp_ext_vars
cal add(types, [ each[2], each[3] ])
endfor
endif
let max = len(types) - 1
let next = types[s:walker(max, s:itemtype, 1)][1]
let prev = types[s:walker(max, s:itemtype, -1)][1]
let item = types[s:itemtype][0]
let focus = s:Focus() ? 'prt' : 'win'
let byfname = s:byfname ? 'file' : 'path'
let regex = s:regexp ? '%#LineNr# regex %*' : ''
@ -1077,7 +1113,7 @@ endfunc
func! s:listdirs(path,parent)
let str = ''
for entry in filter(split(globpath(a:path, '*'), '\n'), 'isdirectory(v:val)')
for entry in filter(split(globpath(a:path, '*', 1), '\n'), 'isdirectory(v:val)')
let str .= a:parent.split(entry, '[\/]')[-1] . "\n"
endfor
retu str
@ -1241,6 +1277,10 @@ endfunc
"}}}
" Misc {{{
func! ctrlp#exit()
cal s:PrtExit()
endfunc
func! s:openfile(cmd)
try
exe a:cmd
@ -1251,16 +1291,12 @@ func! s:openfile(cmd)
endtry
endfunc
func! s:walker(max, pos, dir, ...)
if a:dir == 1
func! s:walker(max, pos, dir)
if a:dir > 0
let pos = a:pos < a:max ? a:pos + 1 : 0
elseif a:dir == -1
else
let pos = a:pos > 0 ? a:pos - 1 : a:max
endif
if !g:ctrlp_mru_files && pos == 2 && !exists('a:1')
let jmp = pos == a:max ? 0 : 3
let pos = a:pos == 1 ? jmp : 1
endif
retu pos
endfunc
@ -1336,6 +1372,14 @@ func! s:SetLines(type)
\ 's:ListAllBuffers()',
\ 'ctrlp#mrufiles#list(-1)',
\ ]
if !s:mru
cal remove(types, 2)
endif
if exists('g:ctrlp_ext_vars')
for each in g:ctrlp_ext_vars
cal add(types, each[0])
endfor
endif
let g:ctrlp_lines = eval(types[a:type])
endfunc

View File

@ -17,14 +17,12 @@ func! ctrlp#mrufiles#opts()
let s:max = g:ctrlp_mruf_max
unl g:ctrlp_mruf_max
endif
if !exists('g:ctrlp_mruf_include')
let s:include = ''
else
let s:include = g:ctrlp_mruf_include
unl g:ctrlp_mruf_include
endif
if !exists('g:ctrlp_mruf_exclude')
let s:exclude = ''
else
@ -35,38 +33,53 @@ endfunc
cal ctrlp#mrufiles#opts()
"}}}
func! ctrlp#mrufiles#list(bufnr) "{{{
func! ctrlp#mrufiles#list(bufnr,...) "{{{
if s:locked | retu | endif
" get the list
let cache_dir = ctrlp#utils#cachedir().ctrlp#utils#lash().'mru'
let cache_file = cache_dir.ctrlp#utils#lash().'cache.txt'
let mrufiles = ctrlp#utils#readfile(cache_file)
let cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'mru'
let cafile = cadir.ctrlp#utils#lash().'cache.txt'
let mrufs = ctrlp#utils#readfile(cafile)
" remove non-existent files
if exists('a:1')
let mrufs = s:clearnonexists(mrufs, cadir, cafile)
endif
" return the list
if a:bufnr == -1 | retu mrufiles | endif
if a:bufnr == -1 | retu mrufs | endif
" filter it
let filename = fnamemodify(bufname(a:bufnr + 0), ':p')
if empty(filename) || !empty(&bt)
\ || ( !empty(s:include) && filename !~# s:include )
\ || ( !empty(s:exclude) && filename =~# s:exclude )
\ || ( index(mrufiles, filename) == -1 && !filereadable(filename) )
\ || ( index(mrufs, filename) == -1 && !filereadable(filename) )
retu
endif
" remove old matched entry
cal filter(mrufiles, 'v:val !=# filename')
cal filter(mrufs, 'v:val !=# filename')
" insert new one
cal insert(mrufiles, filename)
cal insert(mrufs, filename)
" remove oldest entry
if len(mrufiles) > s:max
cal remove(mrufiles, s:max, -1)
if len(mrufs) > s:max
cal remove(mrufs, s:max, -1)
endif
cal ctrlp#utils#writecache(mrufiles, cache_dir, cache_file)
cal ctrlp#utils#writecache(mrufs, cadir, cafile)
endfunc "}}}
func! s:clearnonexists(mrufs, cadir, cafile) "{{{
let mrufs = a:mrufs
for each in range(len(mrufs) - 1, 0, -1)
if empty(glob(mrufs[each], 1))
cal remove(mrufs, each)
endif
endfor
cal ctrlp#utils#writecache(mrufs, a:cadir, a:cafile)
retu mrufs
endfunc "}}}
func! ctrlp#mrufiles#init() "{{{
let s:locked = 0
aug CtrlPMRUF
au!
au BufReadPost,BufNewFile,BufWritePost * cal ctrlp#mrufiles#list(expand('<abuf>'))
au BufReadPost,BufNewFile,BufWritePost * cal ctrlp#mrufiles#list(expand('<abuf>', 1))
au QuickFixCmdPre *vimgrep* let s:locked = 1
au QuickFixCmdPost *vimgrep* let s:locked = 0
aug END

View File

@ -20,7 +20,7 @@ endfunc
cal ctrlp#utils#opts()
"}}}
" Files and Directories functions {{{
" Files and Directories {{{
func! ctrlp#utils#cachedir()
retu exists('*mkdir') ? s:cache_dir.ctrlp#utils#lash().'.ctrlp_cache' : s:cache_dir
endfunc
@ -63,9 +63,7 @@ func! ctrlp#utils#writecache(lines,...)
endif
endif
endfunc
"}}}
" Generic functions {{{
func! ctrlp#utils#lash()
retu &ssl || !exists('+ssl') ? '/' : '\'
endfunc

View File

@ -1,4 +1,4 @@
*ctrlp.txt* Full path fuzzy file, buffer and MRU file finder. v1.5.5
*ctrlp.txt* Full path fuzzy file, buffer and MRU file finder. v1.5.6
*CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'*
===============================================================================
# #
@ -119,7 +119,7 @@ Set this to 0 to disable per-session caching. When disabled, caching will still
be enabled for directories that have more than 4000 files: >
let g:ctrlp_use_caching = 1
<
Note: you can quickly purge the cache by pressing <F5>.
Note: you can quickly purge the cache by pressing <F5> while inside |CtrlP|.
*'g:ctrlp_clear_cache_on_exit'*
Set this to 0 to enable cross-sessions caching by not deleting the caches upon
@ -258,7 +258,7 @@ pressing <c-y>:
1 - in a new tab
2 - in a new horizontal split
3 - in a new vertical split
0 - in the current window/split
0 - in the current window
>
let g:ctrlp_open_new_file = 3
<
@ -461,7 +461,7 @@ d) Type exactly two dots (..) at the start of the line and press enter to go
backward in the directory tree by 1 level. If the parent directory is
large, this might be slow.
e) Type the name of a non-existed file and press <c-y> to create it.
e) Type the name of a non-existent file and press <c-y> to create it.
e.g. 'parentdir/file.txt' will create a directory named 'parentdir' as well
as 'file.txt'. Use '\' in place of '/' on Windows (if |'ssl'| is not set).
@ -485,9 +485,17 @@ Homepage: http://kien.github.com/ctrlp.vim
Git repository: https://github.com/kien/ctrlp.vim
Mercurial repository: https://bitbucket.org/kien/ctrlp.vim
===============================================================================
THANKS
Thanks to everyone that has submitted ideas, bug reports, helped debugging or
coming up with solutions on gibhub, bitbucket, and through email.
===============================================================================
CHANGELOG
+ New feature: Add support for user-made extensions.
<F5> now removes non-existent files from MRU list.
+ New option: |g:ctrlp_jump_to_buffer|
Before 2011/10/12
@ -503,7 +511,7 @@ Before 2011/10/12
Before 2011/09/29
+ New mappings: <c-n>, <c-p> next/prev string in the input history.
<c-y> create new file and its parent dirs.
<c-y> create a new file and its parent dirs.
+ New options: |g:ctrlp_open_new_file|,
|g:ctrlp_max_history|
+ Added a new open-in-horizontal-split mapping: <c-x>

View File

@ -5,6 +5,7 @@ Full path fuzzy __file__, __buffer__ and __MRU__ file finder for Vim.
* Full support for Vims regexp as search pattern.
* Built-in Most Recently Used (MRU) files monitoring.
* Built-in projects root finder.
* CtrlP is [extensible][2].
![ctrlp][1]
@ -80,3 +81,4 @@ _Check [the docs][2] for more mappings, commands and options._
[1]: http://i.imgur.com/3rtLt.png
[2]: https://github.com/kien/ctrlp.vim/blob/master/doc/ctrlp.txt
[3]: https://github.com/kien/ctrlp.vim/tree/extensions