Open Multiple Files

Use <c-z> to mark/unmark files and <c-o> to open them. You can enter new input strings and continue to mark more files. The list of marked files will be cleared upon exiting CtrlP.
This commit is contained in:
Kien N 2011-10-03 03:04:43 +07:00
parent e47d7c3947
commit 1a2c3ee8d2
3 changed files with 286 additions and 214 deletions

View File

@ -3,161 +3,58 @@
" Description: Full path fuzzy file, buffer and MRU file finder for Vim. " Description: Full path fuzzy file, buffer and MRU file finder for Vim.
" Author: Kien Nguyen <github.com/kien> " Author: Kien Nguyen <github.com/kien>
" License: MIT " License: MIT
" Version: 1.5
" ============================================================================= " =============================================================================
if v:version < '700' "{{{ if v:version < '700' "{{{
func! ctrlp#init(...)
echoh Error | ec 'CtrlP requires Vim 7.0+' | echoh None
endfunc
fini fini
endif "}}} endif "}}}
" Option variables {{{ " Option variables {{{
func! s:opts() func! s:opts()
if !exists('g:ctrlp_match_window_reversed') let opts = {
let s:mwreverse = 1 \ 'g:ctrlp_match_window_reversed' : ['s:mwreverse', 1],
else \ 'g:ctrlp_persistent_input' : ['s:pinput', 0],
let s:mwreverse = g:ctrlp_match_window_reversed \ 'g:ctrlp_split_window' : ['s:splitwin', 0],
unl g:ctrlp_match_window_reversed \ 'g:ctrlp_working_path_mode' : ['s:pathmode', 1],
endif \ 'g:ctrlp_root_markers' : ['s:rmarkers', []],
\ 'g:ctrlp_max_height' : ['s:mxheight', 10],
if !exists('g:ctrlp_persistent_input') \ 'g:ctrlp_regexp_search' : ['s:regexp', 0],
let s:pinput = 0 \ 'g:ctrlp_use_caching' : ['s:caching', 1],
else \ 'g:ctrlp_clear_cache_on_exit' : ['s:cconex', 1],
let s:pinput = g:ctrlp_persistent_input \ 'g:ctrlp_by_filename' : ['s:byfname', 0],
unl g:ctrlp_persistent_input \ 'g:ctrlp_prompt_mappings' : ['s:urprtmaps', 0],
endif \ 'g:ctrlp_dotfiles' : ['s:dotfiles', 1],
\ 'g:ctrlp_highlight_match' : ['s:mathi', [1, 'Function']],
if !exists('g:ctrlp_split_window') \ 'g:ctrlp_max_files' : ['s:maxfiles', 20000],
let s:splitwin = 0 \ 'g:ctrlp_max_depth' : ['s:maxdepth', 40],
else \ 'g:ctrlp_live_update' : ['s:liup', 1],
let s:splitwin = g:ctrlp_split_window \ 'g:ctrlp_open_new_file' : ['s:newfop', 3],
unl g:ctrlp_split_window \ 'g:ctrlp_open_multi' : ['s:opmul', 1],
endif \ }
for key in keys(opts)
if !exists('g:ctrlp_ignore_space') if call('exists', [key])
let s:igspace = 0 let def = type(eval(key)) != 1 ? string(eval(key)) : eval(key)
else exe 'unl' key
let s:igspace = g:ctrlp_ignore_space else
unl g:ctrlp_ignore_space let def = type(opts[key][1]) != 1 ? string(opts[key][1]) : opts[key][1]
endif endif
exe 'let' opts[key][0] '=' def
if !exists('g:ctrlp_working_path_mode') endfor
let s:pathmode = 1
else
let s:pathmode = g:ctrlp_working_path_mode
unl g:ctrlp_working_path_mode
endif
if !exists('g:ctrlp_root_markers')
let s:rmarkers = []
else
let s:rmarkers = g:ctrlp_root_markers
unl g:ctrlp_root_markers
endif
if !exists('g:ctrlp_max_height')
let s:mxheight = 10
else
let s:mxheight = g:ctrlp_max_height
unl g:ctrlp_max_height
endif
if !exists('g:ctrlp_regexp_search')
let s:regexp = 0
else
let s:regexp = g:ctrlp_regexp_search
unl g:ctrlp_regexp_search
endif
if !exists('g:ctrlp_use_caching')
let s:caching = 1
else
let s:caching = g:ctrlp_use_caching
unl g:ctrlp_use_caching
endif
if !exists('g:ctrlp_clear_cache_on_exit')
let s:cconex = 1
else
let s:cconex = g:ctrlp_clear_cache_on_exit
unl g:ctrlp_clear_cache_on_exit
endif
if !exists('g:ctrlp_cache_dir') if !exists('g:ctrlp_cache_dir')
let s:cache_dir = $HOME let s:cache_dir = $HOME
else else
let s:cache_dir = g:ctrlp_cache_dir let s:cache_dir = g:ctrlp_cache_dir
endif endif
if !exists('g:ctrlp_newcache') if !exists('g:ctrlp_newcache')
let g:ctrlp_newcache = 0 let g:ctrlp_newcache = 0
endif endif
if !exists('g:ctrlp_by_filename')
let s:byfname = 0
else
let s:byfname = g:ctrlp_by_filename
unl g:ctrlp_by_filename
endif
if !exists('g:ctrlp_prompt_mappings')
let s:urprtmaps = 0
else
let s:urprtmaps = g:ctrlp_prompt_mappings
unl g:ctrlp_prompt_mappings
endif
if !exists('g:ctrlp_dotfiles')
let s:dotfiles = 1
else
let s:dotfiles = g:ctrlp_dotfiles
unl g:ctrlp_dotfiles
endif
if !exists('g:ctrlp_highlight_match')
let s:mathi = [1, 'Function']
else
let s:mathi = g:ctrlp_highlight_match
unl g:ctrlp_highlight_match
endif
if !exists('g:ctrlp_max_files')
let s:maxfiles = 20000
else
let s:maxfiles = g:ctrlp_max_files
unl g:ctrlp_max_files
endif
if !exists('g:ctrlp_max_depth')
let s:maxdepth = 40
else
let s:maxdepth = g:ctrlp_max_depth
unl g:ctrlp_max_depth
endif
if s:maxdepth > 200 if s:maxdepth > 200
let s:maxdepth = 200 let s:maxdepth = 200
endif endif
if !exists('g:ctrlp_live_update')
let s:liup = 1
else
let s:liup = g:ctrlp_live_update
unl g:ctrlp_live_update
endif
if !exists('g:ctrlp_user_command') if !exists('g:ctrlp_user_command')
let g:ctrlp_user_command = '' let g:ctrlp_user_command = ''
endif endif
if !exists('g:ctrlp_open_new_file')
let s:newfop = 3
else
let s:newfop = g:ctrlp_open_new_file
unl g:ctrlp_open_new_file
endif
if !exists('g:ctrlp_max_history') if !exists('g:ctrlp_max_history')
let s:maxhst = exists('+hi') ? &hi : 20 let s:maxhst = exists('+hi') ? &hi : 20
else else
@ -167,6 +64,8 @@ func! s:opts()
endfunc endfunc
cal s:opts() cal s:opts()
let s:lash = ctrlp#utils#lash()
" Limiters " Limiters
let s:compare_lim = 3000 let s:compare_lim = 3000
let s:nocache_lim = 4000 let s:nocache_lim = 4000
@ -273,18 +172,19 @@ func! s:ListAllBuffers() "{{{
endfunc "}}} endfunc "}}}
func! s:SplitPattern(str,...) "{{{ func! s:SplitPattern(str,...) "{{{
" Ignore spaces let str = a:str
let str = s:igspace ? substitute(a:str, ' ', '', 'g') : a:str " Restore the number of backslashes
" Clear the jumptoline var
unl! s:jmpln
" If pattern contains :\d (e.g. abc:25)
if match(str, ':\d*$') >= 0
" Get the line to jump to
let s:jmpln = matchstr(str, ':\zs\d*$')
" Remove the line number
let str = substitute(str, ':\d*$', '', 'g')
endif
let str = substitute(str, '\\\\', '\', 'g') let str = substitute(str, '\\\\', '\', 'g')
" Clear the tail var
unl! s:optail
" If pattern contains :str$
" e.g. abc:25, abc:/myclass or abc:++[opt] +[cmd]
if match(str, ':\([^:]\|\\:\)*$') >= 0
" Set the tail var
let s:optail = matchstr(str, ':\zs\([^:]\|\\:\)*$')
" Remove the tail
let str = substitute(str, ':\([^:]\|\\:\)*$', '', 'g')
endif
if s:regexp || match(str, '[*|]') >= 0 if s:regexp || match(str, '[*|]') >= 0
\ || match(str, '\\\(zs\|ze\|<\|>\)') >= 0 \ || match(str, '\\\(zs\|ze\|<\|>\)') >= 0
let array = [str] let array = [str]
@ -395,6 +295,9 @@ func! s:BufOpen(...) "{{{
let &gcr = s:CtrlP_gcr let &gcr = s:CtrlP_gcr
let &mfd = s:CtrlP_mfd let &mfd = s:CtrlP_mfd
" Cleaning up " Cleaning up
cal s:unmarksigns()
let g:ctrlp_lines = []
let g:ctrlp_allfiles = []
if s:pinput != 2 if s:pinput != 2
unl! g:CtrlP_cline unl! g:CtrlP_cline
endif endif
@ -402,18 +305,14 @@ func! s:BufOpen(...) "{{{
exe 'chd!' s:cwd exe 'chd!' s:cwd
unl s:cwd unl s:cwd
endif endif
unl! s:focus unl! s:focus s:firstinit s:hisidx s:hstgot s:marked s:bufnr
unl! s:firstinit
unl! s:hisidx
unl! s:hstgot
let g:ctrlp_lines = []
let g:ctrlp_allfiles = []
ec ec
else else
let s:currwin = winnr() let s:currwin = winnr()
" Open new buffer " Open new buffer
exe 'sil! bo 1new' buf exe 'sil! bo 1new' buf
let s:winnr = bufwinnr('%') let s:winnr = bufwinnr('%')
let s:bufnr = bufnr('%')
" Store global options " Store global options
let s:CtrlP_magic = &magic let s:CtrlP_magic = &magic
let s:CtrlP_to = &to let s:CtrlP_to = &to
@ -430,9 +329,9 @@ func! s:BufOpen(...) "{{{
if !s:pinput if !s:pinput
let g:CtrlP_prompt = ['', '', ''] let g:CtrlP_prompt = ['', '', '']
endif endif
if !exists('s:ctrlp_history') if !exists('s:hstry')
let s:ctrlp_history = filereadable(s:gethistloc()[1]) ? s:gethistdata() : [''] let hst = filereadable(s:gethistloc()[1]) ? s:gethistdata() : ['']
let s:ctrlp_history = empty(s:ctrlp_history) || !s:maxhst ? [''] : s:ctrlp_history let s:hstry = empty(hst) || !s:maxhst ? [''] : hst
endif endif
se magic se magic
se to se to
@ -446,10 +345,14 @@ func! s:BufOpen(...) "{{{
se siso=0 se siso=0
se mfd=200 se mfd=200
se gcr=a:block-PmenuSel-blinkon0 se gcr=a:block-PmenuSel-blinkon0
if s:opmul && has('signs')
sign define ctrlpmark text=+> texthl=Search
endif
endif endif
endfunc "}}} endfunc "}}}
func! s:Renderer(lines, pat) "{{{ func! s:Renderer(lines, pat) "{{{
cal s:unmarksigns()
let nls = [] let nls = []
for i in range(0, len(a:lines) - 1) for i in range(0, len(a:lines) - 1)
cal add(nls, '> '.a:lines[i]) cal add(nls, '> '.a:lines[i])
@ -478,6 +381,7 @@ func! s:Renderer(lines, pat) "{{{
endif endif
keepj norm! 1| keepj norm! 1|
let s:matched = nls let s:matched = nls
cal s:remarksigns(nls)
else else
setl nocul setl nocul
cal setline('1', ' == NO MATCHES ==') cal setline('1', ' == NO MATCHES ==')
@ -548,6 +452,7 @@ endfunc "}}}
func! s:CreateNewFile() "{{{ func! s:CreateNewFile() "{{{
let prt = g:CtrlP_prompt let prt = g:CtrlP_prompt
let str = prt[0] . prt[1] . prt[2] let str = prt[0] . prt[1] . prt[2]
if empty(str) | retu | endif
let arr = split(str, '[\/]') let arr = split(str, '[\/]')
cal map(arr, 'escape(v:val, "%#")') cal map(arr, 'escape(v:val, "%#")')
let fname = remove(arr, -1) let fname = remove(arr, -1)
@ -573,6 +478,79 @@ func! s:CreateNewFile() "{{{
cal s:insertcache(str) cal s:insertcache(str)
endfunc "}}} endfunc "}}}
" * OpenMulti {{{
func! s:MarkToOpen()
if s:bufnr <= 0 || !s:opmul | retu | endif
let matchstr = matchstr(getline('.'), '^> \zs.\+\ze\t*$')
if empty(matchstr) | retu | endif
let filpath = s:itemtype ? matchstr : getcwd().s:lash.matchstr
if exists('s:marked') && s:dictindex(s:marked, filpath) > 0
" Unmark, remove the file from s:marked
let key = s:dictindex(s:marked, filpath)
cal remove(s:marked, key)
if has('signs')
exe 'sign unplace' key 'buffer='.s:bufnr
endif
if empty(s:marked) | unl! s:marked | endif
else
" Add to s:marked and place a new sign
if exists('s:marked')
let vac = s:vacantdict(s:marked)
let key = empty(vac) ? len(s:marked) + 1 : vac[0]
let s:marked = extend(s:marked, { key : filpath })
else
let key = 1
let s:marked = { 1: filpath }
endif
if has('signs')
exe 'sign place' key 'line='.line('.').' name=ctrlpmark buffer='.s:bufnr
endif
endif
cal s:statusline()
endfunc
func! s:OpenMulti()
if !exists('s:marked') || !s:opmul | retu | endif
let marked = deepcopy(s:marked)
let prt = g:CtrlP_prompt
let str = prt[0] . prt[1] . prt[2]
if !empty(str) | cal s:recordhist(str) | endif
if !has('autocmd') | cal s:BufOpen('ControlP', 'del') | endif
" Try not to open in new tab
let bufs = []
for winnr in range(1, winnr('$'))
cal add(bufs, winbufnr(winnr))
endfor
let ntab = 1
" Check if the other window only has a blank buffer
if len(bufs) == 2
for each in bufs
if getbufvar(each, '&bl') && empty(bufname(each))
\ && empty(getbufvar(each, '&bt')) && empty(getbufvar(each, '&ft'))
\ && getbufvar(each, '&ma') && bufname(each) != 'ControlP'
" If it does, don't open new tab
let ntab = 0
endif
endfor
endif
if ntab | tabnew | endif
let ic = 1
for key in keys(marked)
let filpath = marked[key]
exe 'bo vne' filpath
if s:opmul > 1 && s:opmul < ic
winc c
else
let ic += 1
endif
endfor
if ntab
1winc w | winc c
endif
ec
endfunc
"}}}
" * Prt Actions {{{ " * Prt Actions {{{
func! s:PrtClear() func! s:PrtClear()
let s:nomatches = 1 let s:nomatches = 1
@ -699,10 +677,12 @@ func! s:PrtHistory(...)
if !s:maxhst | retu | endif if !s:maxhst | retu | endif
let prt = g:CtrlP_prompt let prt = g:CtrlP_prompt
let str = prt[0] . prt[1] . prt[2] let str = prt[0] . prt[1] . prt[2]
let hst = s:ctrlp_history let hst = s:hstry
" Save to history if not saved before
let hst[0] = exists('s:hstgot') ? hst[0] : str let hst[0] = exists('s:hstgot') ? hst[0] : str
let hslen = len(hst) let hslen = len(hst)
let idx = exists('s:hisidx') ? s:hisidx + a:1 : a:1 let idx = exists('s:hisidx') ? s:hisidx + a:1 : a:1
" Limit idx within 0 and hslen
let idx = idx < 0 ? 0 : idx >= hslen ? hslen > 1 ? hslen - 1 : 0 : idx let idx = idx < 0 ? 0 : idx >= hslen ? hslen > 1 ? hslen - 1 : 0 : idx
let g:CtrlP_prompt = [hst[idx], '', ''] let g:CtrlP_prompt = [hst[idx], '', '']
let s:hisidx = idx let s:hisidx = idx
@ -739,21 +719,23 @@ func! s:MapSpecs(...)
\ 'PrtHistory(-1)': ['<c-n>'], \ 'PrtHistory(-1)': ['<c-n>'],
\ 'PrtHistory(1)': ['<c-p>'], \ 'PrtHistory(1)': ['<c-p>'],
\ 'AcceptSelection("e")': ['<cr>'], \ 'AcceptSelection("e")': ['<cr>'],
\ 'AcceptSelection("h")': ['<c-cr>', '<c-s>', '<c-x>'], \ 'AcceptSelection("h")': ['<c-x>', '<c-cr>', '<c-s>'],
\ 'AcceptSelection("t")': ['<c-t>'], \ 'AcceptSelection("t")': ['<c-t>'],
\ 'AcceptSelection("v")': ['<c-v>'], \ 'AcceptSelection("v")': ['<c-v>', '<c-q>'],
\ 'ToggleFocus()': ['<tab>'], \ 'ToggleFocus()': ['<tab>'],
\ 'ToggleRegex()': ['<c-r>'], \ 'ToggleRegex()': ['<c-r>'],
\ 'ToggleByFname()': ['<c-d>'], \ 'ToggleByFname()': ['<c-d>'],
\ 'ToggleType(1)': ['<c-f>', '<c-up'], \ 'ToggleType(1)': ['<c-f>', '<c-up'],
\ 'ToggleType(-1)': ['<c-b>', '<c-down>'], \ 'ToggleType(-1)': ['<c-b>', '<c-down>'],
\ 'ForceUpdate()': ['<c-o>'], \ 'ForceUpdate()': ['<c-^>'],
\ 'PrtCurStart()': ['<c-a>'], \ 'PrtCurStart()': ['<c-a>'],
\ 'PrtCurEnd()': ['<c-e>'], \ 'PrtCurEnd()': ['<c-e>'],
\ 'PrtCurLeft()': ['<c-h>', '<left>'], \ 'PrtCurLeft()': ['<c-h>', '<left>'],
\ 'PrtCurRight()': ['<c-l>', '<right>'], \ 'PrtCurRight()': ['<c-l>', '<right>'],
\ 'PrtClearCache()': ['<F5>'], \ 'PrtClearCache()': ['<F5>'],
\ 'CreateNewFile()': ['<c-y>'], \ 'CreateNewFile()': ['<c-y>'],
\ 'MarkToOpen()': ['<c-z>'],
\ 'OpenMulti()': ['<c-o>'],
\ 'BufOpen("ControlP", "del")': ['<esc>', '<c-c>', '<c-g>'], \ 'BufOpen("ControlP", "del")': ['<esc>', '<c-c>', '<c-g>'],
\ } \ }
if type(s:urprtmaps) == 4 if type(s:urprtmaps) == 4
@ -891,7 +873,7 @@ func! s:AcceptSelection(mode,...) "{{{
" Get the full path " Get the full path
let matchstr = matchstr(getline('.'), '^> \zs.\+\ze\t*$') let matchstr = matchstr(getline('.'), '^> \zs.\+\ze\t*$')
if empty(matchstr) | retu | endif if empty(matchstr) | retu | endif
let filpath = s:itemtype ? matchstr : getcwd().ctrlp#utils#lash().matchstr let filpath = s:itemtype ? matchstr : getcwd().s:lash.matchstr
" If only need the full path " If only need the full path
if exists('a:1') && a:1 | retu filpath | endif if exists('a:1') && a:1 | retu filpath | endif
" Manually remove the prompt and match window " Manually remove the prompt and match window
@ -903,9 +885,8 @@ func! s:AcceptSelection(mode,...) "{{{
let mds = split(md, '\zs') let mds = split(md, '\zs')
let md = mds[0] let md = mds[0]
endif endif
" Do something with the selected entry " Determine the command to use
if md == 't' || s:splitwin == 1 " In new tab if md == 't' || s:splitwin == 1 " In new tab
tabnew
let cmd = 'e' let cmd = 'e'
elseif md == 'h' || s:splitwin == 2 " In new hor split elseif md == 'h' || s:splitwin == 2 " In new hor split
let cmd = 'new' let cmd = 'new'
@ -918,7 +899,7 @@ func! s:AcceptSelection(mode,...) "{{{
let bufwinnr = bufwinnr(bufnum) let bufwinnr = bufwinnr(bufnum)
let norbuf = s:normbuf() let norbuf = s:normbuf()
exe s:currwin.'winc w' exe s:currwin.'winc w'
" Check if the buffer's already opened in a tab " Check if the file's already opened in a tab
for nr in range(1, tabpagenr('$')) for nr in range(1, tabpagenr('$'))
" Get a list of the buffers in the nr tab " Get a list of the buffers in the nr tab
let buflist = tabpagebuflist(nr) let buflist = tabpagebuflist(nr)
@ -935,6 +916,12 @@ func! s:AcceptSelection(mode,...) "{{{
endfor endfor
endif endif
endfor endfor
" Get the tail
let tail = ''
if exists('s:optail') && !empty('s:optail')
let tailpref = match(s:optail, '^\s*+') < 0 ? ' +' : ' '
let tail = tailpref.s:optail
endif
" Switch to existing buffer or open new one " Switch to existing buffer or open new one
let filpath = escape(filpath, '%#') let filpath = escape(filpath, '%#')
" If the file's already loaded " If the file's already loaded
@ -950,27 +937,27 @@ func! s:AcceptSelection(mode,...) "{{{
if norbuf if norbuf
" But not the current one " But not the current one
if !&l:bl || !empty(&l:bt) || !&l:ma if !&l:bl || !empty(&l:bt) || !&l:ma
" Go to the first one " Go to the first normal one
exe norbuf.'winc w' exe norbuf.'winc w'
endif endif
else else
" No normal buffers " No normal buffers
let cmd = 'vne' let cmd = 'vne'
endif endif
elseif md == 't'
tabnew
endif endif
" Open new window/buffer " Open new window/buffer
exe 'bo '.cmd.' '.filpath sil! exe 'bo '.cmd.tail.' '.filpath
endif endif
" Jump to line if !empty('tail')
if exists('s:jmpln') && !empty('s:jmpln') sil! norm! zOzz
exe s:jmpln
norm! 0zz
endif endif
ec ec
endfunc "}}} endfunc "}}}
" * Helper functions {{{ " ** Helper functions {{{
" Comparing and sorting {{{ " Sorting {{{
func! s:complen(s1, s2) func! s:complen(s1, s2)
" By length " By length
let len1 = strlen(a:s1) let len1 = strlen(a:s1)
@ -1033,12 +1020,12 @@ func! s:mixedsort(s1, s2)
endfunc endfunc
"}}} "}}}
" Dealing with statusline {{{ " Statusline {{{
func! s:statusline(...) func! s:statusline(...)
let itemtypes = [ let itemtypes = [
\ ['files', 'fil'], \ ['files', 'fil'],
\ ['buffers', 'buf'], \ ['buffers', 'buf'],
\ ['recent files', 'mru'], \ ['mru files', 'mru'],
\ ] \ ]
if !g:ctrlp_mru_files if !g:ctrlp_mru_files
cal remove(itemtypes, 2) cal remove(itemtypes, 2)
@ -1055,7 +1042,8 @@ func! s:statusline(...)
let item = '%#Character# '.item.' %*' let item = '%#Character# '.item.' %*'
let slider = ' <'.prev.'>={'.item.'}=<'.next.'>' let slider = ' <'.prev.'>={'.item.'}=<'.next.'>'
let dir = ' %=%<%#LineNr# '.getcwd().' %*' let dir = ' %=%<%#LineNr# '.getcwd().' %*'
let &l:stl = focus.byfname.regex.slider.dir let marked = s:opmul ? exists('s:marked') ? ' <+'.len(s:marked).'>' : ' <+>' : ''
let &l:stl = focus.byfname.regex.slider.marked.dir
endfunc endfunc
func! s:progress(len) func! s:progress(len)
@ -1066,7 +1054,7 @@ func! s:progress(len)
endfunc endfunc
"}}} "}}}
" Working with paths {{{ " Paths {{{
func! s:dirfilter(val) func! s:dirfilter(val)
retu isdirectory(a:val) && match(a:val, '[\/]\.\{,2}$') < 0 ? 1 : 0 retu isdirectory(a:val) && match(a:val, '[\/]\.\{,2}$') < 0 ? 1 : 0
endfunc endfunc
@ -1081,14 +1069,14 @@ endfunc
func! s:createparentdirs(arr) func! s:createparentdirs(arr)
let curr = '' let curr = ''
for each in a:arr for each in a:arr
let curr = empty(curr) ? each : curr.ctrlp#utils#lash().each let curr = empty(curr) ? each : curr.s:lash.each
cal ctrlp#utils#mkdir(curr) cal ctrlp#utils#mkdir(curr)
endfor endfor
retu curr retu curr
endfunc endfunc
"}}} "}}}
" Syntax and coloring {{{ " Highlighting {{{
func! s:syntax() func! s:syntax()
syn match CtrlPNoEntries '^ == NO MATCHES ==$' syn match CtrlPNoEntries '^ == NO MATCHES ==$'
syn match CtrlPLineMarker '^>' syn match CtrlPLineMarker '^>'
@ -1114,8 +1102,8 @@ endfunc
" Prompt history {{{ " Prompt history {{{
func! s:gethistloc() func! s:gethistloc()
let cache_dir = ctrlp#utils#cachedir().ctrlp#utils#lash().'hist' let cache_dir = ctrlp#utils#cachedir().s:lash.'hist'
let cache_file = cache_dir.ctrlp#utils#lash().'cache.txt' let cache_file = cache_dir.s:lash.'cache.txt'
retu [cache_dir, cache_file] retu [cache_dir, cache_file]
endfunc endfunc
@ -1125,7 +1113,8 @@ endfunc
func! s:recordhist(str) func! s:recordhist(str)
if empty(a:str) || !s:maxhst | retu | endif if empty(a:str) || !s:maxhst | retu | endif
let hst = s:ctrlp_history let hst = s:hstry
if len(hst) > 1 && hst[1] == a:str | retu | endif
cal extend(hst, [a:str], 1) cal extend(hst, [a:str], 1)
if len(hst) > s:maxhst if len(hst) > s:maxhst
cal remove(hst, s:maxhst, -1) cal remove(hst, s:maxhst, -1)
@ -1133,6 +1122,34 @@ func! s:recordhist(str)
endfunc endfunc
"}}} "}}}
" Signs {{{
func! s:unmarksigns()
if !s:dosigns() | retu | endif
for key in keys(s:marked)
exe 'sign unplace' key 'buffer='.s:bufnr
endfor
endfunc
func! s:remarksigns(nls)
if !s:dosigns() | retu | endif
let nls = deepcopy(a:nls)
cal map(nls, 'substitute(v:val, "^> ", "", "g")')
let ic = 1
while ic <= len(nls)
let filpath = s:itemtype ? nls[ic - 1] : getcwd().s:lash.nls[ic - 1]
let key = s:dictindex(s:marked, filpath)
if key > 0
exe 'sign place' key 'line='.ic.' name=ctrlpmark buffer='.s:bufnr
endif
let ic+= 1
endwhile
endfunc
func! s:dosigns()
retu exists('s:marked') && s:bufnr > 0 && s:opmul && has('signs')
endfunc
"}}}
" Misc {{{ " Misc {{{
func! s:walker(max, pos, dir, ...) func! s:walker(max, pos, dir, ...)
if a:dir == 1 if a:dir == 1
@ -1155,6 +1172,26 @@ func! s:maxfiles(len)
retu s:maxfiles && a:len > s:maxfiles ? 1 : 0 retu s:maxfiles && a:len > s:maxfiles ? 1 : 0
endfunc endfunc
func! s:dictindex(dict, expr)
for key in keys(a:dict)
let val = a:dict[key]
if val == a:expr
retu key
endif
endfor
retu -1
endfunc
func! s:vacantdict(dict)
let vac = []
for ic in range(1, max(keys(a:dict)))
if !has_key(a:dict, ic)
cal add(vac, ic)
endif
endfor
retu vac
endfunc
func! s:normbuf() func! s:normbuf()
if &l:bl && empty(&l:bt) && &l:ma | retu winnr() | endif if &l:bl && empty(&l:bt) && &l:ma | retu winnr() | endif
for each in range(1, winnr('$')) for each in range(1, winnr('$'))
@ -1166,7 +1203,7 @@ endfunc
func! s:leavepre() func! s:leavepre()
if s:cconex | cal ctrlp#clearallcaches() | endif if s:cconex | cal ctrlp#clearallcaches() | endif
cal ctrlp#utils#writecache(s:ctrlp_history, s:gethistloc()[0], s:gethistloc()[1]) cal ctrlp#utils#writecache(s:hstry, s:gethistloc()[0], s:gethistloc()[1])
endfunc endfunc
func! s:insertcache(str) func! s:insertcache(str)
@ -1178,12 +1215,15 @@ func! s:insertcache(str)
elseif strlen(a:str) >= strlen(data[-1]) elseif strlen(a:str) >= strlen(data[-1])
let pos = len(data) - 1 let pos = len(data) - 1
else else
" Boost the value
let strlen = abs((strlen(a:str) - strlen(data[0])) * 100000) let strlen = abs((strlen(a:str) - strlen(data[0])) * 100000)
let fullen = abs(strlen(data[-1]) - strlen(data[0])) let fullen = abs(strlen(data[-1]) - strlen(data[0]))
let posi = string(len(data) * strlen / fullen) let posi = string(len(data) * strlen / fullen)
" Find and move the floating point back
let floatpos = stridx(posi, '.') let floatpos = stridx(posi, '.')
let posi = substitute(posi, '\.', '', 'g') let posi = substitute(posi, '\.', '', 'g')
let posi = join(insert(split(posi, '\zs'), '.', floatpos - 5), '') let posi = join(insert(split(posi, '\zs'), '.', floatpos - 5), '')
" Get the approximate integer
let pos = float2nr(round(str2float(posi))) let pos = float2nr(round(str2float(posi)))
endif endif
cal insert(data, a:str, pos) cal insert(data, a:str, pos)

View File

@ -1,4 +1,4 @@
*ctrlp.txt* Full path fuzzy file, buffer and MRU file finder for Vim. *ctrlp.txt* Full path fuzzy file, buffer and MRU file finder. v1.5
*CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'* *CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'*
=============================================================================== ===============================================================================
# # # #
@ -69,6 +69,11 @@ setting is from bottom to top: >
let g:ctrlp_match_window_reversed = 1 let g:ctrlp_match_window_reversed = 1
< <
*'g:ctrlp_max_height'*
Set the maximum height of the match window: >
let g:ctrlp_max_height = 10
<
*'g:ctrlp_split_window'* *'g:ctrlp_split_window'*
Use this option to specify how the file is to be opened when pressing <cr>: Use this option to specify how the file is to be opened when pressing <cr>:
1 - in a new tab 1 - in a new tab
@ -79,11 +84,6 @@ Use this option to specify how the file is to be opened when pressing <cr>:
let g:ctrlp_split_window = 0 let g:ctrlp_split_window = 0
< <
*'g:ctrlp_ignore_space'*
Set this to 1 to ignore whitespaces in filenames and directory names: >
let g:ctrlp_ignore_space = 0
<
*'g:ctrlp_working_path_mode'* *'g:ctrlp_working_path_mode'*
*SetWorkingPath()* *SetWorkingPath()*
When starting up the prompt, automatically set the working directory (i.e. the When starting up the prompt, automatically set the working directory (i.e. the
@ -111,11 +111,6 @@ addition to the default ones, your markers will take precedence: >
let g:ctrlp_root_markers = [''] let g:ctrlp_root_markers = ['']
< <
*'g:ctrlp_max_height'*
Set the maximum height of the match window: >
let g:ctrlp_max_height = 10
<
*'g:ctrlp_use_caching'* *'g:ctrlp_use_caching'*
Set this to 0 to disable per-session caching. When disabled, caching will still Set this to 0 to disable per-session caching. When disabled, caching will still
be enabled for directories that have more than 4000 files: > be enabled for directories that have more than 4000 files: >
@ -125,7 +120,7 @@ Note: you can quickly purge the cache by pressing <F5>.
*'g:ctrlp_clear_cache_on_exit'* *'g:ctrlp_clear_cache_on_exit'*
Set this to 0 to enable cross-sessions caching by not deleting the caches upon Set this to 0 to enable cross-sessions caching by not deleting the caches upon
exit: > exiting Vim: >
let g:ctrlp_clear_cache_on_exit = 1 let g:ctrlp_clear_cache_on_exit = 1
< <
@ -147,7 +142,7 @@ only need to keep the lines that youve changed the values (inside []): >
\ 'PrtHistory(-1)': ['<c-n>'], \ 'PrtHistory(-1)': ['<c-n>'],
\ 'PrtHistory(1)': ['<c-p>'], \ 'PrtHistory(1)': ['<c-p>'],
\ 'AcceptSelection("e")': ['<cr>'], \ 'AcceptSelection("e")': ['<cr>'],
\ 'AcceptSelection("h")': ['<c-cr>', '<c-s>', '<c-x>'], \ 'AcceptSelection("h")': ['<c-x>', '<c-cr>', '<c-s>'],
\ 'AcceptSelection("t")': ['<c-t>'], \ 'AcceptSelection("t")': ['<c-t>'],
\ 'AcceptSelection("v")': ['<c-v>'], \ 'AcceptSelection("v")': ['<c-v>'],
\ 'ToggleFocus()': ['<tab>'], \ 'ToggleFocus()': ['<tab>'],
@ -155,13 +150,15 @@ only need to keep the lines that youve changed the values (inside []): >
\ 'ToggleByFname()': ['<c-d>'], \ 'ToggleByFname()': ['<c-d>'],
\ 'ToggleType(1)': ['<c-f>', '<c-up'], \ 'ToggleType(1)': ['<c-f>', '<c-up'],
\ 'ToggleType(-1)': ['<c-b>', '<c-down>'], \ 'ToggleType(-1)': ['<c-b>', '<c-down>'],
\ 'ForceUpdate()': ['<c-o>'], \ 'ForceUpdate()': ['<c-^>'],
\ 'PrtCurStart()': ['<c-a>'], \ 'PrtCurStart()': ['<c-a>'],
\ 'PrtCurEnd()': ['<c-e>'], \ 'PrtCurEnd()': ['<c-e>'],
\ 'PrtCurLeft()': ['<c-h>', '<left>'], \ 'PrtCurLeft()': ['<c-h>', '<left>'],
\ 'PrtCurRight()': ['<c-l>', '<right>'], \ 'PrtCurRight()': ['<c-l>', '<right>'],
\ 'PrtClearCache()': ['<F5>'], \ 'PrtClearCache()': ['<F5>'],
\ 'CreateNewFile()': ['<c-y>'], \ 'CreateNewFile()': ['<c-y>'],
\ 'MarkToOpen()': ['<c-z>'],
\ 'OpenMulti()': ['<c-o>'],
\ 'BufOpen("ControlP", "del")': ['<esc>', '<c-c>', '<c-g>'], \ 'BufOpen("ControlP", "del")': ['<esc>', '<c-c>', '<c-g>'],
\ } \ }
< <
@ -226,7 +223,7 @@ The maximum depth of a directory tree to recurse into: >
Note: the larger the value, the more memory Vim uses. Note: the larger the value, the more memory Vim uses.
*'g:ctrlp_live_update'* *'g:ctrlp_live_update'*
Set to 0 to disable the update-as-you-type functionality; press <c-o> to force Set to 0 to disable the update-as-you-type functionality; press <c-^> to force
an update: > an update: >
let g:ctrlp_live_update = 1 let g:ctrlp_live_update = 1
< <
@ -262,7 +259,15 @@ The maximum number of input strings you want |CtrlP| to remember. The default
value mirrors Vims global |'history'| option. E.g. `set history=50`: > value mirrors Vims global |'history'| option. E.g. `set history=50`: >
let g:ctrlp_max_history = &history let g:ctrlp_max_history = &history
< <
Set it to 0 to disable prompts history. Set to 0 to disable prompts history.
*'g:ctrlp_open_multi'*
If non-zero this will enable opening multiple files with <c-z> and <c-o>: >
let g:ctrlp_open_multi = 0
<
If bigger than 1, itll be used as the maximum number of windows to create when
opening the files (the rest will be hidden buffers). If is 1, itll open all
files, each in a vertical split.
=============================================================================== ===============================================================================
3. Commands *ctrlp-commands* 3. Commands *ctrlp-commands*
@ -342,10 +347,6 @@ Once inside the prompt:
<tab> <tab>
Toggle the focus between the match window and the prompt. Toggle the focus between the match window and the prompt.
<c-o>
Force update the match window.
Use this if |g:ctrlp_live_update| has been set to 0.
<c-j>, <c-j>,
<down> <down>
Move selection down Move selection down
@ -397,9 +398,19 @@ Once inside the prompt:
<c-p> <c-p>
'Previous' string in the prompts history 'Previous' string in the prompts history
<c-z>
Mark/unmark a file to be opened with <c-o>.
<c-o>
Open files marked by <c-z>.
<F5> <F5>
Refresh the match window and purge the cache for the current directory. Refresh the match window and purge the cache for the current directory.
<c-^>
Force update the match window.
You only need to use this if |g:ctrlp_live_update| has been set to 0.
<esc>, <esc>,
<c-c>, <c-c>,
<c-g> <c-g>
@ -429,14 +440,25 @@ b) Vim |regexp|. If the input string contains '*' or '|', itll be treated as
See also |ctrlp-fullregexp| and |g:ctrlp_regexp_search|. See also |ctrlp-fullregexp| and |g:ctrlp_regexp_search|.
c) Strings end with a colon ':' followed by an arbitrary number will be read c) End the string with a colon ':' followed by a Vim command to execute that
as a line number to jump to after opening the file. command after opening the file. If you need to use ':' in the command,
escape it with a backslash: '\:'.
e.g. 'abc:45' will open the selected file and jump to line 45. e.g. 'abc:45' will open the selected file and jump to line 45.
'abc:/my\:function' will open the selected file and jump to the first
instance of 'my:function'.
'abc:+setf\ myfiletype|50' will open the selected file and set its
filetype to 'myfiletype' then jump to line 50.
See also |++opt| and |+cmd|.
d) Type exactly two dots (..) at the start of the line and press enter to go 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 backward in the directory tree by 1 level. If the parent directory is
large, this might be slow. large, this might be slow.
e) Type the name of a non-existed 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).
=============================================================================== ===============================================================================
6. Credits *ctrlp-credits* 6. Credits *ctrlp-credits*
@ -456,8 +478,16 @@ Mercurial repository: https://bitbucket.org/kien/ctrlp.vim
=============================================================================== ===============================================================================
CHANGELOG CHANGELOG
+ New mappings: <c-y> create new file and its parent dirs. + New features: Open multiple files.
<c-n>, <c-p> next/prev string in the input history. Pass Vims ++opt and +cmd to the opening file (section 5.c)
+ New mappings: <c-z> mark/unmark a file to be opened with <c-o>.
<c-o> open all marked files.
+ New option: |g:ctrlp_open_multi|
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.
+ New options: |g:ctrlp_open_new_file|, + New options: |g:ctrlp_open_new_file|,
|g:ctrlp_max_history| |g:ctrlp_max_history|
+ Added a new open-in-horizontal-split mapping: <c-x> + Added a new open-in-horizontal-split mapping: <c-x>
@ -468,6 +498,7 @@ Before 2011/09/19
+ New options: |g:ctrlp_max_files|, + New options: |g:ctrlp_max_files|,
|g:ctrlp_max_depth|, |g:ctrlp_max_depth|,
|g:ctrlp_live_update| |g:ctrlp_live_update|
+ New mapping: <c-^>
Before 2011/09/12 Before 2011/09/12
@ -484,7 +515,7 @@ Before 2011/09/12
|:CtrlPCurFile|, |:CtrlPCurFile|,
|:CtrlPRoot| |:CtrlPRoot|
+ New feature: search in most recently used (MRU) files + New feature: Search in most recently used (MRU) files
+ New mapping: <c-b>. + New mapping: <c-b>.
+ Extended the behavior of <c-f>. + Extended the behavior of <c-f>.
+ New options: |g:ctrlp_mru_files|, + New options: |g:ctrlp_mru_files|,
@ -493,8 +524,5 @@ Before 2011/09/12
|g:ctrlp_mruf_include| |g:ctrlp_mruf_include|
+ New command: |:CtrlPMRUFiles| + New command: |:CtrlPMRUFiles|
The updates are shown in reverse chronological order, from newest (top) to
oldest (bottom).
=============================================================================== ===============================================================================
vim:et:ts=2:sw=2:sts=2 vim:et:ts=2:sw=2:sts=2

View File

@ -2,20 +2,24 @@
Full path fuzzy __file__, __buffer__ and __MRU__ file finder for Vim. Full path fuzzy __file__, __buffer__ and __MRU__ file finder for Vim.
* Written in pure Vimscript for MacVim and Vim 7.0+. * Written in pure Vimscript for MacVim and Vim 7.0+.
* Has full support for Vims regexp as search pattern, and more. * Has full support for Vims regexp as search pattern.
* Can also find file in most recently used files. * Can also find file in most recently used files.
![ctrlp][1] ![ctrlp][1]
## Basic Usage ## Basic Usage
* Press `<c-p>` or run `:CtrlP` to invoke CtrlP. * Press `<c-p>` or run `:CtrlP` to invoke CtrlP.
* Press `<c-f>` and `<c-b>` while CtrlP is open to switch between find file, find buffer, and find MRU file modes.
* Ever remember only a files name but not where it is? Press `<c-d>` while CtrlP is open to switch to filename only search. Once CtrlP is open:
* Press `<c-f>` and `<c-b>` to switch between find file, buffer, and MRU file modes.
* Press `<c-d>` to switch to filename only search instead of full path.
* Use `*` or `|` in the prompt to submit the string as a Vims regexp pattern. * Use `*` or `|` in the prompt to submit the string as a Vims regexp pattern.
* Or press `<c-r>` while CtrlP is open to switch to full regexp search mode. * Or press `<c-r>` to switch to full regexp search mode.
* End the input string with a colon `:` followed with a number to jump to that line in the selected file. * End the input string with a colon `:` followed by a command to execute after opening the file.
e.g. `abc:45` to open the file matched the pattern and jump to line 45. e.g. `abc:45` will open the file matched the pattern and jump to line 45.
* Submit two dots `..` as the input string to go backward the directory tree by 1 level. * Submit two dots `..` as the input string to go backward the directory tree by 1 level.
* Use `<c-y>` to create a new file and its parent dirs.
## Basic Options ## Basic Options
* Change the mapping to invoke CtrlP: * Change the mapping to invoke CtrlP:
@ -65,5 +69,5 @@ e.g. Just have something like this in your vimrc:
_Check [the docs][2] for more mappings, commands and options._ _Check [the docs][2] for more mappings, commands and options._
[1]: http://i.imgur.com/iviMa.png [1]: http://i.imgur.com/3rtLt.png
[2]: https://github.com/kien/ctrlp.vim/blob/master/doc/ctrlp.txt [2]: https://github.com/kien/ctrlp.vim/blob/master/doc/ctrlp.txt