Skip to content
Browse files

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.
  • Loading branch information...
1 parent b44a699 commit 0319703514482feaca31faa4f278a2a9370f9aaa @kien committed
Showing with 175 additions and 110 deletions.
  1. +132 −88 autoload/ctrlp.vim
  2. +27 −14 autoload/ctrlp/mrufiles.vim
  3. +1 −3 autoload/ctrlp/utils.vim
  4. +13 −5 doc/ctrlp.txt
  5. +2 −0 readme.md
View
220 autoload/ctrlp.vim
@@ -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()
- cal ctrlp#clearcache()
- cal s:SetLines(s:itemtype)
- cal s:BuildPrompt(1)
+ 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,12 +995,11 @@ 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)
- let lens = extend(lens, { nr : [len, str] })
- let lens = s:matchlens(a:str, a:pat, end, lens, nr + 1)
+ let str = matchstr(a:str, a:pat, st)
+ let len = len(str)
+ let end = matchend(a:str, a:pat, st)
+ let lens = extend(lens, { nr : [len, str] })
+ let lens = s:matchlens(a:str, a:pat, end, lens, nr + 1)
endif
retu lens
endfunc
@@ -988,7 +1013,7 @@ func! s:shortest(lens)
endfunc
func! s:wordonly(lens)
- let lens = a:lens
+ let lens = a:lens
let minln = s:shortest(lens)
cal filter(lens, 'minln == v:val[0]')
for nr in keys(lens)
@@ -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 cword = s:compword(a:s1, a:s2)
- retu 3 * cmatlen + 3 * ctime + 2 * clen + cword
+ 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)
+ 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
41 autoload/ctrlp/mrufiles.vim
@@ -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
4 autoload/ctrlp/utils.vim
@@ -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
18 doc/ctrlp.txt
@@ -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).
@@ -486,8 +486,16 @@ 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
2 readme.md
@@ -5,6 +5,7 @@ Full path fuzzy __file__, __buffer__ and __MRU__ file finder for Vim.
* Full support for Vim’s regexp as search pattern.
* Built-in Most Recently Used (MRU) files monitoring.
* Built-in project’s 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

0 comments on commit 0319703

Please sign in to comment.
Something went wrong with that request. Please try again.