├── .gitignore ├── autoload ├── ctrlp │ ├── quickfix.vim │ ├── line.vim │ ├── rtscript.vim │ ├── mixed.vim │ ├── changes.vim │ ├── dir.vim │ ├── tag.vim │ ├── utils.vim │ ├── bookmarkdir.vim │ ├── undo.vim │ ├── mrufiles.vim │ └── buffertag.vim └── ctrlp.vim ├── plugin └── ctrlp.vim ├── readme.md └── doc └── ctrlp.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.markdown 2 | *.zip 3 | note.txt 4 | tags 5 | .hg* 6 | tmp/* 7 | -------------------------------------------------------------------------------- /autoload/ctrlp/quickfix.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/quickfix.vim 3 | " Description: Quickfix extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_quickfix') && g:loaded_ctrlp_quickfix 9 | fini 10 | en 11 | let g:loaded_ctrlp_quickfix = 1 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#quickfix#init()', 15 | \ 'accept': 'ctrlp#quickfix#accept', 16 | \ 'lname': 'quickfix', 17 | \ 'sname': 'qfx', 18 | \ 'type': 'line', 19 | \ 'sort': 0, 20 | \ 'nolim': 1, 21 | \ }) 22 | 23 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 24 | 25 | fu! s:lineout(dict) 26 | retu printf('%s|%d:%d| %s', bufname(a:dict['bufnr']), a:dict['lnum'], 27 | \ a:dict['col'], matchstr(a:dict['text'], '\s*\zs.*\S')) 28 | endf 29 | " Utilities {{{1 30 | fu! s:syntax() 31 | if !ctrlp#nosy() 32 | cal ctrlp#hicheck('CtrlPqfLineCol', 'Search') 33 | sy match CtrlPqfLineCol '|\zs\d\+:\d\+\ze|' 34 | en 35 | endf 36 | " Public {{{1 37 | fu! ctrlp#quickfix#init() 38 | cal s:syntax() 39 | retu map(getqflist(), 's:lineout(v:val)') 40 | endf 41 | 42 | fu! ctrlp#quickfix#accept(mode, str) 43 | let vals = matchlist(a:str, '^\([^|]\+\ze\)|\(\d\+\):\(\d\+\)|') 44 | if vals == [] || vals[1] == '' | retu | en 45 | cal ctrlp#acceptfile(a:mode, vals[1]) 46 | let cur_pos = getpos('.')[1:2] 47 | if cur_pos != [1, 1] && cur_pos != map(vals[2:3], 'str2nr(v:val)') 48 | mark ' 49 | en 50 | cal cursor(vals[2], vals[3]) 51 | sil! norm! zvzz 52 | endf 53 | 54 | fu! ctrlp#quickfix#id() 55 | retu s:id 56 | endf 57 | "}}} 58 | 59 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 60 | -------------------------------------------------------------------------------- /autoload/ctrlp/line.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/line.vim 3 | " Description: Line extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_line') && g:loaded_ctrlp_line 9 | fini 10 | en 11 | let g:loaded_ctrlp_line = 1 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#line#init()', 15 | \ 'accept': 'ctrlp#line#accept', 16 | \ 'lname': 'lines', 17 | \ 'sname': 'lns', 18 | \ 'type': 'tabe', 19 | \ }) 20 | 21 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 22 | " Utilities {{{1 23 | fu! s:syntax() 24 | if !ctrlp#nosy() 25 | cal ctrlp#hicheck('CtrlPBufName', 'Directory') 26 | cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') 27 | sy match CtrlPBufName '\t|\zs[^|]\+\ze|\d\+:\d\+|$' 28 | sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName 29 | en 30 | endf 31 | " Public {{{1 32 | fu! ctrlp#line#init() 33 | let [bufs, lines] = [ctrlp#buffers('id'), []] 34 | for bufnr in bufs 35 | let [lfb, bufn] = [getbufline(bufnr, 1, '$'), bufname(bufnr)] 36 | let lfb = lfb == [] ? ctrlp#utils#readfile(fnamemodify(bufn, ':p')) : lfb 37 | cal map(lfb, 'tr(v:val, '' '', '' '')') 38 | let [linenr, len_lfb, buft] = [1, len(lfb), fnamemodify(bufn, ':t')] 39 | wh linenr <= len_lfb 40 | let lfb[linenr - 1] .= ' |'.buft.'|'.bufnr.':'.linenr.'|' 41 | let linenr += 1 42 | endw 43 | cal extend(lines, filter(lfb, 'v:val !~ ''^\s*\t|[^|]\+|\d\+:\d\+|$''')) 44 | endfo 45 | cal s:syntax() 46 | retu lines 47 | endf 48 | 49 | fu! ctrlp#line#accept(mode, str) 50 | let info = matchlist(a:str, '\t|[^|]\+|\(\d\+\):\(\d\+\)|$') 51 | let bufnr = str2nr(get(info, 1)) 52 | if bufnr 53 | cal ctrlp#acceptfile(a:mode, bufname(bufnr), get(info, 2)) 54 | en 55 | endf 56 | 57 | fu! ctrlp#line#id() 58 | retu s:id 59 | endf 60 | "}}} 61 | 62 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 63 | -------------------------------------------------------------------------------- /autoload/ctrlp/rtscript.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/rtscript.vim 3 | " Description: Runtime scripts extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_rtscript') && g:loaded_ctrlp_rtscript 9 | fini 10 | en 11 | let [g:loaded_ctrlp_rtscript, g:ctrlp_newrts] = [1, 0] 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#rtscript#init(s:caching)', 15 | \ 'accept': 'ctrlp#acceptfile', 16 | \ 'lname': 'runtime scripts', 17 | \ 'sname': 'rts', 18 | \ 'type': 'path', 19 | \ 'opmul': 1, 20 | \ }) 21 | 22 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 23 | 24 | let s:filecounts = {} 25 | " Utilities {{{1 26 | fu! s:nocache() 27 | retu g:ctrlp_newrts || 28 | \ !s:caching || ( s:caching > 1 && get(s:filecounts, s:cwd) < s:caching ) 29 | endf 30 | " Public {{{1 31 | fu! ctrlp#rtscript#init(caching) 32 | let [s:caching, s:cwd] = [a:caching, getcwd()] 33 | if s:nocache() || 34 | \ !( exists('g:ctrlp_rtscache') && g:ctrlp_rtscache[0] == &rtp ) 35 | sil! cal ctrlp#progress('Indexing...') 36 | let entries = split(globpath(ctrlp#utils#fnesc(&rtp, 'g'), '**/*.*'), "\n") 37 | cal filter(entries, 'count(entries, v:val) == 1') 38 | let [entries, echoed] = [ctrlp#dirnfile(entries)[1], 1] 39 | el 40 | let [entries, results] = g:ctrlp_rtscache[2:3] 41 | en 42 | if s:nocache() || 43 | \ !( exists('g:ctrlp_rtscache') && g:ctrlp_rtscache[:1] == [&rtp, s:cwd] ) 44 | if !exists('echoed') 45 | sil! cal ctrlp#progress('Processing...') 46 | en 47 | let results = map(copy(entries), 'fnamemodify(v:val, '':.'')') 48 | en 49 | let [g:ctrlp_rtscache, g:ctrlp_newrts] = [[&rtp, s:cwd, entries, results], 0] 50 | cal extend(s:filecounts, { s:cwd : len(results) }) 51 | retu results 52 | endf 53 | 54 | fu! ctrlp#rtscript#id() 55 | retu s:id 56 | endf 57 | "}}} 58 | 59 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 60 | -------------------------------------------------------------------------------- /plugin/ctrlp.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: plugin/ctrlp.vim 3 | " Description: Fuzzy file, buffer, mru, tag, etc finder. 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | " GetLatestVimScripts: 3736 1 :AutoInstall: ctrlp.zip 7 | 8 | if ( exists('g:loaded_ctrlp') && g:loaded_ctrlp ) || v:version < 700 || &cp 9 | fini 10 | en 11 | let g:loaded_ctrlp = 1 12 | 13 | let [g:ctrlp_lines, g:ctrlp_allfiles, g:ctrlp_alltags, g:ctrlp_alldirs, 14 | \ g:ctrlp_allmixes, g:ctrlp_buftags, g:ctrlp_ext_vars, g:ctrlp_builtins] 15 | \ = [[], [], [], [], {}, {}, [], 2] 16 | 17 | if !exists('g:ctrlp_map') | let g:ctrlp_map = '' | en 18 | if !exists('g:ctrlp_cmd') | let g:ctrlp_cmd = 'CtrlP' | en 19 | 20 | com! -n=? -com=custom,ctrlp#utils#dircompl CtrlP 21 | \ cal ctrlp#init(0, { 'dir': }) 22 | 23 | com! -n=? -com=custom,ctrlp#utils#dircompl CtrlPMRUFiles 24 | \ cal ctrlp#init(2, { 'dir': }) 25 | 26 | com! -bar CtrlPBuffer cal ctrlp#init(1) 27 | com! -n=? CtrlPLastMode cal ctrlp#init(-1, { 'args': }) 28 | 29 | com! -bar CtrlPClearCache cal ctrlp#clr() 30 | com! -bar CtrlPClearAllCaches cal ctrlp#clra() 31 | 32 | com! -bar ClearCtrlPCache cal ctrlp#clr() 33 | com! -bar ClearAllCtrlPCaches cal ctrlp#clra() 34 | 35 | com! -bar CtrlPCurWD cal ctrlp#init(0, { 'mode': '' }) 36 | com! -bar CtrlPCurFile cal ctrlp#init(0, { 'mode': 'c' }) 37 | com! -bar CtrlPRoot cal ctrlp#init(0, { 'mode': 'r' }) 38 | 39 | if g:ctrlp_map != '' && !hasmapto(':'.g:ctrlp_cmd.'', 'n') 40 | exe 'nn ' g:ctrlp_map ':'.g:ctrlp_cmd.'' 41 | en 42 | 43 | cal ctrlp#mrufiles#init() 44 | 45 | com! -bar CtrlPTag cal ctrlp#init(ctrlp#tag#id()) 46 | com! -bar CtrlPQuickfix cal ctrlp#init(ctrlp#quickfix#id()) 47 | 48 | com! -n=? -com=custom,ctrlp#utils#dircompl CtrlPDir 49 | \ cal ctrlp#init(ctrlp#dir#id(), { 'dir': }) 50 | 51 | com! -n=? -com=buffer CtrlPBufTag 52 | \ cal ctrlp#init(ctrlp#buffertag#cmd(0, )) 53 | 54 | com! -bar CtrlPBufTagAll cal ctrlp#init(ctrlp#buffertag#cmd(1)) 55 | com! -bar CtrlPRTS cal ctrlp#init(ctrlp#rtscript#id()) 56 | com! -bar CtrlPUndo cal ctrlp#init(ctrlp#undo#id()) 57 | com! -bar CtrlPLine cal ctrlp#init(ctrlp#line#id()) 58 | 59 | com! -n=? -com=buffer CtrlPChange 60 | \ cal ctrlp#init(ctrlp#changes#cmd(0, )) 61 | 62 | com! -bar CtrlPChangeAll cal ctrlp#init(ctrlp#changes#cmd(1)) 63 | com! -bar CtrlPMixed cal ctrlp#init(ctrlp#mixed#id()) 64 | com! -bar CtrlPBookmarkDir cal ctrlp#init(ctrlp#bookmarkdir#id()) 65 | 66 | com! -n=? -com=custom,ctrlp#utils#dircompl CtrlPBookmarkDirAdd 67 | \ cal ctrlp#call('ctrlp#bookmarkdir#add', ) 68 | 69 | " vim:ts=2:sw=2:sts=2 70 | -------------------------------------------------------------------------------- /autoload/ctrlp/mixed.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/mixed.vim 3 | " Description: Mixing Files + MRU + Buffers 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_mixed') && g:loaded_ctrlp_mixed 9 | fini 10 | en 11 | let [g:loaded_ctrlp_mixed, g:ctrlp_newmix] = [1, 0] 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#mixed#init(s:compare_lim)', 15 | \ 'accept': 'ctrlp#acceptfile', 16 | \ 'lname': 'fil + mru + buf', 17 | \ 'sname': 'mix', 18 | \ 'type': 'path', 19 | \ 'opmul': 1, 20 | \ 'specinput': 1, 21 | \ }) 22 | 23 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 24 | " Utilities {{{1 25 | fu! s:newcache(cwd) 26 | if g:ctrlp_newmix || !has_key(g:ctrlp_allmixes, 'data') | retu 1 | en 27 | retu g:ctrlp_allmixes['cwd'] != a:cwd 28 | \ || g:ctrlp_allmixes['filtime'] < getftime(ctrlp#utils#cachefile()) 29 | \ || g:ctrlp_allmixes['mrutime'] < getftime(ctrlp#mrufiles#cachefile()) 30 | \ || g:ctrlp_allmixes['bufs'] < len(ctrlp#mrufiles#bufs()) 31 | endf 32 | 33 | fu! s:getnewmix(cwd, clim) 34 | if g:ctrlp_newmix 35 | cal ctrlp#mrufiles#refresh('raw') 36 | let g:ctrlp_newcache = 1 37 | en 38 | let g:ctrlp_lines = copy(ctrlp#files()) 39 | cal ctrlp#progress('Mixing...') 40 | let mrufs = copy(ctrlp#mrufiles#list('raw')) 41 | if exists('+ssl') && &ssl 42 | cal map(mrufs, 'tr(v:val, "\\", "/")') 43 | en 44 | let bufs = map(ctrlp#buffers('id'), 'fnamemodify(bufname(v:val), ":p")') 45 | let mrufs = bufs + filter(mrufs, 'index(bufs, v:val) < 0') 46 | if len(mrufs) > len(g:ctrlp_lines) 47 | cal filter(mrufs, 'stridx(v:val, a:cwd)') 48 | el 49 | let cwd_mrufs = filter(copy(mrufs), '!stridx(v:val, a:cwd)') 50 | let cwd_mrufs = ctrlp#rmbasedir(cwd_mrufs) 51 | for each in cwd_mrufs 52 | let id = index(g:ctrlp_lines, each) 53 | if id >= 0 | cal remove(g:ctrlp_lines, id) | en 54 | endfo 55 | en 56 | cal map(mrufs, 'fnamemodify(v:val, ":.")') 57 | let g:ctrlp_lines = len(mrufs) > len(g:ctrlp_lines) 58 | \ ? g:ctrlp_lines + mrufs : mrufs + g:ctrlp_lines 59 | if len(g:ctrlp_lines) <= a:clim 60 | cal sort(g:ctrlp_lines, 'ctrlp#complen') 61 | en 62 | let g:ctrlp_allmixes = { 'filtime': getftime(ctrlp#utils#cachefile()), 63 | \ 'mrutime': getftime(ctrlp#mrufiles#cachefile()), 'cwd': a:cwd, 64 | \ 'bufs': len(ctrlp#mrufiles#bufs()), 'data': g:ctrlp_lines } 65 | endf 66 | " Public {{{1 67 | fu! ctrlp#mixed#init(clim) 68 | let cwd = getcwd() 69 | if s:newcache(cwd) 70 | cal s:getnewmix(cwd, a:clim) 71 | el 72 | let g:ctrlp_lines = g:ctrlp_allmixes['data'] 73 | en 74 | let g:ctrlp_newmix = 0 75 | retu g:ctrlp_lines 76 | endf 77 | 78 | fu! ctrlp#mixed#id() 79 | retu s:id 80 | endf 81 | "}}} 82 | 83 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 84 | -------------------------------------------------------------------------------- /autoload/ctrlp/changes.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/changes.vim 3 | " Description: Change list extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_changes') && g:loaded_ctrlp_changes 9 | fini 10 | en 11 | let g:loaded_ctrlp_changes = 1 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#changes#init(s:bufnr, s:crbufnr)', 15 | \ 'accept': 'ctrlp#changes#accept', 16 | \ 'lname': 'changes', 17 | \ 'sname': 'chs', 18 | \ 'exit': 'ctrlp#changes#exit()', 19 | \ 'type': 'tabe', 20 | \ 'sort': 0, 21 | \ 'nolim': 1, 22 | \ }) 23 | 24 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 25 | " Utilities {{{1 26 | fu! s:changelist(bufnr) 27 | sil! exe 'noa hid b' a:bufnr 28 | redi => result 29 | sil! changes 30 | redi END 31 | retu map(split(result, "\n")[1:], 'tr(v:val, " ", " ")') 32 | endf 33 | 34 | fu! s:process(clines, ...) 35 | let [clines, evas] = [[], []] 36 | for each in a:clines 37 | let parts = matchlist(each, '\v^.\s*\d+\s+(\d+)\s+(\d+)\s(.*)$') 38 | if !empty(parts) 39 | if parts[3] == '' | let parts[3] = ' ' | en 40 | cal add(clines, parts[3].' |'.a:1.':'.a:2.'|'.parts[1].':'.parts[2].'|') 41 | en 42 | endfo 43 | retu reverse(filter(clines, 'count(clines, v:val) == 1')) 44 | endf 45 | 46 | fu! s:syntax() 47 | if !ctrlp#nosy() 48 | cal ctrlp#hicheck('CtrlPBufName', 'Directory') 49 | cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') 50 | sy match CtrlPBufName '\t|\d\+:\zs[^|]\+\ze|\d\+:\d\+|$' 51 | sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName 52 | en 53 | endf 54 | " Public {{{1 55 | fu! ctrlp#changes#init(original_bufnr, bufnr) 56 | let bufnr = exists('s:bufnr') ? s:bufnr : a:bufnr 57 | let bufs = exists('s:clmode') && s:clmode ? ctrlp#buffers('id') : [bufnr] 58 | cal filter(bufs, 'v:val > 0') 59 | let [swb, &swb] = [&swb, ''] 60 | let lines = [] 61 | for each in bufs 62 | let fnamet = fnamemodify(bufname(each), ':t') 63 | cal extend(lines, s:process(s:changelist(each), each, fnamet)) 64 | endfo 65 | sil! exe 'noa hid b' a:original_bufnr 66 | let &swb = swb 67 | cal ctrlp#syntax() 68 | cal s:syntax() 69 | retu lines 70 | endf 71 | 72 | fu! ctrlp#changes#accept(mode, str) 73 | let info = matchlist(a:str, '\t|\(\d\+\):[^|]\+|\(\d\+\):\(\d\+\)|$') 74 | let bufnr = str2nr(get(info, 1)) 75 | if bufnr 76 | cal ctrlp#acceptfile(a:mode, bufname(bufnr)) 77 | cal cursor(get(info, 2), get(info, 3)) 78 | sil! norm! zvzz 79 | en 80 | endf 81 | 82 | fu! ctrlp#changes#cmd(mode, ...) 83 | let s:clmode = a:mode 84 | if a:0 && !empty(a:1) 85 | let s:bufnr = bufnr('^'.fnamemodify(a:1, ':p').'$') 86 | en 87 | retu s:id 88 | endf 89 | 90 | fu! ctrlp#changes#exit() 91 | unl! s:clmode s:bufnr 92 | endf 93 | "}}} 94 | 95 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 96 | -------------------------------------------------------------------------------- /autoload/ctrlp/dir.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/dir.vim 3 | " Description: Directory extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_dir') && g:loaded_ctrlp_dir 9 | fini 10 | en 11 | let [g:loaded_ctrlp_dir, g:ctrlp_newdir] = [1, 0] 12 | 13 | let s:ars = ['s:maxdepth', 's:maxfiles', 's:compare_lim', 's:glob', 's:caching'] 14 | 15 | cal add(g:ctrlp_ext_vars, { 16 | \ 'init': 'ctrlp#dir#init('.join(s:ars, ', ').')', 17 | \ 'accept': 'ctrlp#dir#accept', 18 | \ 'lname': 'dirs', 19 | \ 'sname': 'dir', 20 | \ 'type': 'path', 21 | \ 'specinput': 1, 22 | \ }) 23 | 24 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 25 | 26 | let s:dircounts = {} 27 | " Utilities {{{1 28 | fu! s:globdirs(dirs, depth) 29 | let entries = split(globpath(a:dirs, s:glob), "\n") 30 | let [dirs, depth] = [ctrlp#dirnfile(entries)[0], a:depth + 1] 31 | cal extend(g:ctrlp_alldirs, dirs) 32 | let nr = len(g:ctrlp_alldirs) 33 | if !empty(dirs) && !s:max(nr, s:maxfiles) && depth <= s:maxdepth 34 | sil! cal ctrlp#progress(nr) 35 | cal map(dirs, 'ctrlp#utils#fnesc(v:val, "g", ",")') 36 | cal s:globdirs(join(dirs, ','), depth) 37 | en 38 | endf 39 | 40 | fu! s:max(len, max) 41 | retu a:max && a:len > a:max 42 | endf 43 | 44 | fu! s:nocache() 45 | retu !s:caching || ( s:caching > 1 && get(s:dircounts, s:cwd) < s:caching ) 46 | endf 47 | " Public {{{1 48 | fu! ctrlp#dir#init(...) 49 | let s:cwd = getcwd() 50 | for each in range(len(s:ars)) 51 | let {s:ars[each]} = a:{each + 1} 52 | endfo 53 | let cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'dir' 54 | let cafile = cadir.ctrlp#utils#lash().ctrlp#utils#cachefile('dir') 55 | if g:ctrlp_newdir || s:nocache() || !filereadable(cafile) 56 | let [s:initcwd, g:ctrlp_alldirs] = [s:cwd, []] 57 | cal s:globdirs(ctrlp#utils#fnesc(s:cwd, 'g', ','), 0) 58 | cal ctrlp#rmbasedir(g:ctrlp_alldirs) 59 | if len(g:ctrlp_alldirs) <= s:compare_lim 60 | cal sort(g:ctrlp_alldirs, 'ctrlp#complen') 61 | en 62 | cal ctrlp#utils#writecache(g:ctrlp_alldirs, cadir, cafile) 63 | let g:ctrlp_newdir = 0 64 | el 65 | if !( exists('s:initcwd') && s:initcwd == s:cwd ) 66 | let s:initcwd = s:cwd 67 | let g:ctrlp_alldirs = ctrlp#utils#readfile(cafile) 68 | en 69 | en 70 | cal extend(s:dircounts, { s:cwd : len(g:ctrlp_alldirs) }) 71 | retu g:ctrlp_alldirs 72 | endf 73 | 74 | fu! ctrlp#dir#accept(mode, str) 75 | let path = a:mode == 'h' ? getcwd() : s:cwd.ctrlp#utils#lash().a:str 76 | if a:mode =~ 't\|v\|h' 77 | cal ctrlp#exit() 78 | en 79 | cal ctrlp#setdir(path, a:mode =~ 't\|h' ? 'chd!' : 'lc!') 80 | if a:mode == 'e' 81 | sil! cal ctrlp#statusline() 82 | cal ctrlp#setlines(s:id) 83 | cal ctrlp#recordhist() 84 | cal ctrlp#prtclear() 85 | en 86 | endf 87 | 88 | fu! ctrlp#dir#id() 89 | retu s:id 90 | endf 91 | "}}} 92 | 93 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 94 | -------------------------------------------------------------------------------- /autoload/ctrlp/tag.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/tag.vim 3 | " Description: Tag file extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_tag') && g:loaded_ctrlp_tag 9 | fini 10 | en 11 | let g:loaded_ctrlp_tag = 1 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#tag#init()', 15 | \ 'accept': 'ctrlp#tag#accept', 16 | \ 'lname': 'tags', 17 | \ 'sname': 'tag', 18 | \ 'enter': 'ctrlp#tag#enter()', 19 | \ 'type': 'tabs', 20 | \ }) 21 | 22 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 23 | " Utilities {{{1 24 | fu! s:findcount(str) 25 | let [tg, fname] = split(a:str, '\t\+\ze[^\t]\+$') 26 | let tgs = taglist('^'.tg.'$') 27 | if len(tgs) < 2 28 | retu [1, 1] 29 | en 30 | let bname = fnamemodify(bufname('%'), ':p') 31 | let fname = expand(fnamemodify(simplify(fname), ':s?^[.\/]\+??:p:.'), 1) 32 | let [fnd, ct, pos, idx] = [0, 0, 0, 0] 33 | wh idx < len(tgs) 34 | if bname == fnamemodify(tgs[idx]["filename"], ':p') 35 | cal insert(tgs, remove(tgs, idx)) 36 | brea 37 | en 38 | let idx += 1 39 | endw 40 | for each in tgs 41 | let ct += 1 42 | let fulname = fnamemodify(each["filename"], ':p') 43 | if stridx(fulname, fname) >= 0 44 | \ && strlen(fname) + stridx(fulname, fname) == strlen(fulname) 45 | let fnd += 1 46 | let pos = ct 47 | en 48 | if fnd > 1 | brea | en 49 | endfo 50 | retu [fnd, pos] 51 | endf 52 | 53 | fu! s:filter(tags) 54 | let nr = 0 55 | wh 0 < 1 56 | if a:tags == [] | brea | en 57 | if a:tags[nr] =~ '^!' && a:tags[nr] !~# '^!_TAG_' 58 | let nr += 1 59 | con 60 | en 61 | if a:tags[nr] =~# '^!_TAG_' && len(a:tags) > nr 62 | cal remove(a:tags, nr) 63 | el 64 | brea 65 | en 66 | endw 67 | retu a:tags 68 | endf 69 | 70 | fu! s:syntax() 71 | if !ctrlp#nosy() 72 | cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') 73 | sy match CtrlPTabExtra '\zs\t.*\ze$' 74 | en 75 | endf 76 | " Public {{{1 77 | fu! ctrlp#tag#init() 78 | if empty(s:tagfiles) | retu [] | en 79 | let g:ctrlp_alltags = [] 80 | let tagfiles = sort(filter(s:tagfiles, 'count(s:tagfiles, v:val) == 1')) 81 | for each in tagfiles 82 | let alltags = s:filter(ctrlp#utils#readfile(each)) 83 | cal extend(g:ctrlp_alltags, alltags) 84 | endfo 85 | cal s:syntax() 86 | retu g:ctrlp_alltags 87 | endf 88 | 89 | fu! ctrlp#tag#accept(mode, str) 90 | cal ctrlp#exit() 91 | let str = matchstr(a:str, '^[^\t]\+\t\+[^\t]\+\ze\t') 92 | let [tg, fnd] = [split(str, '^[^\t]\+\zs\t')[0], s:findcount(str)] 93 | let cmds = { 94 | \ 't': ['tab sp', 'tab stj'], 95 | \ 'h': ['sp', 'stj'], 96 | \ 'v': ['vs', 'vert stj'], 97 | \ 'e': ['', 'tj'], 98 | \ } 99 | let cmd = fnd[0] == 1 ? cmds[a:mode][0] : cmds[a:mode][1] 100 | let cmd = a:mode == 'e' && ctrlp#modfilecond(!&aw) 101 | \ ? ( cmd == 'tj' ? 'stj' : 'sp' ) : cmd 102 | let cmd = a:mode == 't' ? ctrlp#tabcount().cmd : cmd 103 | if fnd[0] == 1 104 | if cmd != '' 105 | exe cmd 106 | en 107 | exe fnd[1].'ta' tg 108 | el 109 | exe cmd tg 110 | en 111 | cal ctrlp#setlcdir() 112 | endf 113 | 114 | fu! ctrlp#tag#id() 115 | retu s:id 116 | endf 117 | 118 | fu! ctrlp#tag#enter() 119 | let tfs = tagfiles() 120 | let s:tagfiles = tfs != [] ? filter(map(tfs, 'fnamemodify(v:val, ":p")'), 121 | \ 'filereadable(v:val)') : [] 122 | endf 123 | "}}} 124 | 125 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 126 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ctrlp.vim 2 | Full path fuzzy __file__, __buffer__, __mru__, __tag__, __...__ finder for Vim. 3 | 4 | * Written in pure Vimscript for MacVim, gVim and Vim 7.0+. 5 | * Full support for Vim's regexp as search patterns. 6 | * Built-in Most Recently Used (MRU) files monitoring. 7 | * Built-in project's root finder. 8 | * Open multiple files at once. 9 | * Create new files and directories. 10 | * [Extensible][2]. 11 | 12 | ![ctrlp][1] 13 | 14 | ## Basic Usage 15 | * Run `:CtrlP` or `:CtrlP [starting-directory]` to invoke CtrlP in find file mode. 16 | * Run `:CtrlPBuffer` or `:CtrlPMRU` to invoke CtrlP in find buffer or find MRU file mode. 17 | * Run `:CtrlPMixed` to search in Files, Buffers and MRU files at the same time. 18 | 19 | Check `:help ctrlp-commands` and `:help ctrlp-extensions` for other commands. 20 | 21 | ##### Once CtrlP is open: 22 | * Press `` to purge the cache for the current directory to get new files, remove deleted files and apply new ignore options. 23 | * Press `` and `` to cycle between modes. 24 | * Press `` to switch to filename only search instead of full path. 25 | * Press `` to switch to regexp mode. 26 | * Use ``, `` to select the next/previous string in the prompt's history. 27 | * Use `` to create a new file and its parent directories. 28 | * Use `` to mark/unmark multiple files and `` to open them. 29 | 30 | Run `:help ctrlp-mappings` or submit `?` in CtrlP for more mapping help. 31 | 32 | * Submit two or more dots `..` to go up the directory tree by one or multiple levels. 33 | * End the input string with a colon `:` followed by a command to execute it on the opening file(s): 34 | Use `:25` to jump to line 25. 35 | Use `:diffthis` when opening multiple files to run `:diffthis` on the first 4 files. 36 | 37 | ## Basic Options 38 | * Change the default mapping and the default command to invoke CtrlP: 39 | 40 | ```vim 41 | let g:ctrlp_map = '' 42 | let g:ctrlp_cmd = 'CtrlP' 43 | ``` 44 | 45 | * When invoked, unless a starting directory is specified, CtrlP will set its local working directory according to this variable: 46 | 47 | ```vim 48 | let g:ctrlp_working_path_mode = 'ra' 49 | ``` 50 | 51 | `'c'` - the directory of the current file. 52 | `'r'` - the nearest ancestor that contains one of these directories or files: `.git` `.hg` `.svn` `.bzr` `_darcs` 53 | `'a'` - like c, but only if the current working directory outside of CtrlP is not a direct ancestor of the directory of the current file. 54 | `0` or `''` (empty string) - disable this feature. 55 | 56 | Define additional root markers with the `g:ctrlp_root_markers` option. 57 | 58 | * Exclude files and directories using Vim's `wildignore` and CtrlP's own `g:ctrlp_custom_ignore`: 59 | 60 | ```vim 61 | set wildignore+=*/tmp/*,*.so,*.swp,*.zip " MacOSX/Linux 62 | set wildignore+=*\\tmp\\*,*.swp,*.zip,*.exe " Windows 63 | 64 | let g:ctrlp_custom_ignore = '\v[\/]\.(git|hg|svn)$' 65 | let g:ctrlp_custom_ignore = { 66 | \ 'dir': '\v[\/]\.(git|hg|svn)$', 67 | \ 'file': '\v\.(exe|so|dll)$', 68 | \ 'link': 'some_bad_symbolic_links', 69 | \ } 70 | ``` 71 | 72 | * Use a custom file listing command: 73 | 74 | ```vim 75 | let g:ctrlp_user_command = 'find %s -type f' " MacOSX/Linux 76 | let g:ctrlp_user_command = 'dir %s /-n /b /s /a-d' " Windows 77 | ``` 78 | 79 | Check `:help ctrlp-options` for other options. 80 | 81 | ## Installation 82 | Use your favorite method or check the homepage for a [quick installation guide][3]. 83 | 84 | [1]: http://i.imgur.com/yIynr.png 85 | [2]: https://github.com/kien/ctrlp.vim/tree/extensions 86 | [3]: http://kien.github.com/ctrlp.vim#installation 87 | -------------------------------------------------------------------------------- /autoload/ctrlp/utils.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/utils.vim 3 | " Description: Utilities 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Static variables {{{1 8 | fu! ctrlp#utils#lash() 9 | retu &ssl || !exists('+ssl') ? '/' : '\' 10 | endf 11 | 12 | fu! s:lash(...) 13 | retu ( a:0 ? a:1 : getcwd() ) !~ '[\/]$' ? s:lash : '' 14 | endf 15 | 16 | fu! ctrlp#utils#opts() 17 | let s:lash = ctrlp#utils#lash() 18 | let usrhome = $HOME.s:lash($HOME) 19 | let cahome = exists('$XDG_CACHE_HOME') ? $XDG_CACHE_HOME : usrhome.'.cache' 20 | let cadir = isdirectory(usrhome.'.ctrlp_cache') 21 | \ ? usrhome.'.ctrlp_cache' : cahome.s:lash(cahome).'ctrlp' 22 | if exists('g:ctrlp_cache_dir') 23 | let cadir = expand(g:ctrlp_cache_dir, 1) 24 | if isdirectory(cadir.s:lash(cadir).'.ctrlp_cache') 25 | let cadir = cadir.s:lash(cadir).'.ctrlp_cache' 26 | en 27 | en 28 | let s:cache_dir = cadir 29 | endf 30 | cal ctrlp#utils#opts() 31 | 32 | let s:wig_cond = v:version > 702 || ( v:version == 702 && has('patch051') ) 33 | " Files and Directories {{{1 34 | fu! ctrlp#utils#cachedir() 35 | retu s:cache_dir 36 | endf 37 | 38 | fu! ctrlp#utils#cachefile(...) 39 | let [tail, dir] = [a:0 == 1 ? '.'.a:1 : '', a:0 == 2 ? a:1 : getcwd()] 40 | let cache_file = substitute(dir, '\([\/]\|^\a\zs:\)', '%', 'g').tail.'.txt' 41 | retu a:0 == 1 ? cache_file : s:cache_dir.s:lash(s:cache_dir).cache_file 42 | endf 43 | 44 | fu! ctrlp#utils#readfile(file) 45 | if filereadable(a:file) 46 | let data = readfile(a:file) 47 | if empty(data) || type(data) != 3 48 | unl data 49 | let data = [] 50 | en 51 | retu data 52 | en 53 | retu [] 54 | endf 55 | 56 | fu! ctrlp#utils#mkdir(dir) 57 | if exists('*mkdir') && !isdirectory(a:dir) 58 | sil! cal mkdir(a:dir, 'p') 59 | en 60 | retu a:dir 61 | endf 62 | 63 | fu! ctrlp#utils#writecache(lines, ...) 64 | if isdirectory(ctrlp#utils#mkdir(a:0 ? a:1 : s:cache_dir)) 65 | sil! cal writefile(a:lines, a:0 >= 2 ? a:2 : ctrlp#utils#cachefile()) 66 | en 67 | endf 68 | 69 | fu! ctrlp#utils#glob(...) 70 | let path = ctrlp#utils#fnesc(a:1, 'g') 71 | retu s:wig_cond ? glob(path, a:2) : glob(path) 72 | endf 73 | 74 | fu! ctrlp#utils#globpath(...) 75 | retu call('globpath', s:wig_cond ? a:000 : a:000[:1]) 76 | endf 77 | 78 | fu! ctrlp#utils#fnesc(path, type, ...) 79 | if exists('*fnameescape') 80 | if exists('+ssl') 81 | if a:type == 'c' 82 | let path = escape(a:path, '%#') 83 | elsei a:type == 'f' 84 | let path = fnameescape(a:path) 85 | elsei a:type == 'g' 86 | let path = escape(a:path, '?*') 87 | en 88 | let path = substitute(path, '[', '[[]', 'g') 89 | el 90 | let path = fnameescape(a:path) 91 | en 92 | el 93 | if exists('+ssl') 94 | if a:type == 'c' 95 | let path = escape(a:path, '%#') 96 | elsei a:type == 'f' 97 | let path = escape(a:path, " \t\n%#*?|<\"") 98 | elsei a:type == 'g' 99 | let path = escape(a:path, '?*') 100 | en 101 | let path = substitute(path, '[', '[[]', 'g') 102 | el 103 | let path = escape(a:path, " \t\n*?[{`$\\%#'\"|!<") 104 | en 105 | en 106 | retu a:0 ? escape(path, a:1) : path 107 | endf 108 | 109 | fu! ctrlp#utils#dircompl(...) 110 | let [hsl, str] = [match(a:1, '[\/]'), ''] 111 | let par = substitute(a:1, '[^\/]*$', '', '') 112 | let path = !hsl ? par : hsl > 0 ? getcwd().s:lash().par : getcwd() 113 | for dir in split(globpath(ctrlp#utils#fnesc(path, 'g', ','), '*/'), '\n') 114 | let str .= par.split(dir, '[\/]')[-1]."\n" 115 | endfo 116 | retu str 117 | endf 118 | "}}} 119 | 120 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 121 | -------------------------------------------------------------------------------- /autoload/ctrlp/bookmarkdir.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/bookmarkdir.vim 3 | " Description: Bookmarked directories extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if exists('g:loaded_ctrlp_bookmarkdir') && g:loaded_ctrlp_bookmarkdir 9 | fini 10 | en 11 | let g:loaded_ctrlp_bookmarkdir = 1 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#bookmarkdir#init()', 15 | \ 'accept': 'ctrlp#bookmarkdir#accept', 16 | \ 'lname': 'bookmarked dirs', 17 | \ 'sname': 'bkd', 18 | \ 'type': 'tabs', 19 | \ 'opmul': 1, 20 | \ 'nolim': 1, 21 | \ 'wipe': 'ctrlp#bookmarkdir#remove', 22 | \ }) 23 | 24 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 25 | " Utilities {{{1 26 | fu! s:getinput(str, ...) 27 | echoh Identifier 28 | cal inputsave() 29 | let input = call('input', a:0 ? [a:str] + a:000 : [a:str]) 30 | cal inputrestore() 31 | echoh None 32 | retu input 33 | endf 34 | 35 | fu! s:cachefile() 36 | if !exists('s:cadir') || !exists('s:cafile') 37 | let s:cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'bkd' 38 | let s:cafile = s:cadir.ctrlp#utils#lash().'cache.txt' 39 | en 40 | retu s:cafile 41 | endf 42 | 43 | fu! s:writecache(lines) 44 | cal ctrlp#utils#writecache(a:lines, s:cadir, s:cafile) 45 | endf 46 | 47 | fu! s:getbookmarks() 48 | retu ctrlp#utils#readfile(s:cachefile()) 49 | endf 50 | 51 | fu! s:savebookmark(name, cwd) 52 | let cwds = exists('+ssl') ? [tr(a:cwd, '\', '/'), tr(a:cwd, '/', '\')] : [a:cwd] 53 | let entries = filter(s:getbookmarks(), 'index(cwds, s:parts(v:val)[1]) < 0') 54 | cal s:writecache(insert(entries, a:name.' '.a:cwd)) 55 | endf 56 | 57 | fu! s:setentries() 58 | let time = getftime(s:cachefile()) 59 | if !( exists('s:bookmarks') && time == s:bookmarks[0] ) 60 | let s:bookmarks = [time, s:getbookmarks()] 61 | en 62 | endf 63 | 64 | fu! s:parts(str) 65 | let mlist = matchlist(a:str, '\v([^\t]+)\t(.*)$') 66 | retu mlist != [] ? mlist[1:2] : ['', ''] 67 | endf 68 | 69 | fu! s:process(entries, type) 70 | retu map(a:entries, 's:modify(v:val, a:type)') 71 | endf 72 | 73 | fu! s:modify(entry, type) 74 | let [name, dir] = s:parts(a:entry) 75 | let dir = fnamemodify(dir, a:type) 76 | retu name.' '.( dir == '' ? '.' : dir ) 77 | endf 78 | 79 | fu! s:msg(name, cwd) 80 | redr 81 | echoh Identifier | echon 'Bookmarked ' | echoh Constant 82 | echon a:name.' ' | echoh Directory | echon a:cwd 83 | echoh None 84 | endf 85 | 86 | fu! s:syntax() 87 | if !ctrlp#nosy() 88 | cal ctrlp#hicheck('CtrlPBookmark', 'Identifier') 89 | cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') 90 | sy match CtrlPBookmark '^> [^\t]\+' contains=CtrlPLinePre 91 | sy match CtrlPTabExtra '\zs\t.*\ze$' 92 | en 93 | endf 94 | " Public {{{1 95 | fu! ctrlp#bookmarkdir#init() 96 | cal s:setentries() 97 | cal s:syntax() 98 | retu s:process(copy(s:bookmarks[1]), ':.') 99 | endf 100 | 101 | fu! ctrlp#bookmarkdir#accept(mode, str) 102 | let parts = s:parts(s:modify(a:str, ':p')) 103 | cal call('s:savebookmark', parts) 104 | if a:mode =~ 't\|v\|h' 105 | cal ctrlp#exit() 106 | en 107 | cal ctrlp#setdir(parts[1], a:mode =~ 't\|h' ? 'chd!' : 'lc!') 108 | if a:mode == 'e' 109 | cal ctrlp#switchtype(0) 110 | cal ctrlp#recordhist() 111 | cal ctrlp#prtclear() 112 | en 113 | endf 114 | 115 | fu! ctrlp#bookmarkdir#add(dir) 116 | let str = 'Directory to bookmark: ' 117 | let cwd = a:dir != '' ? a:dir : s:getinput(str, getcwd(), 'dir') 118 | if cwd == '' | retu | en 119 | let cwd = fnamemodify(cwd, ':p') 120 | let name = s:getinput('Bookmark as: ', cwd) 121 | if name == '' | retu | en 122 | let name = tr(name, ' ', ' ') 123 | cal s:savebookmark(name, cwd) 124 | cal s:msg(name, cwd) 125 | endf 126 | 127 | fu! ctrlp#bookmarkdir#remove(entries) 128 | cal s:process(a:entries, ':p') 129 | cal s:writecache(a:entries == [] ? [] : 130 | \ filter(s:getbookmarks(), 'index(a:entries, v:val) < 0')) 131 | cal s:setentries() 132 | retu s:process(copy(s:bookmarks[1]), ':.') 133 | endf 134 | 135 | fu! ctrlp#bookmarkdir#id() 136 | retu s:id 137 | endf 138 | "}}} 139 | 140 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 141 | -------------------------------------------------------------------------------- /autoload/ctrlp/undo.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/undo.vim 3 | " Description: Undo extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Init {{{1 8 | if ( exists('g:loaded_ctrlp_undo') && g:loaded_ctrlp_undo ) 9 | fini 10 | en 11 | let g:loaded_ctrlp_undo = 1 12 | 13 | cal add(g:ctrlp_ext_vars, { 14 | \ 'init': 'ctrlp#undo#init()', 15 | \ 'accept': 'ctrlp#undo#accept', 16 | \ 'lname': 'undo', 17 | \ 'sname': 'udo', 18 | \ 'enter': 'ctrlp#undo#enter()', 19 | \ 'exit': 'ctrlp#undo#exit()', 20 | \ 'type': 'line', 21 | \ 'sort': 0, 22 | \ 'nolim': 1, 23 | \ }) 24 | 25 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 26 | 27 | let s:text = map(['second', 'seconds', 'minutes', 'hours', 'days', 'weeks', 28 | \ 'months', 'years'], '" ".v:val." ago"') 29 | " Utilities {{{1 30 | fu! s:getundo() 31 | if exists('*undotree') 32 | \ && ( v:version > 703 || ( v:version == 703 && has('patch005') ) ) 33 | retu [1, undotree()] 34 | el 35 | redi => result 36 | sil! undol 37 | redi END 38 | retu [0, split(result, "\n")[1:]] 39 | en 40 | endf 41 | 42 | fu! s:flatten(tree, cur) 43 | let flatdict = {} 44 | for each in a:tree 45 | let saved = has_key(each, 'save') ? 'saved' : '' 46 | let current = each['seq'] == a:cur ? 'current' : '' 47 | cal extend(flatdict, { each['seq'] : [each['time'], saved, current] }) 48 | if has_key(each, 'alt') 49 | cal extend(flatdict, s:flatten(each['alt'], a:cur)) 50 | en 51 | endfo 52 | retu flatdict 53 | endf 54 | 55 | fu! s:elapsed(nr) 56 | let [text, time] = [s:text, localtime() - a:nr] 57 | let mins = time / 60 58 | let hrs = time / 3600 59 | let days = time / 86400 60 | let wks = time / 604800 61 | let mons = time / 2592000 62 | let yrs = time / 31536000 63 | if yrs > 1 64 | retu yrs.text[7] 65 | elsei mons > 1 66 | retu mons.text[6] 67 | elsei wks > 1 68 | retu wks.text[5] 69 | elsei days > 1 70 | retu days.text[4] 71 | elsei hrs > 1 72 | retu hrs.text[3] 73 | elsei mins > 1 74 | retu mins.text[2] 75 | elsei time == 1 76 | retu time.text[0] 77 | elsei time < 120 78 | retu time.text[1] 79 | en 80 | endf 81 | 82 | fu! s:syntax() 83 | if ctrlp#nosy() | retu | en 84 | for [ke, va] in items({'T': 'Directory', 'Br': 'Comment', 'Nr': 'String', 85 | \ 'Sv': 'Comment', 'Po': 'Title'}) 86 | cal ctrlp#hicheck('CtrlPUndo'.ke, va) 87 | endfo 88 | sy match CtrlPUndoT '\v\d+ \zs[^ ]+\ze|\d+:\d+:\d+' 89 | sy match CtrlPUndoBr '\[\|\]' 90 | sy match CtrlPUndoNr '\[\d\+\]' contains=CtrlPUndoBr 91 | sy match CtrlPUndoSv 'saved' 92 | sy match CtrlPUndoPo 'current' 93 | endf 94 | 95 | fu! s:dict2list(dict) 96 | for ke in keys(a:dict) 97 | let a:dict[ke][0] = s:elapsed(a:dict[ke][0]) 98 | endfo 99 | retu map(keys(a:dict), 'eval(''[v:val, a:dict[v:val]]'')') 100 | endf 101 | 102 | fu! s:compval(...) 103 | retu a:2[0] - a:1[0] 104 | endf 105 | 106 | fu! s:format(...) 107 | let saved = !empty(a:1[1][1]) ? ' '.a:1[1][1] : '' 108 | let current = !empty(a:1[1][2]) ? ' '.a:1[1][2] : '' 109 | retu a:1[1][0].' ['.a:1[0].']'.saved.current 110 | endf 111 | 112 | fu! s:formatul(...) 113 | let parts = matchlist(a:1, 114 | \ '\v^\s+(\d+)\s+\d+\s+([^ ]+\s?[^ ]+|\d+\s\w+\s\w+)(\s*\d*)$') 115 | retu parts == [] ? '----' 116 | \ : parts[2].' ['.parts[1].']'.( parts[3] != '' ? ' saved' : '' ) 117 | endf 118 | " Public {{{1 119 | fu! ctrlp#undo#init() 120 | let entries = s:undos[0] ? s:undos[1]['entries'] : s:undos[1] 121 | if empty(entries) | retu [] | en 122 | if !exists('s:lines') 123 | if s:undos[0] 124 | let entries = s:dict2list(s:flatten(entries, s:undos[1]['seq_cur'])) 125 | let s:lines = map(sort(entries, 's:compval'), 's:format(v:val)') 126 | el 127 | let s:lines = map(reverse(entries), 's:formatul(v:val)') 128 | en 129 | en 130 | cal s:syntax() 131 | retu s:lines 132 | endf 133 | 134 | fu! ctrlp#undo#accept(mode, str) 135 | let undon = matchstr(a:str, '\[\zs\d\+\ze\]') 136 | if empty(undon) | retu | en 137 | cal ctrlp#exit() 138 | exe 'u' undon 139 | endf 140 | 141 | fu! ctrlp#undo#id() 142 | retu s:id 143 | endf 144 | 145 | fu! ctrlp#undo#enter() 146 | let s:undos = s:getundo() 147 | endf 148 | 149 | fu! ctrlp#undo#exit() 150 | unl! s:lines 151 | endf 152 | "}}} 153 | 154 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 155 | -------------------------------------------------------------------------------- /autoload/ctrlp/mrufiles.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/mrufiles.vim 3 | " Description: Most Recently Used Files extension 4 | " Author: Kien Nguyen 5 | " ============================================================================= 6 | 7 | " Static variables {{{1 8 | let [s:mrbs, s:mrufs] = [[], []] 9 | 10 | fu! ctrlp#mrufiles#opts() 11 | let [pref, opts] = ['g:ctrlp_mruf_', { 12 | \ 'max': ['s:max', 250], 13 | \ 'include': ['s:in', ''], 14 | \ 'exclude': ['s:ex', ''], 15 | \ 'case_sensitive': ['s:cseno', 1], 16 | \ 'relative': ['s:re', 0], 17 | \ 'save_on_update': ['s:soup', 1], 18 | \ }] 19 | for [ke, va] in items(opts) 20 | let [{va[0]}, {pref.ke}] = [pref.ke, exists(pref.ke) ? {pref.ke} : va[1]] 21 | endfo 22 | endf 23 | cal ctrlp#mrufiles#opts() 24 | " Utilities {{{1 25 | fu! s:excl(fn) 26 | retu !empty({s:ex}) && a:fn =~# {s:ex} 27 | endf 28 | 29 | fu! s:mergelists() 30 | let diskmrufs = ctrlp#utils#readfile(ctrlp#mrufiles#cachefile()) 31 | cal filter(diskmrufs, 'index(s:mrufs, v:val) < 0') 32 | let mrufs = s:mrufs + diskmrufs 33 | retu s:chop(mrufs) 34 | endf 35 | 36 | fu! s:chop(mrufs) 37 | if len(a:mrufs) > {s:max} | cal remove(a:mrufs, {s:max}, -1) | en 38 | retu a:mrufs 39 | endf 40 | 41 | fu! s:reformat(mrufs) 42 | let cwd = getcwd() 43 | let cwd .= cwd !~ '[\/]$' ? ctrlp#utils#lash() : '' 44 | if {s:re} 45 | let cwd = exists('+ssl') ? tr(cwd, '/', '\') : cwd 46 | cal filter(a:mrufs, '!stridx(v:val, cwd)') 47 | en 48 | let idx = strlen(cwd) 49 | if exists('+ssl') && &ssl 50 | let cwd = tr(cwd, '\', '/') 51 | cal map(a:mrufs, 'tr(v:val, "\\", "/")') 52 | en 53 | retu map(a:mrufs, '!stridx(v:val, cwd) ? strpart(v:val, idx) : v:val') 54 | endf 55 | 56 | fu! s:record(bufnr) 57 | if s:locked | retu | en 58 | let bufnr = a:bufnr + 0 59 | let bufname = bufname(bufnr) 60 | if bufnr > 0 && !empty(bufname) 61 | cal filter(s:mrbs, 'v:val != bufnr') 62 | cal insert(s:mrbs, bufnr) 63 | cal s:addtomrufs(bufname) 64 | en 65 | endf 66 | 67 | fu! s:addtomrufs(fname) 68 | let fn = fnamemodify(a:fname, ':p') 69 | let fn = exists('+ssl') ? tr(fn, '/', '\') : fn 70 | if ( !empty({s:in}) && fn !~# {s:in} ) || ( !empty({s:ex}) && fn =~# {s:ex} ) 71 | \ || !empty(getbufvar('^'.fn.'$', '&bt')) || !filereadable(fn) | retu 72 | en 73 | let idx = index(s:mrufs, fn, 0, !{s:cseno}) 74 | if idx 75 | cal filter(s:mrufs, 'v:val !='.( {s:cseno} ? '#' : '?' ).' fn') 76 | cal insert(s:mrufs, fn) 77 | if {s:soup} && idx < 0 78 | cal s:savetofile(s:mergelists()) 79 | en 80 | en 81 | endf 82 | 83 | fu! s:savetofile(mrufs) 84 | cal ctrlp#utils#writecache(a:mrufs, s:cadir, s:cafile) 85 | endf 86 | " Public {{{1 87 | fu! ctrlp#mrufiles#refresh(...) 88 | let mrufs = s:mergelists() 89 | cal filter(mrufs, '!empty(ctrlp#utils#glob(v:val, 1)) && !s:excl(v:val)') 90 | if exists('+ssl') 91 | cal map(mrufs, 'tr(v:val, "/", "\\")') 92 | cal map(s:mrufs, 'tr(v:val, "/", "\\")') 93 | let cond = 'count(mrufs, v:val, !{s:cseno}) == 1' 94 | cal filter(mrufs, cond) 95 | cal filter(s:mrufs, cond) 96 | en 97 | cal s:savetofile(mrufs) 98 | retu a:0 && a:1 == 'raw' ? [] : s:reformat(mrufs) 99 | endf 100 | 101 | fu! ctrlp#mrufiles#remove(files) 102 | let mrufs = [] 103 | if a:files != [] 104 | let mrufs = s:mergelists() 105 | let cond = 'index(a:files, v:val, 0, !{s:cseno}) < 0' 106 | cal filter(mrufs, cond) 107 | cal filter(s:mrufs, cond) 108 | en 109 | cal s:savetofile(mrufs) 110 | retu s:reformat(mrufs) 111 | endf 112 | 113 | fu! ctrlp#mrufiles#add(fn) 114 | if !empty(a:fn) 115 | cal s:addtomrufs(a:fn) 116 | en 117 | endf 118 | 119 | fu! ctrlp#mrufiles#list(...) 120 | retu a:0 ? a:1 == 'raw' ? s:mergelists() : 0 : s:reformat(s:mergelists()) 121 | endf 122 | 123 | fu! ctrlp#mrufiles#bufs() 124 | retu s:mrbs 125 | endf 126 | 127 | fu! ctrlp#mrufiles#cachefile() 128 | if !exists('s:cadir') || !exists('s:cafile') 129 | let s:cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'mru' 130 | let s:cafile = s:cadir.ctrlp#utils#lash().'cache.txt' 131 | en 132 | retu s:cafile 133 | endf 134 | 135 | fu! ctrlp#mrufiles#init() 136 | if !has('autocmd') | retu | en 137 | let s:locked = 0 138 | aug CtrlPMRUF 139 | au! 140 | au BufAdd,BufEnter,BufLeave,BufWritePost * cal s:record(expand('', 1)) 141 | au QuickFixCmdPre *vimgrep* let s:locked = 1 142 | au QuickFixCmdPost *vimgrep* let s:locked = 0 143 | au VimLeavePre * cal s:savetofile(s:mergelists()) 144 | aug END 145 | endf 146 | "}}} 147 | 148 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 149 | -------------------------------------------------------------------------------- /autoload/ctrlp/buffertag.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp/buffertag.vim 3 | " Description: Buffer Tag extension 4 | " Maintainer: Kien Nguyen 5 | " Credits: Much of the code was taken from tagbar.vim by Jan Larres, plus 6 | " a few lines from taglist.vim by Yegappan Lakshmanan and from 7 | " buffertag.vim by Takeshi Nishida. 8 | " ============================================================================= 9 | 10 | " Init {{{1 11 | if exists('g:loaded_ctrlp_buftag') && g:loaded_ctrlp_buftag 12 | fini 13 | en 14 | let g:loaded_ctrlp_buftag = 1 15 | 16 | cal add(g:ctrlp_ext_vars, { 17 | \ 'init': 'ctrlp#buffertag#init(s:crfile)', 18 | \ 'accept': 'ctrlp#buffertag#accept', 19 | \ 'lname': 'buffer tags', 20 | \ 'sname': 'bft', 21 | \ 'exit': 'ctrlp#buffertag#exit()', 22 | \ 'type': 'tabs', 23 | \ 'opts': 'ctrlp#buffertag#opts()', 24 | \ }) 25 | 26 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 27 | 28 | let [s:pref, s:opts] = ['g:ctrlp_buftag_', { 29 | \ 'systemenc': ['s:enc', &enc], 30 | \ 'ctags_bin': ['s:bin', ''], 31 | \ 'types': ['s:usr_types', {}], 32 | \ }] 33 | 34 | let s:bins = [ 35 | \ 'ctags-exuberant', 36 | \ 'exuberant-ctags', 37 | \ 'exctags', 38 | \ '/usr/local/bin/ctags', 39 | \ '/opt/local/bin/ctags', 40 | \ 'ctags', 41 | \ 'ctags.exe', 42 | \ 'tags', 43 | \ ] 44 | 45 | let s:types = { 46 | \ 'asm' : '%sasm%sasm%sdlmt', 47 | \ 'aspperl': '%sasp%sasp%sfsv', 48 | \ 'aspvbs' : '%sasp%sasp%sfsv', 49 | \ 'awk' : '%sawk%sawk%sf', 50 | \ 'beta' : '%sbeta%sbeta%sfsv', 51 | \ 'c' : '%sc%sc%sdgsutvf', 52 | \ 'cpp' : '%sc++%sc++%snvdtcgsuf', 53 | \ 'cs' : '%sc#%sc#%sdtncEgsipm', 54 | \ 'cobol' : '%scobol%scobol%sdfgpPs', 55 | \ 'eiffel' : '%seiffel%seiffel%scf', 56 | \ 'erlang' : '%serlang%serlang%sdrmf', 57 | \ 'expect' : '%stcl%stcl%scfp', 58 | \ 'fortran': '%sfortran%sfortran%spbceiklmntvfs', 59 | \ 'html' : '%shtml%shtml%saf', 60 | \ 'java' : '%sjava%sjava%spcifm', 61 | \ 'javascript': '%sjavascript%sjavascript%sf', 62 | \ 'lisp' : '%slisp%slisp%sf', 63 | \ 'lua' : '%slua%slua%sf', 64 | \ 'make' : '%smake%smake%sm', 65 | \ 'pascal' : '%spascal%spascal%sfp', 66 | \ 'perl' : '%sperl%sperl%sclps', 67 | \ 'php' : '%sphp%sphp%scdvf', 68 | \ 'python' : '%spython%spython%scmf', 69 | \ 'rexx' : '%srexx%srexx%ss', 70 | \ 'ruby' : '%sruby%sruby%scfFm', 71 | \ 'scheme' : '%sscheme%sscheme%ssf', 72 | \ 'sh' : '%ssh%ssh%sf', 73 | \ 'csh' : '%ssh%ssh%sf', 74 | \ 'zsh' : '%ssh%ssh%sf', 75 | \ 'slang' : '%sslang%sslang%snf', 76 | \ 'sml' : '%ssml%ssml%secsrtvf', 77 | \ 'sql' : '%ssql%ssql%scFPrstTvfp', 78 | \ 'tcl' : '%stcl%stcl%scfmp', 79 | \ 'vera' : '%svera%svera%scdefgmpPtTvx', 80 | \ 'verilog': '%sverilog%sverilog%smcPertwpvf', 81 | \ 'vim' : '%svim%svim%savf', 82 | \ 'yacc' : '%syacc%syacc%sl', 83 | \ } 84 | 85 | cal map(s:types, 'printf(v:val, "--language-force=", " --", "-types=")') 86 | 87 | if executable('jsctags') 88 | cal extend(s:types, { 'javascript': { 'args': '-f -', 'bin': 'jsctags' } }) 89 | en 90 | 91 | fu! ctrlp#buffertag#opts() 92 | for [ke, va] in items(s:opts) 93 | let {va[0]} = exists(s:pref.ke) ? {s:pref.ke} : va[1] 94 | endfo 95 | " Ctags bin 96 | if empty(s:bin) 97 | for bin in s:bins | if executable(bin) 98 | let s:bin = bin 99 | brea 100 | en | endfo 101 | el 102 | let s:bin = expand(s:bin, 1) 103 | en 104 | " Types 105 | cal extend(s:types, s:usr_types) 106 | endf 107 | " Utilities {{{1 108 | fu! s:validfile(fname, ftype) 109 | if ( !empty(a:fname) || !empty(a:ftype) ) && filereadable(a:fname) 110 | \ && index(keys(s:types), a:ftype) >= 0 | retu 1 | en 111 | retu 0 112 | endf 113 | 114 | fu! s:exectags(cmd) 115 | if exists('+ssl') 116 | let [ssl, &ssl] = [&ssl, 0] 117 | en 118 | if &sh =~ 'cmd\.exe' 119 | let [sxq, &sxq, shcf, &shcf] = [&sxq, '"', &shcf, '/s /c'] 120 | en 121 | let output = system(a:cmd) 122 | if &sh =~ 'cmd\.exe' 123 | let [&sxq, &shcf] = [sxq, shcf] 124 | en 125 | if exists('+ssl') 126 | let &ssl = ssl 127 | en 128 | retu output 129 | endf 130 | 131 | fu! s:exectagsonfile(fname, ftype) 132 | let [ags, ft] = ['-f - --sort=no --excmd=pattern --fields=nKs ', a:ftype] 133 | if type(s:types[ft]) == 1 134 | let ags .= s:types[ft] 135 | let bin = s:bin 136 | elsei type(s:types[ft]) == 4 137 | let ags = s:types[ft]['args'] 138 | let bin = expand(s:types[ft]['bin'], 1) 139 | en 140 | if empty(bin) | retu '' | en 141 | let cmd = s:esctagscmd(bin, ags, a:fname) 142 | if empty(cmd) | retu '' | en 143 | let output = s:exectags(cmd) 144 | if v:shell_error || output =~ 'Warning: cannot open' | retu '' | en 145 | retu output 146 | endf 147 | 148 | fu! s:esctagscmd(bin, args, ...) 149 | if exists('+ssl') 150 | let [ssl, &ssl] = [&ssl, 0] 151 | en 152 | let fname = a:0 ? shellescape(a:1) : '' 153 | let cmd = shellescape(a:bin).' '.a:args.' '.fname 154 | if &sh =~ 'cmd\.exe' 155 | let cmd = substitute(cmd, '[&()@^<>|]', '^\0', 'g') 156 | en 157 | if exists('+ssl') 158 | let &ssl = ssl 159 | en 160 | if has('iconv') 161 | let last = s:enc != &enc ? s:enc : !empty($LANG) ? $LANG : &enc 162 | let cmd = iconv(cmd, &enc, last) 163 | en 164 | retu cmd 165 | endf 166 | 167 | fu! s:process(fname, ftype) 168 | if !s:validfile(a:fname, a:ftype) | retu [] | endif 169 | let ftime = getftime(a:fname) 170 | if has_key(g:ctrlp_buftags, a:fname) 171 | \ && g:ctrlp_buftags[a:fname]['time'] >= ftime 172 | let lines = g:ctrlp_buftags[a:fname]['lines'] 173 | el 174 | let data = s:exectagsonfile(a:fname, a:ftype) 175 | let [raw, lines] = [split(data, '\n\+'), []] 176 | for line in raw 177 | if line !~# '^!_TAG_' && len(split(line, ';"')) == 2 178 | let parsed_line = s:parseline(line) 179 | if parsed_line != '' 180 | cal add(lines, parsed_line) 181 | en 182 | en 183 | endfo 184 | let cache = { a:fname : { 'time': ftime, 'lines': lines } } 185 | cal extend(g:ctrlp_buftags, cache) 186 | en 187 | retu lines 188 | endf 189 | 190 | fu! s:parseline(line) 191 | let vals = matchlist(a:line, 192 | \ '\v^([^\t]+)\t(.+)\t[?/]\^?(.{-1,})\$?[?/]\;\"\t(.+)\tline(no)?\:(\d+)') 193 | if vals == [] | retu '' | en 194 | let [bufnr, bufname] = [bufnr('^'.vals[2].'$'), fnamemodify(vals[2], ':p:t')] 195 | retu vals[1].' '.vals[4].'|'.bufnr.':'.bufname.'|'.vals[6].'| '.vals[3] 196 | endf 197 | 198 | fu! s:syntax() 199 | if !ctrlp#nosy() 200 | cal ctrlp#hicheck('CtrlPTagKind', 'Title') 201 | cal ctrlp#hicheck('CtrlPBufName', 'Directory') 202 | cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') 203 | sy match CtrlPTagKind '\zs[^\t|]\+\ze|\d\+:[^|]\+|\d\+|' 204 | sy match CtrlPBufName '|\d\+:\zs[^|]\+\ze|\d\+|' 205 | sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName,CtrlPTagKind 206 | en 207 | endf 208 | 209 | fu! s:chknearby(pat) 210 | if match(getline('.'), a:pat) < 0 211 | let [int, forw, maxl] = [1, 1, line('$')] 212 | wh !search(a:pat, 'W'.( forw ? '' : 'b' )) 213 | if !forw 214 | if int > maxl | brea | en 215 | let int += int 216 | en 217 | let forw = !forw 218 | endw 219 | en 220 | endf 221 | " Public {{{1 222 | fu! ctrlp#buffertag#init(fname) 223 | let bufs = exists('s:btmode') && s:btmode 224 | \ ? filter(ctrlp#buffers(), 'filereadable(v:val)') 225 | \ : [exists('s:bufname') ? s:bufname : a:fname] 226 | let lines = [] 227 | for each in bufs 228 | let bname = fnamemodify(each, ':p') 229 | let tftype = get(split(getbufvar('^'.bname.'$', '&ft'), '\.'), 0, '') 230 | cal extend(lines, s:process(bname, tftype)) 231 | endfo 232 | cal s:syntax() 233 | retu lines 234 | endf 235 | 236 | fu! ctrlp#buffertag#accept(mode, str) 237 | let vals = matchlist(a:str, 238 | \ '\v^[^\t]+\t+[^\t|]+\|(\d+)\:[^\t|]+\|(\d+)\|\s(.+)$') 239 | let bufnr = str2nr(get(vals, 1)) 240 | if bufnr 241 | cal ctrlp#acceptfile(a:mode, bufname(bufnr)) 242 | exe 'norm!' str2nr(get(vals, 2, line('.'))).'G' 243 | cal s:chknearby('\V\C'.get(vals, 3, '')) 244 | sil! norm! zvzz 245 | en 246 | endf 247 | 248 | fu! ctrlp#buffertag#cmd(mode, ...) 249 | let s:btmode = a:mode 250 | if a:0 && !empty(a:1) 251 | let s:bufname = fnamemodify(a:1, ':p') 252 | en 253 | retu s:id 254 | endf 255 | 256 | fu! ctrlp#buffertag#exit() 257 | unl! s:btmode s:bufname 258 | endf 259 | "}}} 260 | 261 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 262 | -------------------------------------------------------------------------------- /doc/ctrlp.txt: -------------------------------------------------------------------------------- 1 | *ctrlp.txt* Fuzzy file, buffer, mru, tag, ... finder. v1.78 2 | *CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'* 3 | =============================================================================== 4 | # # 5 | # :::::::: ::::::::::: ::::::::: ::: ::::::::: # 6 | # :+: :+: :+: :+: :+: :+: :+: :+: # 7 | # +:+ +:+ +:+ +:+ +:+ +:+ +:+ # 8 | # +#+ +#+ +#++:++#: +#+ +#++:++#+ # 9 | # +#+ +#+ +#+ +#+ +#+ +#+ # 10 | # #+# #+# #+# #+# #+# #+# #+# # 11 | # ######## ### ### ### ########## ### # 12 | # # 13 | =============================================================================== 14 | CONTENTS *ctrlp-contents* 15 | 16 | 1. Intro........................................|ctrlp-intro| 17 | 2. Options......................................|ctrlp-options| 18 | 3. Commands.....................................|ctrlp-commands| 19 | 4. Mappings.....................................|ctrlp-mappings| 20 | 5. Input Formats................................|ctrlp-input-formats| 21 | 6. Extensions...................................|ctrlp-extensions| 22 | 23 | =============================================================================== 24 | INTRO *ctrlp-intro* 25 | 26 | Full path fuzzy file, buffer, mru, tag, ... finder with an intuitive interface. 27 | Written in pure Vimscript for MacVim, gVim and Vim version 7.0+. Has full 28 | support for Vim's |regexp| as search pattern, built-in MRU files monitoring, 29 | project's root finder, and more. 30 | 31 | To enable optional extensions (tag, dir, rtscript...), see |ctrlp-extensions|. 32 | 33 | =============================================================================== 34 | OPTIONS *ctrlp-options* 35 | 36 | Overview:~ 37 | 38 | |loaded_ctrlp|................Disable the plugin. 39 | |ctrlp_map|...................Default mapping. 40 | |ctrlp_cmd|...................Default command used for the default mapping. 41 | |ctrlp_by_filename|...........Default to filename mode or not. 42 | |ctrlp_regexp|................Default to regexp mode or not. 43 | |ctrlp_match_window_bottom|...Where to show the match window. 44 | |ctrlp_match_window_reversed|.Sort order in the match window. 45 | |ctrlp_max_height|............Max height of the match window. 46 | |ctrlp_switch_buffer|.........Jump to an open buffer if already opened. 47 | |ctrlp_reuse_window|..........Reuse special windows (help, quickfix, etc). 48 | |ctrlp_tabpage_position|......Where to put the new tab page. 49 | |ctrlp_working_path_mode|.....How to set CtrlP's local working directory. 50 | |ctrlp_root_markers|..........Additional, high priority root markers. 51 | |ctrlp_use_caching|...........Use per-session caching or not. 52 | |ctrlp_clear_cache_on_exit|...Keep cache after exiting Vim or not. 53 | |ctrlp_cache_dir|.............Location of the cache directory. 54 | |ctrlp_show_hidden|...........Ignore dotfiles and dotdirs or not. 55 | |ctrlp_custom_ignore|.........Hide stuff when using |globpath()|. 56 | |ctrlp_max_files|.............Number of files to scan initially. 57 | |ctrlp_max_depth|.............Directory depth to recurse into when scanning. 58 | |ctrlp_user_command|..........Use an external scanner. 59 | |ctrlp_max_history|...........Number of entries saved in the prompt history. 60 | |ctrlp_open_new_file|.........How to open a file created by . 61 | |ctrlp_open_multiple_files|...How to open files selected by . 62 | |ctrlp_arg_map|...............Intercept and or not. 63 | |ctrlp_follow_symlinks|.......Follow symbolic links or not. 64 | |ctrlp_lazy_update|...........Only update when typing has stopped. 65 | |ctrlp_default_input|.........Seed the prompt with an initial string. 66 | |ctrlp_abbrev|................Input abbreviations. 67 | |ctrlp_key_loop|..............Use input looping for multi-byte input. 68 | |ctrlp_use_migemo|............Use Migemo patterns for Japanese filenames. 69 | |ctrlp_prompt_mappings|.......Change the mappings inside the prompt. 70 | 71 | MRU mode: 72 | |ctrlp_mruf_max|..............Max MRU entries to remember. 73 | |ctrlp_mruf_exclude|..........Files that shouldn't be remembered. 74 | |ctrlp_mruf_include|..........Files to be remembered. 75 | |ctrlp_mruf_relative|.........Show only MRU files in the working directory. 76 | |ctrlp_mruf_default_order|....Disable sorting. 77 | |ctrlp_mruf_case_sensitive|...MRU files are case sensitive or not. 78 | |ctrlp_mruf_save_on_update|...Save to disk whenever a new entry is added. 79 | 80 | Advanced options: 81 | |ctrlp_open_func|.............Use custom file opening functions. 82 | |ctrlp_status_func|...........Change CtrlP's two statuslines. 83 | |ctrlp_buffer_func|...........Call custom functions in the CtrlP buffer. 84 | |ctrlp_match_func|............Replace the built-in matching algorithm. 85 | 86 | ------------------------------------------------------------------------------- 87 | Detailed descriptions and default values:~ 88 | 89 | *'g:ctrlp_map'* 90 | Use this option to change the mapping to invoke CtrlP in |Normal| mode: > 91 | let g:ctrlp_map = '' 92 | < 93 | 94 | *'g:ctrlp_cmd'* 95 | Set the default opening command to use when pressing the above mapping: > 96 | let g:ctrlp_cmd = 'CtrlP' 97 | < 98 | 99 | *'g:loaded_ctrlp'* 100 | Use this to disable the plugin completely: > 101 | let g:loaded_ctrlp = 1 102 | < 103 | 104 | *'g:ctrlp_by_filename'* 105 | Set this to 1 to set searching by filename (as opposed to full path) as the 106 | default: > 107 | let g:ctrlp_by_filename = 0 108 | < 109 | Can be toggled on/off by pressing inside the prompt. 110 | 111 | *'g:ctrlp_regexp'* 112 | Set this to 1 to set regexp search as the default: > 113 | let g:ctrlp_regexp = 0 114 | < 115 | Can be toggled on/off by pressing inside the prompt. 116 | 117 | *'g:ctrlp_match_window_bottom'* 118 | Set this to 0 to show the match window at the top of the screen: > 119 | let g:ctrlp_match_window_bottom = 1 120 | < 121 | 122 | *'g:ctrlp_match_window_reversed'* 123 | Change the listing order of the files in the match window. The default setting 124 | (1) is from bottom to top: > 125 | let g:ctrlp_match_window_reversed = 1 126 | < 127 | 128 | *'g:ctrlp_max_height'* 129 | Set the maximum height of the match window: > 130 | let g:ctrlp_max_height = 10 131 | < 132 | 133 | *'g:ctrlp_switch_buffer'* 134 | When opening a file, if it's already open in a window somewhere, CtrlP will try 135 | to jump to it instead of opening a new instance: > 136 | let g:ctrlp_switch_buffer = 'Et' 137 | < 138 | e - jump when is pressed, but only to windows in the current tab. 139 | t - jump when is pressed, but only to windows in another tab. 140 | v - like "e", but jump when is pressed. 141 | h - like "e", but jump when is pressed. 142 | E, T, V, H - like "e", "t", "v", and "h", but jump to windows anywhere. 143 | 0 or - disable this feature. 144 | 145 | *'g:ctrlp_reuse_window'* 146 | When opening a file with , CtrlP avoids opening it in windows created by 147 | plugins, help and quickfix. Use this to setup some exceptions: > 148 | let g:ctrlp_reuse_window = 'netrw' 149 | < 150 | Acceptable values are partial name, filetype or buftype of the special buffers. 151 | Use regexp to specify the pattern. 152 | Example: > 153 | let g:ctrlp_reuse_window = 'netrw\|help\|quickfix' 154 | < 155 | 156 | *'g:ctrlp_tabpage_position'* 157 | Where to put the new tab page when opening one: > 158 | let g:ctrlp_tabpage_position = 'ac' 159 | < 160 | a - after. 161 | b - before. 162 | c - the current tab page. 163 | l - the last tab page. 164 | f - the first tab page. 165 | 166 | *'g:ctrlp_working_path_mode'* 167 | When starting up, CtrlP sets its local working directory according to this 168 | variable: > 169 | let g:ctrlp_working_path_mode = 'ra' 170 | < 171 | c - the directory of the current file. 172 | a - like "c", but only applies when the current working directory outside of 173 | CtrlP isn't a direct ancestor of the directory of the current file. 174 | r - the nearest ancestor that contains one of these directories or files: 175 | .git .hg .svn .bzr _darcs 176 | w - begin finding a root from the current working directory outside of CtrlP 177 | instead of from the directory of the current file (default). Only applies 178 | when "r" is also present. 179 | 0 or - disable this feature. 180 | 181 | Note #1: if "a" or "c" is included with "r", use the behavior of "a" or "c" (as 182 | a fallback) when a root can't be found. 183 | 184 | Note #2: you can use a |b:var| to set this option on a per buffer basis. 185 | 186 | *'g:ctrlp_root_markers'* 187 | Use this to set your own root markers in addition to the default ones (.git, 188 | .hg, .svn, .bzr, and _darcs). Your markers will take precedence: > 189 | let g:ctrlp_root_markers = [''] 190 | < 191 | Note: you can use a |b:var| to set this option on a per buffer basis. 192 | 193 | *'g:ctrlp_use_caching'* 194 | Enable/Disable per-session caching: > 195 | let g:ctrlp_use_caching = 1 196 | < 197 | 0 - Disable caching. 198 | 1 - Enable caching. 199 | n - When bigger than 1, disable caching and use the number as the limit to 200 | enable caching again. 201 | 202 | Note: you can quickly purge the cache by pressing while inside CtrlP. 203 | 204 | *'g:ctrlp_clear_cache_on_exit'* 205 | Set this to 0 to enable cross-session caching by not deleting the cache files 206 | upon exiting Vim: > 207 | let g:ctrlp_clear_cache_on_exit = 1 208 | < 209 | 210 | *'g:ctrlp_cache_dir'* 211 | Set the directory to store the cache files: > 212 | let g:ctrlp_cache_dir = $HOME.'/.cache/ctrlp' 213 | < 214 | 215 | *'g:ctrlp_show_hidden'* 216 | Set this to 1 if you want CtrlP to scan for dotfiles and dotdirs: > 217 | let g:ctrlp_show_hidden = 0 218 | < 219 | Note: does not apply when a command defined with |g:ctrlp_user_command| is 220 | being used. 221 | 222 | *'ctrlp-wildignore'* 223 | You can use Vim's |'wildignore'| to exclude files and directories from the 224 | results. 225 | Examples: > 226 | " Excluding version control directories 227 | set wildignore+=*/.git/*,*/.hg/*,*/.svn/* " Linux/MacOSX 228 | set wildignore+=*\\.git\\*,*\\.hg\\*,*\\.svn\\* " Windows ('noshellslash') 229 | < 230 | Note #1: the `*/` in front of each directory glob is required. 231 | 232 | Note #2: |wildignore| influences the result of |expand()|, |globpath()| and 233 | |glob()| which many plugins use to find stuff on the system (e.g. VCS related 234 | plugins look for .git/, .hg/,... some other plugins look for external *.exe 235 | tools on Windows). So be a little mindful of what you put in your |wildignore|. 236 | 237 | *'g:ctrlp_custom_ignore'* 238 | In addition to |'wildignore'|, use this for files and directories you want only 239 | CtrlP to not show. Use regexp to specify the patterns: > 240 | let g:ctrlp_custom_ignore = '' 241 | < 242 | Examples: > 243 | let g:ctrlp_custom_ignore = '\v[\/]\.(git|hg|svn)$' 244 | let g:ctrlp_custom_ignore = { 245 | \ 'dir': '\v[\/]\.(git|hg|svn)$', 246 | \ 'file': '\v\.(exe|so|dll)$', 247 | \ 'link': 'SOME_BAD_SYMBOLIC_LINKS', 248 | \ } 249 | let g:ctrlp_custom_ignore = { 250 | \ 'file': '\v(\.cpp|\.h|\.hh|\.cxx)@ 262 | let g:ctrlp_max_files = 10000 263 | < 264 | Note: does not apply when a command defined with |g:ctrlp_user_command| is 265 | being used. 266 | 267 | *'g:ctrlp_max_depth'* 268 | The maximum depth of a directory tree to recurse into: > 269 | let g:ctrlp_max_depth = 40 270 | < 271 | Note: does not apply when a command defined with |g:ctrlp_user_command| is 272 | being used. 273 | 274 | *'g:ctrlp_user_command'* 275 | Specify an external tool to use for listing files instead of using Vim's 276 | |globpath()|. Use %s in place of the target directory: > 277 | let g:ctrlp_user_command = '' 278 | < 279 | Examples: > 280 | let g:ctrlp_user_command = 'find %s -type f' " MacOSX/Linux 281 | let g:ctrlp_user_command = 'dir %s /-n /b /s /a-d' " Windows 282 | < 283 | You can also use 'grep', 'findstr' or something else to filter the results. 284 | Examples: > 285 | let g:ctrlp_user_command = 286 | \ 'find %s -type f | grep -v -P "\.jpg$|/tmp/"' " MacOSX/Linux 287 | let g:ctrlp_user_command = 288 | \ 'dir %s /-n /b /s /a-d | findstr /v /l ".jpg \\tmp\\"' " Windows 289 | < 290 | Use a version control listing command when inside a repository, this is faster 291 | when scanning large projects: > 292 | let g:ctrlp_user_command = [root_marker, listing_command, fallback_command] 293 | let g:ctrlp_user_command = { 294 | \ 'types': { 295 | \ 1: [root_marker_1, listing_command_1], 296 | \ n: [root_marker_n, listing_command_n], 297 | \ }, 298 | \ 'fallback': fallback_command, 299 | \ 'ignore': 0 or 1 300 | \ } 301 | < 302 | Some examples: > 303 | " Single VCS, listing command does not list untracked files: 304 | let g:ctrlp_user_command = ['.git', 'cd %s && git ls-files'] 305 | let g:ctrlp_user_command = ['.hg', 'hg --cwd %s locate -I .'] 306 | 307 | " Multiple VCS's: 308 | let g:ctrlp_user_command = { 309 | \ 'types': { 310 | \ 1: ['.git', 'cd %s && git ls-files'], 311 | \ 2: ['.hg', 'hg --cwd %s locate -I .'], 312 | \ }, 313 | \ 'fallback': 'find %s -type f' 314 | \ } 315 | 316 | " Single VCS, listing command lists untracked files (slower): 317 | let g:ctrlp_user_command = 318 | \ ['.git', 'cd %s && git ls-files . -co --exclude-standard'] 319 | 320 | let g:ctrlp_user_command = 321 | \ ['.hg', 'hg --cwd %s status -numac -I . $(hg root)'] " MacOSX/Linux 322 | 323 | let g:ctrlp_user_command = ['.hg', 'for /f "tokens=1" %%a in (''hg root'') ' 324 | \ . 'do hg --cwd %s status -numac -I . %%a'] " Windows 325 | < 326 | Note #1: if the fallback_command is empty or the 'fallback' key is not defined, 327 | |globpath()| will then be used when scanning outside of a repository. 328 | 329 | Note #2: unless the |Dictionary| format is used and 'ignore' is defined and set 330 | to 1, the |wildignore| and |g:ctrlp_custom_ignore| options do not apply when 331 | these custom commands are being used. When not present, 'ignore' is set to 0 by 332 | default to retain the performance advantage of using external commands. 333 | 334 | Note #3: when changing the option's variable type, remember to |:unlet| it 335 | first or restart Vim to avoid the "E706: Variable type mismatch" error. 336 | 337 | Note #4: you can use a |b:var| to set this option on a per buffer basis. 338 | 339 | *'g:ctrlp_max_history'* 340 | The maximum number of input strings you want CtrlP to remember. The default 341 | value mirrors Vim's global |'history'| option: > 342 | let g:ctrlp_max_history = &history 343 | < 344 | Set to 0 to disable prompt's history. Browse the history with and . 345 | 346 | *'g:ctrlp_open_new_file'* 347 | Use this option to specify how the newly created file is to be opened when 348 | pressing : > 349 | let g:ctrlp_open_new_file = 'v' 350 | < 351 | t - in a new tab. 352 | h - in a new horizontal split. 353 | v - in a new vertical split. 354 | r - in the current window. 355 | 356 | *'g:ctrlp_open_multiple_files'* 357 | If non-zero, this will enable opening multiple files with and : > 358 | let g:ctrlp_open_multiple_files = 'v' 359 | < 360 | Example: > 361 | let g:ctrlp_open_multiple_files = '2vjr' 362 | < 363 | For the number: 364 | - If given, it'll be used as the maximum number of windows or tabs to create 365 | when opening the files (the rest will be opened as hidden buffers). 366 | - If not given, will open all files, each in a new window or new tab. 367 | 368 | For the letters: 369 | t - each file in a new tab. 370 | h - each file in a new horizontal split. 371 | v - each file in a new vertical split. 372 | i - all files as hidden buffers. 373 | j - after opening, jump to the first opened tab or window. 374 | r - open the first file in the current window, then the remaining files in 375 | new splits or new tabs depending on which of "h", "v" and "t" is also 376 | present. 377 | 378 | *'g:ctrlp_arg_map'* 379 | When this is set to 1, the and mappings will accept one extra key 380 | as an argument to override their default behavior: > 381 | let g:ctrlp_arg_map = 0 382 | < 383 | Pressing or will then prompt for a keypress. The key can be: 384 | t - open in tab(s) 385 | h - open in horizontal split(s) 386 | v - open in vertical split(s) 387 | i - open as hidden buffers (for only) 388 | c - clear the marked files (for only) 389 | r - open in the current window (for only) 390 | , , - cancel and go back to the prompt. 391 | - use the default behavior specified with |g:ctrlp_open_new_file| and 392 | |g:ctrlp_open_multiple_files|. 393 | 394 | *'g:ctrlp_follow_symlinks'* 395 | If non-zero, CtrlP will follow symbolic links when listing files: > 396 | let g:ctrlp_follow_symlinks = 0 397 | < 398 | 0 - don't follow symbolic links. 399 | 1 - follow but ignore looped internal symlinks to avoid duplicates. 400 | 2 - follow all symlinks indiscriminately. 401 | 402 | Note: does not apply when a command defined with |g:ctrlp_user_command| is 403 | being used. 404 | 405 | *'g:ctrlp_lazy_update'* 406 | Set this to 1 to enable the lazy-update feature: only update the match window 407 | after typing's been stopped for a certain amount of time: > 408 | let g:ctrlp_lazy_update = 0 409 | < 410 | If is 1, update after 250ms. If bigger than 1, the number will be used as the 411 | delay time in milliseconds. 412 | 413 | *'g:ctrlp_default_input'* 414 | Set this to 1 to enable seeding the prompt with the current file's relative 415 | path: > 416 | let g:ctrlp_default_input = 0 417 | < 418 | Instead of 1 or 0, if the value of the option is a string, it'll be used as-is 419 | as the default input: > 420 | let g:ctrlp_default_input = 'anystring' 421 | < 422 | 423 | *'g:ctrlp_abbrev'* 424 | Define input abbreviations that can be expanded (either internally or visibly) 425 | in the prompt: > 426 | let g:ctrlp_abbrev = {} 427 | < 428 | Examples: > 429 | let g:ctrlp_abbrev = { 430 | \ 'gmode': 'i', 431 | \ 'abbrevs': [ 432 | \ { 433 | \ 'pattern': '^cd b', 434 | \ 'expanded': '@cd ~/.vim/bundle', 435 | \ 'mode': 'pfrz', 436 | \ }, 437 | \ { 438 | \ 'pattern': '\(^@.\+\|\\\@ (use the expanded string in the 465 | new filename). 466 | c - only when auto-completing directory names with (expand the pattern 467 | immediately before doing the auto-completion). 468 | or not defined - always enable. 469 | 470 | Note: the abbrev entries are evaluated in sequence, so a later entry can be 471 | evaluated against the expanded result of a previous entry; this includes itself 472 | when 'gmode' is "t". 473 | 474 | *'g:ctrlp_key_loop'* 475 | An experimental feature. Set this to 1 to enable input looping for the typing 476 | of multi-byte characters: > 477 | let g:ctrlp_key_loop = 0 478 | < 479 | Note #1: when set, this option resets the |g:ctrlp_lazy_update| option. 480 | 481 | Note #2: you can toggle this feature inside the prompt with a custom mapping: > 482 | let g:ctrlp_prompt_mappings = { 'ToggleKeyLoop()': [''] } 483 | < 484 | 485 | *'g:ctrlp_use_migemo'* 486 | Set this to 1 to use Migemo Pattern for Japanese filenames. Migemo Search only 487 | works in regexp mode. To split the pattern, separate words with space: > 488 | let g:ctrlp_use_migemo = 0 489 | < 490 | 491 | *'g:ctrlp_prompt_mappings'* 492 | Use this to customize the mappings inside CtrlP's prompt to your liking. You 493 | only need to keep the lines that you've changed the values (inside []): > 494 | let g:ctrlp_prompt_mappings = { 495 | \ 'PrtBS()': ['', ''], 496 | \ 'PrtDelete()': [''], 497 | \ 'PrtDeleteWord()': [''], 498 | \ 'PrtClear()': [''], 499 | \ 'PrtSelectMove("j")': ['', ''], 500 | \ 'PrtSelectMove("k")': ['', ''], 501 | \ 'PrtSelectMove("t")': ['', ''], 502 | \ 'PrtSelectMove("b")': ['', ''], 503 | \ 'PrtSelectMove("u")': ['', ''], 504 | \ 'PrtSelectMove("d")': ['', ''], 505 | \ 'PrtHistory(-1)': [''], 506 | \ 'PrtHistory(1)': [''], 507 | \ 'AcceptSelection("e")': ['', '<2-LeftMouse>'], 508 | \ 'AcceptSelection("h")': ['', '', ''], 509 | \ 'AcceptSelection("t")': [''], 510 | \ 'AcceptSelection("v")': ['', ''], 511 | \ 'ToggleFocus()': [''], 512 | \ 'ToggleRegex()': [''], 513 | \ 'ToggleByFname()': [''], 514 | \ 'ToggleType(1)': ['', ''], 515 | \ 'ToggleType(-1)': ['', ''], 516 | \ 'PrtExpandDir()': [''], 517 | \ 'PrtInsert("c")': ['', ''], 518 | \ 'PrtInsert()': [''], 519 | \ 'PrtCurStart()': [''], 520 | \ 'PrtCurEnd()': [''], 521 | \ 'PrtCurLeft()': ['', '', ''], 522 | \ 'PrtCurRight()': ['', ''], 523 | \ 'PrtClearCache()': [''], 524 | \ 'PrtDeleteEnt()': [''], 525 | \ 'CreateNewFile()': [''], 526 | \ 'MarkToOpen()': [''], 527 | \ 'OpenMulti()': [''], 528 | \ 'PrtExit()': ['', '', ''], 529 | \ } 530 | < 531 | Note: if pressing moves the cursor one character to the left instead of 532 | deleting a character for you, add this to your |.vimrc| to disable the plugin's 533 | default mapping: > 534 | let g:ctrlp_prompt_mappings = { 'PrtCurLeft()': ['', ''] } 535 | < 536 | 537 | ---------------------------------------- 538 | MRU mode options:~ 539 | 540 | *'g:ctrlp_mruf_max'* 541 | Specify the number of recently opened files you want CtrlP to remember: > 542 | let g:ctrlp_mruf_max = 250 543 | < 544 | 545 | *'g:ctrlp_mruf_exclude'* 546 | Files you don't want CtrlP to remember. Use regexp to specify the patterns: > 547 | let g:ctrlp_mruf_exclude = '' 548 | < 549 | Examples: > 550 | let g:ctrlp_mruf_exclude = '/tmp/.*\|/temp/.*' " MacOSX/Linux 551 | let g:ctrlp_mruf_exclude = '^C:\\dev\\tmp\\.*' " Windows 552 | < 553 | 554 | *'g:ctrlp_mruf_include'* 555 | And if you want CtrlP to only remember some files, specify them here: > 556 | let g:ctrlp_mruf_include = '' 557 | < 558 | Example: > 559 | let g:ctrlp_mruf_include = '\.py$\|\.rb$' 560 | < 561 | 562 | *'g:ctrlp_mruf_relative'* 563 | Set this to 1 to show only MRU files in the current working directory: > 564 | let g:ctrlp_mruf_relative = 0 565 | < 566 | 567 | *'g:ctrlp_mruf_default_order'* 568 | Set this to 1 to disable sorting when searching in MRU mode: > 569 | let g:ctrlp_mruf_default_order = 0 570 | < 571 | 572 | *'g:ctrlp_mruf_case_sensitive'* 573 | Match this with your file system case-sensitivity setting to avoid duplicate 574 | MRU entries: > 575 | let g:ctrlp_mruf_case_sensitive = 1 576 | < 577 | 578 | *'g:ctrlp_mruf_save_on_update'* 579 | Set this to 0 to disable saving of the MRU list to hard drive whenever a new 580 | entry is added, saving will then only occur when exiting Vim: > 581 | let g:ctrlp_mruf_save_on_update = 1 582 | < 583 | 584 | ---------------------------------------- 585 | Advanced options:~ 586 | 587 | *'g:ctrlp_open_func'* 588 | Define a custom function to open the selected file: > 589 | let g:ctrlp_open_func = {} 590 | < 591 | Example: > 592 | let g:ctrlp_open_func = { 593 | \ 'files' : 'Function_Name_1', 594 | \ 'buffers' : 'Function_Name_2', 595 | \ 'mru files' : 'Function_Name_3', 596 | \ } 597 | < 598 | Structure of the functions: > 599 | function! Function_Name(action, line) 600 | " Arguments: 601 | " | 602 | " +- a:action : The opening action: 603 | " | + 'e' : user pressed (default) 604 | " | + 'h' : user pressed (default) 605 | " | + 'v' : user pressed (default) 606 | " | + 't' : user pressed (default) 607 | " | + 'x' : user used the console dialog (default) and 608 | " | chose "e[x]ternal". 609 | " | 610 | " +- a:line : The selected line. 611 | 612 | endfunction 613 | < 614 | Note: does not apply when opening multiple files with and . 615 | 616 | Example: open HTML files in the default web browser when is pressed and 617 | in Vim otherwise > 618 | function! HTMLOpenFunc(action, line) 619 | if a:action =~ '^[tx]$' && fnamemodify(a:line, ':e') =~? '^html\?$' 620 | 621 | " Get the filename 622 | let filename = fnameescape(fnamemodify(a:line, ':p')) 623 | 624 | " Close CtrlP 625 | call ctrlp#exit() 626 | 627 | " Open the file 628 | silent! execute '!xdg-open' filename 629 | 630 | elseif a:action == 'x' && fnamemodify(a:line, ':e') !~? '^html\?$' 631 | 632 | " Not a HTML file, simulate pressing again and wait for new input 633 | call feedkeys("\") 634 | 635 | else 636 | 637 | " Use CtrlP's default file opening function 638 | call call('ctrlp#acceptfile', [a:action, a:line]) 639 | 640 | endif 641 | endfunction 642 | 643 | let g:ctrlp_open_func = { 'files': 'HTMLOpenFunc' } 644 | < 645 | 646 | *'g:ctrlp_status_func'* 647 | Use this to customize the statuslines for the CtrlP window: > 648 | let g:ctrlp_status_func = {} 649 | < 650 | Example: > 651 | let g:ctrlp_status_func = { 652 | \ 'main': 'Function_Name_1', 653 | \ 'prog': 'Function_Name_2', 654 | \ } 655 | < 656 | Structure of the functions: > 657 | " Main statusline 658 | function! Function_Name_1(focus, byfname, regex, prev, item, next, marked) 659 | " Arguments: 660 | " | 661 | " +- a:focus : The focus of the prompt: "prt" or "win". 662 | " | 663 | " +- a:byfname : In filename mode or in full path mode: "file" or "path". 664 | " | 665 | " +- a:regex : In regex mode: 1 or 0. 666 | " | 667 | " +- a:prev : The previous search mode. 668 | " | 669 | " +- a:item : The current search mode. 670 | " | 671 | " +- a:next : The next search mode. 672 | " | 673 | " +- a:marked : The number of marked files, or a comma separated list of 674 | " the marked filenames. 675 | 676 | return full_statusline 677 | endfunction 678 | 679 | " Progress statusline 680 | function! Function_Name_2(str) 681 | " a:str : Either the number of files scanned so far, or a string indicating 682 | " the current directory is being scanned with a user_command. 683 | 684 | return full_statusline 685 | endfunction 686 | < 687 | See https://gist.github.com/1610859 for a working example. 688 | 689 | *'g:ctrlp_buffer_func'* 690 | Specify the functions that will be called after entering and before exiting the 691 | CtrlP buffer: > 692 | let g:ctrlp_buffer_func = {} 693 | < 694 | Example: > 695 | let g:ctrlp_buffer_func = { 696 | \ 'enter': 'Function_Name_1', 697 | \ 'exit': 'Function_Name_2', 698 | \ } 699 | < 700 | 701 | *'g:ctrlp_match_func'* 702 | Set an external fuzzy matching function for CtrlP to use: > 703 | let g:ctrlp_match_func = {} 704 | < 705 | Example: > 706 | let g:ctrlp_match_func = { 'match': 'Function_Name' } 707 | < 708 | Structure of the function: > 709 | function! Function_Name(items, str, limit, mmode, ispath, crfile, regex) 710 | " Arguments: 711 | " | 712 | " +- a:items : The full list of items to search in. 713 | " | 714 | " +- a:str : The string entered by the user. 715 | " | 716 | " +- a:limit : The max height of the match window. Can be used to limit 717 | " | the number of items to return. 718 | " | 719 | " +- a:mmode : The match mode. Can be one of these strings: 720 | " | + "full-line": match the entire line. 721 | " | + "filename-only": match only the filename. 722 | " | + "first-non-tab": match until the first tab char. 723 | " | + "until-last-tab": match until the last tab char. 724 | " | 725 | " +- a:ispath : Is 1 when searching in file, buffer, mru, mixed, dir, and 726 | " | rtscript modes. Is 0 otherwise. 727 | " | 728 | " +- a:crfile : The file in the current window. Should be excluded from the 729 | " | results when a:ispath == 1. 730 | " | 731 | " +- a:regex : In regex mode: 1 or 0. 732 | 733 | return list_of_matched_items 734 | endfunction 735 | < 736 | 737 | =============================================================================== 738 | COMMANDS *ctrlp-commands* 739 | 740 | *:CtrlP* 741 | :CtrlP [starting-directory] 742 | Open CtrlP in find file mode. 743 | 744 | If no argument is given, the value of |g:ctrlp_working_path_mode| will be 745 | used to determine the starting directory. 746 | 747 | You can use to auto-complete the [starting-directory] when typing it. 748 | 749 | *:CtrlPBuffer* 750 | :CtrlPBuffer 751 | Open CtrlP in find buffer mode. 752 | 753 | *:CtrlPMRU* 754 | :CtrlPMRU 755 | Open CtrlP in find Most-Recently-Used file mode. 756 | 757 | *:CtrlPLastMode* 758 | :CtrlPLastMode [--dir] 759 | Open CtrlP in the last mode used. When having the "--dir" argument, also 760 | reuse the last working directory. 761 | 762 | *:CtrlPRoot* 763 | :CtrlPRoot 764 | This acts like |:CtrlP| with |g:ctrlp_working_path_mode| = 'r' and ignores 765 | the variable's current value. 766 | 767 | *:CtrlPClearCache* 768 | :CtrlPClearCache 769 | Flush the cache for the current working directory. The same as pressing 770 | inside CtrlP. 771 | To enable or disable caching, use the |g:ctrlp_use_caching| option. 772 | 773 | *:CtrlPClearAllCaches* 774 | :CtrlPClearAllCaches 775 | Delete all the cache files saved in |g:ctrlp_cache_dir| location. 776 | 777 | ------------------------------------------------------------------------------- 778 | For commands provided by bundled extensions, see |ctrlp-extensions|. 779 | 780 | =============================================================================== 781 | MAPPINGS *ctrlp-mappings* 782 | 783 | *'ctrlp-'* 784 | 785 | Default |Normal| mode mapping to open the CtrlP prompt in find file mode. 786 | 787 | ---------------------------------------- 788 | Once inside the prompt:~ 789 | 790 | 791 | Toggle between full-path search and filename only search. 792 | Note: in filename mode, the prompt's base is '>d>' instead of '>>>' 793 | 794 | *'ctrlp-fullregexp'* 795 | Toggle between the string mode and full regexp mode. 796 | Note: in full regexp mode, the prompt's base is 'r>>' instead of '>>>' 797 | 798 | See also: |input-formats| (guide) and |g:ctrlp_regexp_search| (option). 799 | 800 | , 'forward' 801 | 802 | Scroll to the 'next' search mode in the sequence. 803 | 804 | , 'backward' 805 | 806 | Scroll to the 'previous' search mode in the sequence. 807 | 808 | *'ctrlp-autocompletion'* 809 | Auto-complete directory names under the current working directory inside 810 | the prompt. 811 | 812 | 813 | Toggle the focus between the match window and the prompt. 814 | 815 | , 816 | 817 | Exit CtrlP. 818 | 819 | Moving:~ 820 | 821 | , 822 | 823 | Move selection down. 824 | 825 | , 826 | 827 | Move selection up. 828 | 829 | 830 | Move the cursor to the 'start' of the prompt. 831 | 832 | 833 | Move the cursor to the 'end' of the prompt. 834 | 835 | , 836 | , 837 | 838 | Move the cursor one character to the 'left'. 839 | 840 | , 841 | 842 | Move the cursor one character to the 'right'. 843 | 844 | Editing:~ 845 | 846 | , 847 | 848 | Delete the preceding character. 849 | 850 | 851 | Delete the current character. 852 | 853 | 854 | Delete a preceding inner word. 855 | 856 | 857 | Clear the input field. 858 | 859 | Browsing input history:~ 860 | 861 | 862 | Next string in the prompt's history. 863 | 864 | 865 | Previous string in the prompt's history. 866 | 867 | Opening/Creating a file:~ 868 | 869 | 870 | Open the selected file in the 'current' window if possible. 871 | 872 | 873 | Open the selected file in a new 'tab'. 874 | 875 | 876 | Open the selected file in a 'vertical' split. 877 | 878 | , 879 | , 880 | 881 | Open the selected file in a 'horizontal' split. 882 | 883 | 884 | Create a new file and its parent directories. 885 | 886 | Opening multiple files:~ 887 | 888 | 889 | - Mark/unmark a file to be opened with . 890 | - Mark/unmark a file to create a new file in its directory using . 891 | 892 | 893 | - Open files marked by . 894 | - When no file has been marked by , open a console dialog with the 895 | following options: 896 | 897 | Open the selected file: 898 | t - in a tab page. 899 | v - in a vertical split. 900 | h - in a horizontal split. 901 | r - in the current window. 902 | i - as a hidden buffer. 903 | x - (optional) with the function defined in |g:ctrlp_open_func|. 904 | 905 | Other options (not shown): 906 | a - mark all files in the match window. 907 | d - change CtrlP's local working directory to the selected file's 908 | directory and switch to find file mode. 909 | 910 | Function keys:~ 911 | 912 | 913 | - Refresh the match window and purge the cache for the current directory. 914 | - Remove deleted files from the MRU list. 915 | 916 | 917 | - Wipe the MRU list. 918 | - Delete MRU entries marked by . 919 | 920 | Pasting:~ 921 | 922 | , *'ctrlp-pasting'* 923 | 924 | Paste the clipboard content into the prompt. 925 | 926 | 927 | Open a console dialog to paste , , the content of the search 928 | register, the last visual selection, the clipboard or any register into the 929 | prompt. 930 | 931 | Choose your own mappings with |g:ctrlp_prompt_mappings|. 932 | 933 | ---------------------------------------- 934 | When inside the match window (press to switch):~ 935 | 936 | a-z 937 | 0-9 938 | ~^-=;`',.+!@#$%&_(){}[] 939 | Cycle through the lines which have the matching first character. 940 | 941 | =============================================================================== 942 | INPUT FORMATS *ctrlp-input-formats* 943 | 944 | Formats for inputting in the prompt:~ 945 | 946 | a) Simple string. 947 | 948 | E.g. 'abc' is understood internally as 'a[^a]\{-}b[^b]\{-}c' 949 | 950 | b) When in regexp mode, the input string's treated as a Vim's regexp |pattern| 951 | without any modification. 952 | 953 | E.g. 'abc\d*efg' will be read as 'abc\d*efg'. 954 | 955 | See |ctrlp-fullregexp| (keymap) and |g:ctrlp_regexp_search| (option) for 956 | how to enable regexp mode. 957 | 958 | c) End the string with a colon ':' followed by a Vim command to execute that 959 | command after opening the file. If you need to use ':' literally, escape it 960 | with a backslash: '\:'. When opening multiple files, the command will be 961 | executed on each opening file. 962 | 963 | E.g. Use ':45' to jump to line 45. 964 | 965 | Use ':/any\:string' to jump to the first instance of 'any:string'. 966 | 967 | Use ':+setf\ myfiletype|50' to set the filetype to 'myfiletype', then 968 | jump to line 50. 969 | 970 | Use ':diffthis' when opening multiple files to run |:diffthis| on the 971 | first 4 files. 972 | 973 | See also: Vim's |++opt| and |+cmd|. 974 | 975 | d) Submit two dots '..' to go upward the directory tree by 1 level. To go up 976 | multiple levels, use one extra dot for each extra level: 977 | > 978 | Raw input Interpreted as 979 | .. ../ 980 | ... ../../ 981 | .... ../../../ 982 | < 983 | Note: if the parent directories are large and uncached, this can be slow. 984 | 985 | You can also use '@cd path/' to change CtrlP's local working directory. 986 | Use '@cd %:h' to change to the directory of the current file. 987 | 988 | e) Similarly, submit '/' or '\' to find and go to the project's root. 989 | 990 | If the project is large, using a VCS listing command to look for files 991 | might help speeding up the intial scan (see |g:ctrlp_user_command| for more 992 | details). 993 | 994 | Note: d) and e) only work in file, directory and mixed modes. 995 | 996 | f) Type the name of a non-existent file and press to create it. Mark a 997 | file with to create the new file in the same directory as the marked 998 | file. 999 | 1000 | E.g. Using 'newdir/newfile.txt' will create a directory named 'newdir' as 1001 | well as a file named 'newfile.txt'. 1002 | 1003 | If an entry 'some/old/dirs/oldfile.txt' is marked with , then 1004 | 'newdir' and 'newfile.txt' will be created under 'some/old/dirs'. The 1005 | final path will then be 'some/old/dirs/newdir/newfile.txt'. 1006 | 1007 | Note: use '\' in place of '/' on Windows (if |'shellslash'| is not set). 1008 | 1009 | g) In filename mode (toggle with ), you can use one primary pattern and 1010 | one refining pattern separated by a semicolon. Both patterns work like (a), 1011 | or (b) when in regexp mode. 1012 | 1013 | h) Submit ? to open this help file. 1014 | 1015 | =============================================================================== 1016 | EXTENSIONS *ctrlp-extensions* 1017 | 1018 | Extensions are optional. To enable an extension, add its name to the variable 1019 | g:ctrlp_extensions: > 1020 | let g:ctrlp_extensions = ['tag', 'buffertag', 'quickfix', 'dir', 'rtscript', 1021 | \ 'undo', 'line', 'changes', 'mixed', 'bookmarkdir'] 1022 | < 1023 | The order of the items will be the order they appear on the statusline and when 1024 | using , . 1025 | 1026 | Available extensions:~ 1027 | 1028 | *:CtrlPTag* 1029 | * Tag mode:~ 1030 | - Name: 'tag' 1031 | - Command: ":CtrlPTag" 1032 | - Search for a tag within a generated central tags file, and jump to the 1033 | definition. Use the Vim's option |'tags'| to specify the names and the 1034 | locations of the tags file(s). 1035 | E.g. set tags+=doc/tags 1036 | 1037 | *:CtrlPBufTag* 1038 | *:CtrlPBufTagAll* 1039 | * Buffer Tag mode:~ 1040 | - Name: 'buffertag' 1041 | - Commands: ":CtrlPBufTag [buffer]", 1042 | ":CtrlPBufTagAll". 1043 | - Search for a tag within the current buffer or all listed buffers and jump 1044 | to the definition. Requires |exuberant_ctags| or compatible programs. 1045 | 1046 | *:CtrlPQuickfix* 1047 | * Quickfix mode:~ 1048 | - Name: 'quickfix' 1049 | - Command: ":CtrlPQuickfix" 1050 | - Search for an entry in the current quickfix errors and jump to it. 1051 | 1052 | *:CtrlPDir* 1053 | * Directory mode:~ 1054 | - Name: 'dir' 1055 | - Command: ":CtrlPDir [starting-directory]" 1056 | - Search for a directory and change the working directory to it. 1057 | - Mappings: 1058 | + change the local working directory for CtrlP and keep it open. 1059 | + change the global working directory (exit). 1060 | + change the local working directory for the current window (exit). 1061 | + change the global working directory to CtrlP's current local 1062 | working directory (exit). 1063 | 1064 | *:CtrlPRTS* 1065 | * Runtime script mode:~ 1066 | - Name: 'rtscript' 1067 | - Command: ":CtrlPRTS" 1068 | - Search for files (vimscripts, docs, snippets...) in runtimepath. 1069 | 1070 | *:CtrlPUndo* 1071 | * Undo mode:~ 1072 | - Name: 'undo' 1073 | - Command: ":CtrlPUndo" 1074 | - Browse undo history. 1075 | 1076 | *:CtrlPLine* 1077 | * Line mode:~ 1078 | - Name: 'line' 1079 | - Command: ":CtrlPLine" 1080 | - Search for a line in all listed buffers. 1081 | 1082 | *:CtrlPChange* 1083 | *:CtrlPChangeAll* 1084 | * Change list mode:~ 1085 | - Name: 'changes' 1086 | - Commands: ":CtrlPChange [buffer]", 1087 | ":CtrlPChangeAll". 1088 | - Search for and jump to a recent change in the current buffer or in all 1089 | listed buffers. 1090 | 1091 | *:CtrlPMixed* 1092 | * Mixed mode:~ 1093 | - Name: 'mixed' 1094 | - Command: ":CtrlPMixed" 1095 | - Search in files, buffers and MRU files at the same time. 1096 | 1097 | *:CtrlPBookmarkDir* 1098 | *:CtrlPBookmarkDirAdd* 1099 | * BookmarkDir mode:~ 1100 | - Name: 'bookmarkdir' 1101 | - Commands: ":CtrlPBookmarkDir", 1102 | ":CtrlPBookmarkDirAdd [directory]". 1103 | - Search for a bookmarked directory and change the working directory to it. 1104 | - Mappings: 1105 | + change the local working directory for CtrlP, keep it open and 1106 | switch to find file mode. 1107 | + change the global working directory (exit). 1108 | + change the local working directory for the current window (exit). 1109 | + 1110 | - Wipe bookmark list. 1111 | - Delete entries marked by . 1112 | 1113 | ---------------------------------------- 1114 | Buffer Tag mode options:~ 1115 | 1116 | *'g:ctrlp_buftag_ctags_bin'* 1117 | If ctags isn't in your $PATH, use this to set its location: > 1118 | let g:ctrlp_buftag_ctags_bin = '' 1119 | < 1120 | 1121 | *'g:ctrlp_buftag_systemenc'* 1122 | Match this with your OS's encoding (not Vim's). The default value mirrors Vim's 1123 | global |'encoding'| option: > 1124 | let g:ctrlp_buftag_systemenc = &encoding 1125 | < 1126 | 1127 | *'g:ctrlp_buftag_types'* 1128 | Use this to set the arguments for ctags, jsctags... for a given filetype: > 1129 | let g:ctrlp_buftag_types = '' 1130 | < 1131 | Examples: > 1132 | let g:ctrlp_buftag_types = { 1133 | \ 'erlang' : '--language-force=erlang --erlang-types=drmf', 1134 | \ 'javascript' : { 1135 | \ 'bin': 'jsctags', 1136 | \ 'args': '-f -', 1137 | \ }, 1138 | \ } 1139 | < 1140 | 1141 | =============================================================================== 1142 | CUSTOMIZATION *ctrlp-customization* 1143 | 1144 | Highlighting:~ 1145 | * For the CtrlP buffer: 1146 | CtrlPNoEntries : the message when no match is found (Error) 1147 | CtrlPMatch : the matched pattern (Identifier) 1148 | CtrlPLinePre : the line prefix '>' in the match window 1149 | CtrlPPrtBase : the prompt's base (Comment) 1150 | CtrlPPrtText : the prompt's text (|hl-Normal|) 1151 | CtrlPPrtCursor : the prompt's cursor when moving over the text (Constant) 1152 | 1153 | * In extensions: 1154 | CtrlPTabExtra : the part of each line that's not matched against (Comment) 1155 | CtrlPBufName : the buffer name an entry belongs to (|hl-Directory|) 1156 | CtrlPTagKind : the kind of the tag in buffer-tag mode (|hl-Title|) 1157 | CtrlPqfLineCol : the line and column numbers in quickfix mode (Comment) 1158 | CtrlPUndoT : the elapsed time in undo mode (|hl-Directory|) 1159 | CtrlPUndoBr : the square brackets [] in undo mode (Comment) 1160 | CtrlPUndoNr : the undo number inside [] in undo mode (String) 1161 | CtrlPUndoSv : the point where the file was saved (Comment) 1162 | CtrlPUndoPo : the current position in the undo tree (|hl-Title|) 1163 | CtrlPBookmark : the name of the bookmark (Identifier) 1164 | 1165 | Statuslines:~ 1166 | * Highlight groups: 1167 | CtrlPMode1 : 'file' or 'path', and the current mode (Character) 1168 | CtrlPMode2 : 'prt' or 'win', 'regex', the working directory (|hl-LineNr|) 1169 | CtrlPStats : the scanning status (Function) 1170 | 1171 | For rebuilding the statuslines, see |g:ctrlp_status_func|. 1172 | 1173 | =============================================================================== 1174 | MISCELLANEOUS CONFIGS *ctrlp-miscellaneous-configs* 1175 | 1176 | * Using |wildignore| for |g:ctrlp_user_command|: 1177 | > 1178 | function! s:wig2cmd() 1179 | " Change wildignore into space or | separated groups 1180 | " e.g. .aux .out .toc .jpg .bmp .gif 1181 | " or .aux$\|.out$\|.toc$\|.jpg$\|.bmp$\|.gif$ 1182 | let pats = ['[*\/]*\([?_.0-9A-Za-z]\+\)\([*\/]*\)\(\\\@) 1197 | 1198 | * A standalone function to set the working directory to the project's root, or 1199 | to the parent directory of the current file if a root can't be found: 1200 | > 1201 | function! s:setcwd() 1202 | let cph = expand('%:p:h', 1) 1203 | if cph =~ '^.\+://' | retu | en 1204 | for mkr in ['.git/', '.hg/', '.svn/', '.bzr/', '_darcs/', '.vimprojects'] 1205 | let wd = call('find'.(mkr =~ '/$' ? 'dir' : 'file'), [mkr, cph.';']) 1206 | if wd != '' | let &acd = 0 | brea | en 1207 | endfo 1208 | exe 'lc!' fnameescape(wd == '' ? cph : substitute(wd, mkr.'$', '.', '')) 1209 | endfunction 1210 | 1211 | autocmd BufEnter * call s:setcwd() 1212 | < 1213 | (requires Vim 7.1.299+) 1214 | 1215 | * Using a |count| to invoke different commands using the same mapping: 1216 | > 1217 | let g:ctrlp_cmd = 'exe "CtrlP".get(["", "Buffer", "MRU"], v:count)' 1218 | < 1219 | 1220 | =============================================================================== 1221 | CREDITS *ctrlp-credits* 1222 | 1223 | Developed by Kien Nguyen . 1224 | 1225 | Project's homepage: http://kien.github.com/ctrlp.vim 1226 | Git repository: https://github.com/kien/ctrlp.vim 1227 | Mercurial repository: https://bitbucket.org/kien/ctrlp.vim 1228 | 1229 | ------------------------------------------------------------------------------- 1230 | Thanks to everyone that has submitted ideas, bug reports or helped debugging on 1231 | gibhub, bitbucket, and through email. 1232 | 1233 | Special thanks:~ 1234 | 1235 | * Woojong Koh 1236 | * Simon Ruderich 1237 | * Yasuhiro Matsumoto 1238 | * Ken Earley 1239 | * Kyo Nagashima 1240 | * Zak Johnson 1241 | * Diego Viola 1242 | * Piet Delport 1243 | * Thibault Duplessis 1244 | * Kent Sibilev 1245 | * Tacahiroy 1246 | * Luca Pette 1247 | * Seth Fowler 1248 | * Lowe Thiderman 1249 | * Christopher Fredén 1250 | * Zahary Karadjov 1251 | * Jo De Boeck 1252 | 1253 | =============================================================================== 1254 | CHANGELOG *ctrlp-changelog* 1255 | 1256 | Before 2012/11/30~ 1257 | 1258 | + New options: |g:ctrlp_abbrev|, 1259 | |g:ctrlp_key_loop|, 1260 | |g:ctrlp_open_func|, 1261 | |g:ctrlp_tabpage_position|, 1262 | |g:ctrlp_mruf_save_on_update| 1263 | + Rename: 1264 | *g:ctrlp_dotfiles* -> |g:ctrlp_show_hidden|. 1265 | + Change |g:ctrlp_switch_buffer|'s and |g:ctrlp_working_path_mode|'s type 1266 | (old values still work). 1267 | + New key for |g:ctrlp_user_command| when it's a Dictionary: 'ignore'. 1268 | 1269 | Before 2012/06/15~ 1270 | 1271 | + New value for |g:ctrlp_follow_symlinks|: 2. 1272 | + New value for |g:ctrlp_open_multiple_files|: 'j'. 1273 | + Allow using , , to open files marked by . 1274 | + Extend '..' (|ctrlp-input-formats| (d)) 1275 | + New input format: '@cd' (|ctrlp-input-formats| (d)) 1276 | 1277 | Before 2012/04/30~ 1278 | 1279 | + New option: |g:ctrlp_mruf_default_order| 1280 | + New feature: Bookmarked directories extension. 1281 | + New commands: |:CtrlPBookmarkDir| 1282 | |:CtrlPBookmarkDirAdd| 1283 | 1284 | Before 2012/04/15~ 1285 | 1286 | + New option: |g:ctrlp_buffer_func|, callback functions for CtrlP buffer. 1287 | + Remove: g:ctrlp_mruf_last_entered, make it a default for MRU mode. 1288 | + New commands: |:CtrlPLastMode|, open CtrlP in the last mode used. 1289 | |:CtrlPMixed|, search in files, buffers and MRU files. 1290 | 1291 | Before 2012/03/31~ 1292 | 1293 | + New options: |g:ctrlp_default_input|, default input when entering CtrlP. 1294 | |g:ctrlp_match_func|, allow using a custom fuzzy matcher. 1295 | + Rename: 1296 | *ClearCtrlPCache* -> |CtrlPClearCache| 1297 | *ClearAllCtrlPCaches* -> |CtrlPClearAllCaches| 1298 | *ResetCtrlP* -> |CtrlPReload| 1299 | 1300 | Before 2012/03/02~ 1301 | 1302 | + Rename: 1303 | *g:ctrlp_regexp_search* -> |g:ctrlp_regexp|, 1304 | *g:ctrlp_dont_split* -> |g:ctrlp_reuse_window|, 1305 | *g:ctrlp_jump_to_buffer* -> |g:ctrlp_switch_buffer|. 1306 | + Rename and tweak: 1307 | *g:ctrlp_open_multi* -> |g:ctrlp_open_multiple_files|. 1308 | + Deprecate *g:ctrlp_highlight_match* 1309 | + Extend |g:ctrlp_user_command| to support multiple commands. 1310 | + New option: |g:ctrlp_mruf_last_entered| change MRU to Recently-Entered. 1311 | 1312 | Before 2012/01/15~ 1313 | 1314 | + New mapping: Switch and . is now used for completion 1315 | of directory names under the current working directory. 1316 | + New options: |g:ctrlp_arg_map| for , to accept an argument. 1317 | |g:ctrlp_status_func| custom statusline. 1318 | |g:ctrlp_mruf_relative| show only MRU files inside cwd. 1319 | + Extend g:ctrlp_open_multi with new optional values: tr, hr, vr. 1320 | + Extend |g:ctrlp_custom_ignore| to specifically filter dir, file and link. 1321 | 1322 | Before 2012/01/05~ 1323 | 1324 | + New feature: Buffer Tag extension. 1325 | + New commands: |:CtrlPBufTag|, |:CtrlPBufTagAll|. 1326 | + New options: |g:ctrlp_cmd|, 1327 | |g:ctrlp_custom_ignore| 1328 | 1329 | Before 2011/11/30~ 1330 | 1331 | + New features: Tag, Quickfix and Directory extensions. 1332 | + New commands: |:CtrlPTag|, |:CtrlPQuickfix|, |:CtrlPDir|. 1333 | + New options: |g:ctrlp_use_migemo|, 1334 | |g:ctrlp_lazy_update|, 1335 | |g:ctrlp_follow_symlinks| 1336 | 1337 | Before 2011/11/13~ 1338 | 1339 | + New special input: '/' and '\' find root (|ctrlp-input-formats| (e)) 1340 | + Remove ctrlp#SetWorkingPath(). 1341 | + Remove *g:ctrlp_mru_files* and make MRU mode permanent. 1342 | + Extend g:ctrlp_open_multi, add new ways to open files. 1343 | + New option: g:ctrlp_dont_split, 1344 | |g:ctrlp_mruf_case_sensitive| 1345 | 1346 | Before 2011/10/30~ 1347 | 1348 | + New feature: Support for custom extensions. 1349 | also removes non-existent files from MRU list. 1350 | + New option: g:ctrlp_jump_to_buffer 1351 | 1352 | Before 2011/10/12~ 1353 | 1354 | + New features: Open multiple files. 1355 | Pass Vim's |++opt| and |+cmd| to the opening file 1356 | (|ctrlp-input-formats| (c)) 1357 | Auto-complete each dir for |:CtrlP| [starting-directory] 1358 | + New mappings: mark/unmark a file to be opened with . 1359 | open all marked files. 1360 | + New option: g:ctrlp_open_multi 1361 | + Remove *g:ctrlp_persistent_input* *g:ctrlp_live_update* and . 1362 | 1363 | Before 2011/09/29~ 1364 | 1365 | + New mappings: , next/prev string in the input history. 1366 | create a new file and its parent dirs. 1367 | + New options: |g:ctrlp_open_new_file|, 1368 | |g:ctrlp_max_history| 1369 | + Added a new open-in-horizontal-split mapping: 1370 | 1371 | Before 2011/09/19~ 1372 | 1373 | + New command: ResetCtrlP 1374 | + New options: |g:ctrlp_max_files|, 1375 | |g:ctrlp_max_depth|, 1376 | g:ctrlp_live_update 1377 | + New mapping: 1378 | 1379 | Before 2011/09/12~ 1380 | 1381 | + Ability to cycle through matched lines in the match window. 1382 | + Extend the behavior of g:ctrlp_persistent_input 1383 | + Extend the behavior of |:CtrlP| 1384 | + New options: |g:ctrlp_dotfiles|, 1385 | |g:ctrlp_clear_cache_on_exit|, 1386 | g:ctrlp_highlight_match, 1387 | |g:ctrlp_user_command| 1388 | + New special input: '..' (|ctrlp-input-formats| (d)) 1389 | + New mapping: . 1390 | + New commands: |:CtrlPCurWD|, 1391 | |:CtrlPCurFile|, 1392 | |:CtrlPRoot| 1393 | 1394 | + New feature: Search in most recently used (MRU) files 1395 | + New mapping: . 1396 | + Extended the behavior of . 1397 | + New options: g:ctrlp_mru_files, 1398 | |g:ctrlp_mruf_max|, 1399 | |g:ctrlp_mruf_exclude|, 1400 | |g:ctrlp_mruf_include| 1401 | + New command: |:CtrlPMRU| 1402 | 1403 | First public release: 2011/09/06~ 1404 | 1405 | =============================================================================== 1406 | vim:ft=help:et:ts=2:sw=2:sts=2:norl 1407 | -------------------------------------------------------------------------------- /autoload/ctrlp.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: autoload/ctrlp.vim 3 | " Description: Fuzzy file, buffer, mru, tag, etc finder. 4 | " Author: Kien Nguyen 5 | " Version: 1.78 6 | " ============================================================================= 7 | 8 | " ** Static variables {{{1 9 | " s:ignore() {{{2 10 | fu! s:ignore() 11 | let igdirs = [ 12 | \ '\.git', 13 | \ '\.hg', 14 | \ '\.svn', 15 | \ '_darcs', 16 | \ '\.bzr', 17 | \ '\.cdv', 18 | \ '\~\.dep', 19 | \ '\~\.dot', 20 | \ '\~\.nib', 21 | \ '\~\.plst', 22 | \ '\.pc', 23 | \ '_MTN', 24 | \ 'blib', 25 | \ 'CVS', 26 | \ 'RCS', 27 | \ 'SCCS', 28 | \ '_sgbak', 29 | \ 'autom4te\.cache', 30 | \ 'cover_db', 31 | \ '_build', 32 | \ ] 33 | let igfiles = [ 34 | \ '\~$', 35 | \ '#.+#$', 36 | \ '[._].*\.swp$', 37 | \ 'core\.\d+$', 38 | \ '\.exe$', 39 | \ '\.so$', 40 | \ '\.bak$', 41 | \ '\.png$', 42 | \ '\.jpg$', 43 | \ '\.gif$', 44 | \ '\.zip$', 45 | \ '\.rar$', 46 | \ '\.tar\.gz$', 47 | \ ] 48 | retu { 49 | \ 'dir': '\v[\/]('.join(igdirs, '|').')$', 50 | \ 'file': '\v'.join(igfiles, '|'), 51 | \ } 52 | endf 53 | " Script local vars {{{2 54 | let [s:pref, s:bpref, s:opts, s:new_opts, s:lc_opts] = 55 | \ ['g:ctrlp_', 'b:ctrlp_', { 56 | \ 'abbrev': ['s:abbrev', {}], 57 | \ 'arg_map': ['s:argmap', 0], 58 | \ 'buffer_func': ['s:buffunc', {}], 59 | \ 'by_filename': ['s:byfname', 0], 60 | \ 'custom_ignore': ['s:usrign', s:ignore()], 61 | \ 'default_input': ['s:deftxt', 0], 62 | \ 'dont_split': ['s:nosplit', 'netrw'], 63 | \ 'dotfiles': ['s:showhidden', 0], 64 | \ 'extensions': ['s:extensions', []], 65 | \ 'follow_symlinks': ['s:folsym', 0], 66 | \ 'highlight_match': ['s:mathi', [1, 'CtrlPMatch']], 67 | \ 'jump_to_buffer': ['s:jmptobuf', 'Et'], 68 | \ 'key_loop': ['s:keyloop', 0], 69 | \ 'lazy_update': ['s:lazy', 0], 70 | \ 'match_func': ['s:matcher', {}], 71 | \ 'match_window_bottom': ['s:mwbottom', 1], 72 | \ 'match_window_reversed': ['s:mwreverse', 1], 73 | \ 'max_depth': ['s:maxdepth', 40], 74 | \ 'max_files': ['s:maxfiles', 10000], 75 | \ 'max_height': ['s:mxheight', 10], 76 | \ 'max_history': ['s:maxhst', exists('+hi') ? &hi : 20], 77 | \ 'mruf_default_order': ['s:mrudef', 0], 78 | \ 'open_func': ['s:openfunc', {}], 79 | \ 'open_multi': ['s:opmul', '1v'], 80 | \ 'open_new_file': ['s:newfop', 'v'], 81 | \ 'prompt_mappings': ['s:urprtmaps', 0], 82 | \ 'regexp_search': ['s:regexp', 0], 83 | \ 'root_markers': ['s:rmarkers', []], 84 | \ 'split_window': ['s:splitwin', 0], 85 | \ 'status_func': ['s:status', {}], 86 | \ 'tabpage_position': ['s:tabpage', 'ac'], 87 | \ 'use_caching': ['s:caching', 1], 88 | \ 'use_migemo': ['s:migemo', 0], 89 | \ 'user_command': ['s:usrcmd', ''], 90 | \ 'working_path_mode': ['s:pathmode', 'ra'], 91 | \ }, { 92 | \ 'open_multiple_files': 's:opmul', 93 | \ 'regexp': 's:regexp', 94 | \ 'reuse_window': 's:nosplit', 95 | \ 'show_hidden': 's:showhidden', 96 | \ 'switch_buffer': 's:jmptobuf', 97 | \ }, { 98 | \ 'root_markers': 's:rmarkers', 99 | \ 'user_command': 's:usrcmd', 100 | \ 'working_path_mode': 's:pathmode', 101 | \ }] 102 | 103 | " Global options 104 | let s:glbs = { 'magic': 1, 'to': 1, 'tm': 0, 'sb': 1, 'hls': 0, 'im': 0, 105 | \ 'report': 9999, 'sc': 0, 'ss': 0, 'siso': 0, 'mfd': 200, 'mouse': 'n', 106 | \ 'gcr': 'a:blinkon0', 'ic': 1, 'lmap': '', 'mousef': 0, 'imd': 1 } 107 | 108 | " Keymaps 109 | let [s:lcmap, s:prtmaps] = ['nn ', { 110 | \ 'PrtBS()': ['', ''], 111 | \ 'PrtDelete()': [''], 112 | \ 'PrtDeleteWord()': [''], 113 | \ 'PrtClear()': [''], 114 | \ 'PrtSelectMove("j")': ['', ''], 115 | \ 'PrtSelectMove("k")': ['', ''], 116 | \ 'PrtSelectMove("t")': ['', ''], 117 | \ 'PrtSelectMove("b")': ['', ''], 118 | \ 'PrtSelectMove("u")': ['', ''], 119 | \ 'PrtSelectMove("d")': ['', ''], 120 | \ 'PrtHistory(-1)': [''], 121 | \ 'PrtHistory(1)': [''], 122 | \ 'AcceptSelection("e")': ['', '<2-LeftMouse>'], 123 | \ 'AcceptSelection("h")': ['', '', ''], 124 | \ 'AcceptSelection("t")': [''], 125 | \ 'AcceptSelection("v")': ['', ''], 126 | \ 'ToggleFocus()': [''], 127 | \ 'ToggleRegex()': [''], 128 | \ 'ToggleByFname()': [''], 129 | \ 'ToggleType(1)': ['', ''], 130 | \ 'ToggleType(-1)': ['', ''], 131 | \ 'PrtExpandDir()': [''], 132 | \ 'PrtInsert("c")': ['', ''], 133 | \ 'PrtInsert()': [''], 134 | \ 'PrtCurStart()': [''], 135 | \ 'PrtCurEnd()': [''], 136 | \ 'PrtCurLeft()': ['', '', ''], 137 | \ 'PrtCurRight()': ['', ''], 138 | \ 'PrtClearCache()': [''], 139 | \ 'PrtDeleteEnt()': [''], 140 | \ 'CreateNewFile()': [''], 141 | \ 'MarkToOpen()': [''], 142 | \ 'OpenMulti()': [''], 143 | \ 'PrtExit()': ['', '', ''], 144 | \ }] 145 | 146 | if !has('gui_running') 147 | cal add(s:prtmaps['PrtBS()'], remove(s:prtmaps['PrtCurLeft()'], 0)) 148 | en 149 | 150 | let s:compare_lim = 3000 151 | 152 | let s:ficounts = {} 153 | 154 | let s:ccex = s:pref.'clear_cache_on_exit' 155 | 156 | " Regexp 157 | let s:fpats = { 158 | \ '^\(\\|\)\|\(\\|\)$': '\\|', 159 | \ '^\\\(zs\|ze\|<\|>\)': '^\\\(zs\|ze\|<\|>\)', 160 | \ '^\S\*$': '\*', 161 | \ '^\S\\?$': '\\?', 162 | \ } 163 | 164 | " Keypad 165 | let s:kprange = { 166 | \ 'Plus': '+', 167 | \ 'Minus': '-', 168 | \ 'Divide': '/', 169 | \ 'Multiply': '*', 170 | \ 'Point': '.', 171 | \ } 172 | 173 | " Highlight groups 174 | let s:hlgrps = { 175 | \ 'NoEntries': 'Error', 176 | \ 'Mode1': 'Character', 177 | \ 'Mode2': 'LineNr', 178 | \ 'Stats': 'Function', 179 | \ 'Match': 'Identifier', 180 | \ 'PrtBase': 'Comment', 181 | \ 'PrtText': 'Normal', 182 | \ 'PrtCursor': 'Constant', 183 | \ } 184 | " s:opts() {{{2 185 | fu! s:opts(...) 186 | unl! s:usrign s:usrcmd s:urprtmaps 187 | for each in ['byfname', 'regexp', 'extensions'] | if exists('s:'.each) 188 | let {each} = s:{each} 189 | en | endfo 190 | for [ke, va] in items(s:opts) 191 | let {va[0]} = exists(s:pref.ke) ? {s:pref.ke} : va[1] 192 | endfo 193 | unl va 194 | for [ke, va] in items(s:new_opts) 195 | let {va} = {exists(s:pref.ke) ? s:pref.ke : va} 196 | endfo 197 | unl va 198 | for [ke, va] in items(s:lc_opts) 199 | if exists(s:bpref.ke) 200 | unl {va} 201 | let {va} = {s:bpref.ke} 202 | en 203 | endfo 204 | if a:0 && a:1 != {} 205 | unl va 206 | for [ke, va] in items(a:1) 207 | let opke = substitute(ke, '\(\w:\)\?ctrlp_', '', '') 208 | if has_key(s:lc_opts, opke) 209 | let sva = s:lc_opts[opke] 210 | unl {sva} 211 | let {sva} = va 212 | en 213 | endfo 214 | en 215 | for each in ['byfname', 'regexp'] | if exists(each) 216 | let s:{each} = {each} 217 | en | endfo 218 | if !exists('g:ctrlp_newcache') | let g:ctrlp_newcache = 0 | en 219 | let s:maxdepth = min([s:maxdepth, 100]) 220 | let s:mxheight = max([s:mxheight, 1]) 221 | let s:glob = s:showhidden ? '.*\|*' : '*' 222 | let s:igntype = empty(s:usrign) ? -1 : type(s:usrign) 223 | let s:lash = ctrlp#utils#lash() 224 | if s:keyloop 225 | let [s:lazy, s:glbs['imd']] = [0, 0] 226 | en 227 | if s:lazy 228 | cal extend(s:glbs, { 'ut': ( s:lazy > 1 ? s:lazy : 250 ) }) 229 | en 230 | " Extensions 231 | if !( exists('extensions') && extensions == s:extensions ) 232 | for each in s:extensions 233 | exe 'ru autoload/ctrlp/'.each.'.vim' 234 | endfo 235 | en 236 | " Keymaps 237 | if type(s:urprtmaps) == 4 238 | cal extend(s:prtmaps, s:urprtmaps) 239 | en 240 | endf 241 | "}}}1 242 | " * Open & Close {{{1 243 | fu! s:Open() 244 | cal s:log(1) 245 | cal s:getenv() 246 | cal s:execextvar('enter') 247 | sil! exe 'keepa' ( s:mwbottom ? 'bo' : 'to' ) '1new ControlP' 248 | cal s:buffunc(1) 249 | let [s:bufnr, s:winw] = [bufnr('%'), winwidth(0)] 250 | let [s:focus, s:prompt] = [1, ['', '', '']] 251 | abc 252 | if !exists('s:hstry') 253 | let hst = filereadable(s:gethistloc()[1]) ? s:gethistdata() : [''] 254 | let s:hstry = empty(hst) || !s:maxhst ? [''] : hst 255 | en 256 | for [ke, va] in items(s:glbs) | if exists('+'.ke) 257 | sil! exe 'let s:glb_'.ke.' = &'.ke.' | let &'.ke.' = '.string(va) 258 | en | endfo 259 | if s:opmul != '0' && has('signs') 260 | sign define ctrlpmark text=+> texthl=Search 261 | en 262 | cal s:setupblank() 263 | endf 264 | 265 | fu! s:Close() 266 | cal s:buffunc(0) 267 | try | bun! 268 | cat | clo! | endt 269 | cal s:unmarksigns() 270 | for key in keys(s:glbs) | if exists('+'.key) 271 | sil! exe 'let &'.key.' = s:glb_'.key 272 | en | endfo 273 | if exists('s:glb_acd') | let &acd = s:glb_acd | en 274 | let g:ctrlp_lines = [] 275 | if s:winres[1] >= &lines && s:winres[2] == winnr('$') 276 | exe s:winres[0].s:winres[0] 277 | en 278 | unl! s:focus s:hisidx s:hstgot s:marked s:statypes s:cline s:init s:savestr 279 | \ s:mrbs s:did_exp 280 | cal ctrlp#recordhist() 281 | cal s:execextvar('exit') 282 | cal s:log(0) 283 | let v:errmsg = s:ermsg 284 | ec 285 | endf 286 | " * Clear caches {{{1 287 | fu! ctrlp#clr(...) 288 | let [s:matches, g:ctrlp_new{ a:0 ? a:1 : 'cache' }] = [1, 1] 289 | endf 290 | 291 | fu! ctrlp#clra() 292 | let cadir = ctrlp#utils#cachedir() 293 | if isdirectory(cadir) 294 | let cafiles = split(s:glbpath(s:fnesc(cadir, 'g', ','), '**', 1), "\n") 295 | let eval = '!isdirectory(v:val) && fnamemodify(v:val, ":t") !~' 296 | \ . ' ''\v^[.a-z]+$|\.log$''' 297 | sil! cal map(filter(cafiles, eval), 'delete(v:val)') 298 | en 299 | cal ctrlp#clr() 300 | endf 301 | 302 | fu! s:Reset(args) 303 | let opts = has_key(a:args, 'opts') ? [a:args['opts']] : [] 304 | cal call('s:opts', opts) 305 | cal s:autocmds() 306 | cal ctrlp#utils#opts() 307 | cal s:execextvar('opts') 308 | endf 309 | " * Files {{{1 310 | fu! ctrlp#files() 311 | let cafile = ctrlp#utils#cachefile() 312 | if g:ctrlp_newcache || !filereadable(cafile) || s:nocache(cafile) 313 | let [lscmd, s:initcwd, g:ctrlp_allfiles] = [s:lsCmd(), s:dyncwd, []] 314 | " Get the list of files 315 | if empty(lscmd) 316 | cal s:GlobPath(s:fnesc(s:dyncwd, 'g', ','), 0) 317 | el 318 | sil! cal ctrlp#progress('Indexing...') 319 | try | cal s:UserCmd(lscmd) 320 | cat | retu [] | endt 321 | en 322 | " Remove base directory 323 | cal ctrlp#rmbasedir(g:ctrlp_allfiles) 324 | if len(g:ctrlp_allfiles) <= s:compare_lim 325 | cal sort(g:ctrlp_allfiles, 'ctrlp#complen') 326 | en 327 | cal s:writecache(cafile) 328 | let catime = getftime(cafile) 329 | el 330 | let catime = getftime(cafile) 331 | if !( exists('s:initcwd') && s:initcwd == s:dyncwd ) 332 | \ || get(s:ficounts, s:dyncwd, [0, catime])[1] != catime 333 | let s:initcwd = s:dyncwd 334 | let g:ctrlp_allfiles = ctrlp#utils#readfile(cafile) 335 | en 336 | en 337 | cal extend(s:ficounts, { s:dyncwd : [len(g:ctrlp_allfiles), catime] }) 338 | retu g:ctrlp_allfiles 339 | endf 340 | 341 | fu! s:GlobPath(dirs, depth) 342 | let entries = split(globpath(a:dirs, s:glob), "\n") 343 | let [dnf, depth] = [ctrlp#dirnfile(entries), a:depth + 1] 344 | cal extend(g:ctrlp_allfiles, dnf[1]) 345 | if !empty(dnf[0]) && !s:maxf(len(g:ctrlp_allfiles)) && depth <= s:maxdepth 346 | sil! cal ctrlp#progress(len(g:ctrlp_allfiles), 1) 347 | cal s:GlobPath(join(map(dnf[0], 's:fnesc(v:val, "g", ",")'), ','), depth) 348 | en 349 | endf 350 | 351 | fu! s:UserCmd(lscmd) 352 | let [path, lscmd] = [s:dyncwd, a:lscmd] 353 | if exists('+ssl') && &ssl 354 | let [ssl, &ssl, path] = [&ssl, 0, tr(path, '/', '\')] 355 | en 356 | if has('win32') || has('win64') 357 | let lscmd = substitute(lscmd, '\v(^|&&\s*)\zscd (/d)@!', 'cd /d ', '') 358 | en 359 | let path = exists('*shellescape') ? shellescape(path) : path 360 | let g:ctrlp_allfiles = split(system(printf(lscmd, path)), "\n") 361 | if exists('+ssl') && exists('ssl') 362 | let &ssl = ssl 363 | cal map(g:ctrlp_allfiles, 'tr(v:val, "\\", "/")') 364 | en 365 | if exists('s:vcscmd') && s:vcscmd 366 | cal map(g:ctrlp_allfiles, 'tr(v:val, "/", "\\")') 367 | en 368 | if type(s:usrcmd) == 4 && has_key(s:usrcmd, 'ignore') && s:usrcmd['ignore'] 369 | if !empty(s:usrign) 370 | let g:ctrlp_allfiles = ctrlp#dirnfile(g:ctrlp_allfiles)[1] 371 | en 372 | if &wig != '' 373 | cal filter(g:ctrlp_allfiles, 'glob(v:val) != ""') 374 | en 375 | en 376 | endf 377 | 378 | fu! s:lsCmd() 379 | let cmd = s:usrcmd 380 | if type(cmd) == 1 381 | retu cmd 382 | elsei type(cmd) == 3 && len(cmd) >= 2 && cmd[:1] != ['', ''] 383 | if s:findroot(s:dyncwd, cmd[0], 0, 1) == [] 384 | retu len(cmd) == 3 ? cmd[2] : '' 385 | en 386 | let s:vcscmd = s:lash == '\' 387 | retu cmd[1] 388 | elsei type(cmd) == 4 && ( has_key(cmd, 'types') || has_key(cmd, 'fallback') ) 389 | let fndroot = [] 390 | if has_key(cmd, 'types') && cmd['types'] != {} 391 | let [markrs, cmdtypes] = [[], values(cmd['types'])] 392 | for pair in cmdtypes 393 | cal add(markrs, pair[0]) 394 | endfo 395 | let fndroot = s:findroot(s:dyncwd, markrs, 0, 1) 396 | en 397 | if fndroot == [] 398 | retu has_key(cmd, 'fallback') ? cmd['fallback'] : '' 399 | en 400 | for pair in cmdtypes 401 | if pair[0] == fndroot[0] | brea | en 402 | endfo 403 | let s:vcscmd = s:lash == '\' 404 | retu pair[1] 405 | en 406 | endf 407 | " - Buffers {{{1 408 | fu! ctrlp#buffers(...) 409 | let ids = sort(filter(range(1, bufnr('$')), 'empty(getbufvar(v:val, "&bt"))' 410 | \ .' && getbufvar(v:val, "&bl") && strlen(bufname(v:val))'), 's:compmreb') 411 | retu a:0 && a:1 == 'id' ? ids : map(ids, 'fnamemodify(bufname(v:val), ":.")') 412 | endf 413 | " * MatchedItems() {{{1 414 | fu! s:MatchIt(items, pat, limit, exc) 415 | let [lines, id] = [[], 0] 416 | let pat = 417 | \ s:byfname ? map(split(a:pat, '^[^;]\+\\\@= 0 422 | cal add(lines, item) 423 | en | cat | brea | endt 424 | if a:limit > 0 && len(lines) >= a:limit | brea | en 425 | endfo 426 | let s:mdata = [s:dyncwd, s:itemtype, s:regexp, s:sublist(a:items, id, -1)] 427 | retu lines 428 | endf 429 | 430 | fu! s:MatchedItems(items, pat, limit) 431 | let exc = exists('s:crfilerel') ? s:crfilerel : '' 432 | let items = s:narrowable() ? s:matched + s:mdata[3] : a:items 433 | if s:matcher != {} 434 | let argms = [items, a:pat, a:limit, s:mmode(), s:ispath, exc, s:regexp] 435 | let lines = call(s:matcher['match'], argms, s:matcher) 436 | el 437 | let lines = s:MatchIt(items, a:pat, a:limit, exc) 438 | en 439 | let s:matches = len(lines) 440 | unl! s:did_exp 441 | retu lines 442 | endf 443 | 444 | fu! s:SplitPattern(str) 445 | let str = a:str 446 | if s:migemo && s:regexp && len(str) > 0 && executable('cmigemo') 447 | let str = s:migemo(str) 448 | en 449 | let s:savestr = str 450 | if s:regexp 451 | let pat = s:regexfilter(str) 452 | el 453 | let lst = split(str, '\zs') 454 | if exists('+ssl') && !&ssl 455 | cal map(lst, 'escape(v:val, ''\'')') 456 | en 457 | for each in ['^', '$', '.'] 458 | cal map(lst, 'escape(v:val, each)') 459 | endfo 460 | en 461 | if exists('lst') 462 | let pat = '' 463 | if !empty(lst) 464 | if s:byfname && index(lst, ';') > 0 465 | let fbar = index(lst, ';') 466 | let lst_1 = s:sublist(lst, 0, fbar - 1) 467 | let lst_2 = len(lst) - 1 > fbar ? s:sublist(lst, fbar + 1, -1) : [''] 468 | let pat = s:buildpat(lst_1).';'.s:buildpat(lst_2) 469 | el 470 | let pat = s:buildpat(lst) 471 | en 472 | en 473 | en 474 | retu escape(pat, '~') 475 | endf 476 | " * BuildPrompt() {{{1 477 | fu! s:Render(lines, pat) 478 | let [&ma, lines, s:height] = [1, a:lines, min([len(a:lines), s:winh])] 479 | let pat = s:byfname ? split(a:pat, '^[^;]\+\\\@' ).( s:byfname ? 'd' : '>' ).'> ' 535 | let str = escape(s:getinput(), '\') 536 | let lazy = str == '' || exists('s:force') || !has('autocmd') ? 0 : s:lazy 537 | if a:upd && !lazy && ( s:matches || s:regexp || exists('s:did_exp') 538 | \ || str =~ '\(\\\(<\|>\)\|[*|]\)\|\(\\\:\([^:]\|\\:\)*$\)' ) 539 | sil! cal s:Update(str) 540 | en 541 | sil! cal ctrlp#statusline() 542 | " Toggling 543 | let [hiactive, hicursor, base] = s:focus 544 | \ ? ['CtrlPPrtText', 'CtrlPPrtCursor', base] 545 | \ : ['CtrlPPrtBase', 'CtrlPPrtBase', tr(base, '>', '-')] 546 | let hibase = 'CtrlPPrtBase' 547 | " Build it 548 | redr 549 | let prt = copy(s:prompt) 550 | cal map(prt, 'escape(v:val, ''"\'')') 551 | exe 'echoh' hibase '| echon "'.base.'" 552 | \ | echoh' hiactive '| echon "'.prt[0].'" 553 | \ | echoh' hicursor '| echon "'.prt[1].'" 554 | \ | echoh' hiactive '| echon "'.prt[2].'" | echoh None' 555 | " Append the cursor at the end 556 | if empty(prt[1]) && s:focus 557 | exe 'echoh' hibase '| echon "_" | echoh None' 558 | en 559 | endf 560 | " - SetDefTxt() {{{1 561 | fu! s:SetDefTxt() 562 | if s:deftxt == '0' || ( s:deftxt == 1 && !s:ispath ) | retu | en 563 | let txt = s:deftxt 564 | if !type(txt) 565 | let txt = txt && !stridx(s:crfpath, s:dyncwd) 566 | \ ? ctrlp#rmbasedir([s:crfpath])[0] : '' 567 | let txt = txt != '' ? txt.s:lash(s:crfpath) : '' 568 | el 569 | let txt = expand(txt, 1) 570 | en 571 | let s:prompt[0] = txt 572 | endf 573 | " ** Prt Actions {{{1 574 | " Editing {{{2 575 | fu! s:PrtClear() 576 | if !s:focus | retu | en 577 | unl! s:hstgot 578 | let [s:prompt, s:matches] = [['', '', ''], 1] 579 | cal s:BuildPrompt(1) 580 | endf 581 | 582 | fu! s:PrtAdd(char) 583 | unl! s:hstgot 584 | let s:act_add = 1 585 | let s:prompt[0] .= a:char 586 | cal s:BuildPrompt(1) 587 | unl s:act_add 588 | endf 589 | 590 | fu! s:PrtBS() 591 | if !s:focus | retu | en 592 | unl! s:hstgot 593 | let [s:prompt[0], s:matches] = [substitute(s:prompt[0], '.$', '', ''), 1] 594 | cal s:BuildPrompt(1) 595 | endf 596 | 597 | fu! s:PrtDelete() 598 | if !s:focus | retu | en 599 | unl! s:hstgot 600 | let [prt, s:matches] = [s:prompt, 1] 601 | let prt[1] = matchstr(prt[2], '^.') 602 | let prt[2] = substitute(prt[2], '^.', '', '') 603 | cal s:BuildPrompt(1) 604 | endf 605 | 606 | fu! s:PrtDeleteWord() 607 | if !s:focus | retu | en 608 | unl! s:hstgot 609 | let [str, s:matches] = [s:prompt[0], 1] 610 | let str = str =~ '\W\w\+$' ? matchstr(str, '^.\+\W\ze\w\+$') 611 | \ : str =~ '\w\W\+$' ? matchstr(str, '^.\+\w\ze\W\+$') 612 | \ : str =~ '\s\+$' ? matchstr(str, '^.*\S\ze\s\+$') 613 | \ : str =~ '\v^(\S+|\s+)$' ? '' : str 614 | let s:prompt[0] = str 615 | cal s:BuildPrompt(1) 616 | endf 617 | 618 | fu! s:PrtInsert(...) 619 | if !s:focus | retu | en 620 | let type = !a:0 ? '' : a:1 621 | if !a:0 622 | let type = s:insertstr() 623 | if type == 'cancel' | retu | en 624 | en 625 | if type ==# 'r' 626 | let regcont = s:getregs() 627 | if regcont < 0 | retu | en 628 | en 629 | unl! s:hstgot 630 | let s:act_add = 1 631 | let s:prompt[0] .= type ==# 'w' ? s:crword 632 | \ : type ==# 'f' ? s:crgfile 633 | \ : type ==# 's' ? s:regisfilter('/') 634 | \ : type ==# 'v' ? s:crvisual 635 | \ : type ==# 'c' ? s:regisfilter('+') 636 | \ : type ==# 'r' ? regcont : '' 637 | cal s:BuildPrompt(1) 638 | unl s:act_add 639 | endf 640 | 641 | fu! s:PrtExpandDir() 642 | if !s:focus | retu | en 643 | let str = s:getinput('c') 644 | if str =~ '\v^\@(cd|lc[hd]?|chd)\s.+' && s:spi 645 | let hasat = split(str, '\v^\@(cd|lc[hd]?|chd)\s*\zs') 646 | let str = get(hasat, 1, '') 647 | en 648 | if str == '' | retu | en 649 | unl! s:hstgot 650 | let s:act_add = 1 651 | let [base, seed] = s:headntail(str) 652 | let dirs = s:dircompl(base, seed) 653 | if len(dirs) == 1 654 | let str = dirs[0] 655 | elsei len(dirs) > 1 656 | let str .= s:findcommon(dirs, str) 657 | en 658 | let s:prompt[0] = exists('hasat') ? hasat[0].str : str 659 | cal s:BuildPrompt(1) 660 | unl s:act_add 661 | endf 662 | " Movement {{{2 663 | fu! s:PrtCurLeft() 664 | if !s:focus | retu | en 665 | let prt = s:prompt 666 | if !empty(prt[0]) 667 | let s:prompt = [substitute(prt[0], '.$', '', ''), matchstr(prt[0], '.$'), 668 | \ prt[1] . prt[2]] 669 | en 670 | cal s:BuildPrompt(0) 671 | endf 672 | 673 | fu! s:PrtCurRight() 674 | if !s:focus | retu | en 675 | let prt = s:prompt 676 | let s:prompt = [prt[0] . prt[1], matchstr(prt[2], '^.'), 677 | \ substitute(prt[2], '^.', '', '')] 678 | cal s:BuildPrompt(0) 679 | endf 680 | 681 | fu! s:PrtCurStart() 682 | if !s:focus | retu | en 683 | let str = join(s:prompt, '') 684 | let s:prompt = ['', matchstr(str, '^.'), substitute(str, '^.', '', '')] 685 | cal s:BuildPrompt(0) 686 | endf 687 | 688 | fu! s:PrtCurEnd() 689 | if !s:focus | retu | en 690 | let s:prompt = [join(s:prompt, ''), '', ''] 691 | cal s:BuildPrompt(0) 692 | endf 693 | 694 | fu! s:PrtSelectMove(dir) 695 | let wht = winheight(0) 696 | let dirs = {'t': 'gg','b': 'G','j': 'j','k': 'k','u': wht.'k','d': wht.'j'} 697 | exe 'keepj norm!' dirs[a:dir] 698 | if s:nolim != 1 | let s:cline = line('.') | en 699 | if line('$') > winheight(0) | cal s:BuildPrompt(0) | en 700 | endf 701 | 702 | fu! s:PrtSelectJump(char) 703 | let lines = copy(s:lines) 704 | if s:byfname 705 | cal map(lines, 'split(v:val, ''[\/]\ze[^\/]\+$'')[-1]') 706 | en 707 | " Cycle through matches, use s:jmpchr to store last jump 708 | let chr = escape(matchstr(a:char, '^.'), '.~') 709 | let smartcs = &scs && chr =~ '\u' ? '\C' : '' 710 | if match(lines, smartcs.'^'.chr) >= 0 711 | " If not exists or does but not for the same char 712 | let pos = match(lines, smartcs.'^'.chr) 713 | if !exists('s:jmpchr') || ( exists('s:jmpchr') && s:jmpchr[0] != chr ) 714 | let [jmpln, s:jmpchr] = [pos, [chr, pos]] 715 | elsei exists('s:jmpchr') && s:jmpchr[0] == chr 716 | " Start of lines 717 | if s:jmpchr[1] == -1 | let s:jmpchr[1] = pos | en 718 | let npos = match(lines, smartcs.'^'.chr, s:jmpchr[1] + 1) 719 | let [jmpln, s:jmpchr] = [npos == -1 ? pos : npos, [chr, npos]] 720 | en 721 | exe 'keepj norm!' ( jmpln + 1 ).'G' 722 | if s:nolim != 1 | let s:cline = line('.') | en 723 | if line('$') > winheight(0) | cal s:BuildPrompt(0) | en 724 | en 725 | endf 726 | " Misc {{{2 727 | fu! s:PrtFocusMap(char) 728 | cal call(( s:focus ? 's:PrtAdd' : 's:PrtSelectJump' ), [a:char]) 729 | endf 730 | 731 | fu! s:PrtClearCache() 732 | if s:itemtype == 0 733 | cal ctrlp#clr() 734 | elsei s:itemtype > 2 735 | cal ctrlp#clr(s:statypes[s:itemtype][1]) 736 | en 737 | if s:itemtype == 2 738 | let g:ctrlp_lines = ctrlp#mrufiles#refresh() 739 | el 740 | cal ctrlp#setlines() 741 | en 742 | let s:force = 1 743 | cal s:BuildPrompt(1) 744 | unl s:force 745 | endf 746 | 747 | fu! s:PrtDeleteEnt() 748 | if s:itemtype == 2 749 | cal s:PrtDeleteMRU() 750 | elsei type(s:getextvar('wipe')) == 1 751 | cal s:delent(s:getextvar('wipe')) 752 | en 753 | endf 754 | 755 | fu! s:PrtDeleteMRU() 756 | if s:itemtype == 2 757 | cal s:delent('ctrlp#mrufiles#remove') 758 | en 759 | endf 760 | 761 | fu! s:PrtExit() 762 | if !has('autocmd') | cal s:Close() | en 763 | exe ( winnr('$') == 1 ? 'bw!' : 'winc p' ) 764 | endf 765 | 766 | fu! s:PrtHistory(...) 767 | if !s:focus || !s:maxhst | retu | en 768 | let [str, hst, s:matches] = [join(s:prompt, ''), s:hstry, 1] 769 | " Save to history if not saved before 770 | let [hst[0], hslen] = [exists('s:hstgot') ? hst[0] : str, len(hst)] 771 | let idx = exists('s:hisidx') ? s:hisidx + a:1 : a:1 772 | " Limit idx within 0 and hslen 773 | let idx = idx < 0 ? 0 : idx >= hslen ? hslen > 1 ? hslen - 1 : 0 : idx 774 | let s:prompt = [hst[idx], '', ''] 775 | let [s:hisidx, s:hstgot, s:force] = [idx, 1, 1] 776 | cal s:BuildPrompt(1) 777 | unl s:force 778 | endf 779 | "}}}1 780 | " * Mappings {{{1 781 | fu! s:MapNorms() 782 | if exists('s:nmapped') && s:nmapped == s:bufnr | retu | en 783 | let pcmd = "nn \ \ \ :\cal \%s(\"%s\")\" 784 | let cmd = substitute(pcmd, 'k%s', 'char-%d', '') 785 | let pfunc = 'PrtFocusMap' 786 | let ranges = [32, 33, 125, 126] + range(35, 91) + range(93, 123) 787 | for each in [34, 92, 124] 788 | exe printf(cmd, each, pfunc, escape(nr2char(each), '"|\')) 789 | endfo 790 | for each in ranges 791 | exe printf(cmd, each, pfunc, nr2char(each)) 792 | endfo 793 | for each in range(0, 9) 794 | exe printf(pcmd, each, pfunc, each) 795 | endfo 796 | for [ke, va] in items(s:kprange) 797 | exe printf(pcmd, ke, pfunc, va) 798 | endfo 799 | let s:nmapped = s:bufnr 800 | endf 801 | 802 | fu! s:MapSpecs() 803 | if !( exists('s:smapped') && s:smapped == s:bufnr ) 804 | " Correct arrow keys in terminal 805 | if ( has('termresponse') && v:termresponse =~ "\" ) 806 | \ || &term =~? '\vxterm|','\B ','\C ','\D '] 808 | exe s:lcmap.' ['.each 809 | endfo 810 | en 811 | en 812 | for [ke, va] in items(s:prtmaps) | for kp in va 813 | exe s:lcmap kp ':cal '.ke.'' 814 | endfo | endfo 815 | let s:smapped = s:bufnr 816 | endf 817 | 818 | fu! s:KeyLoop() 819 | wh exists('s:init') && s:keyloop 820 | redr 821 | let nr = getchar() 822 | let chr = !type(nr) ? nr2char(nr) : nr 823 | if nr >=# 0x20 824 | cal s:PrtFocusMap(chr) 825 | el 826 | let cmd = matchstr(maparg(chr), ':\zs.\+\ze$') 827 | exe ( cmd != '' ? cmd : 'norm '.chr ) 828 | en 829 | endw 830 | endf 831 | " * Toggling {{{1 832 | fu! s:ToggleFocus() 833 | let s:focus = !s:focus 834 | cal s:BuildPrompt(0) 835 | endf 836 | 837 | fu! s:ToggleRegex() 838 | let s:regexp = !s:regexp 839 | cal s:PrtSwitcher() 840 | endf 841 | 842 | fu! s:ToggleByFname() 843 | if s:ispath 844 | let s:byfname = !s:byfname 845 | let s:mfunc = s:mfunc() 846 | cal s:PrtSwitcher() 847 | en 848 | endf 849 | 850 | fu! s:ToggleType(dir) 851 | let max = len(g:ctrlp_ext_vars) + 2 852 | let next = s:walker(max, s:itemtype, a:dir) 853 | cal ctrlp#syntax() 854 | cal ctrlp#setlines(next) 855 | cal s:PrtSwitcher() 856 | endf 857 | 858 | fu! s:ToggleKeyLoop() 859 | let s:keyloop = !s:keyloop 860 | if exists('+imd') 861 | let &imd = !s:keyloop 862 | en 863 | if s:keyloop 864 | let [&ut, s:lazy] = [0, 0] 865 | cal s:KeyLoop() 866 | elsei has_key(s:glbs, 'ut') 867 | let [&ut, s:lazy] = [s:glbs['ut'], 1] 868 | en 869 | endf 870 | 871 | fu! s:PrtSwitcher() 872 | let [s:force, s:matches] = [1, 1] 873 | cal s:BuildPrompt(1) 874 | unl s:force 875 | endf 876 | " - SetWD() {{{1 877 | fu! s:SetWD(args) 878 | if has_key(a:args, 'args') && stridx(a:args['args'], '--dir') >= 0 879 | \ && exists('s:dyncwd') 880 | cal ctrlp#setdir(s:dyncwd) | retu 881 | en 882 | if has_key(a:args, 'dir') && a:args['dir'] != '' 883 | cal ctrlp#setdir(a:args['dir']) | retu 884 | en 885 | let pmode = has_key(a:args, 'mode') ? a:args['mode'] : s:pathmode 886 | let [s:crfilerel, s:dyncwd] = [fnamemodify(s:crfile, ':.'), getcwd()] 887 | if s:crfile =~ '^.\+://' | retu | en 888 | if pmode =~ 'c' || ( pmode =~ 'a' && stridx(s:crfpath, s:cwd) < 0 ) 889 | \ || ( !type(pmode) && pmode ) 890 | if exists('+acd') | let [s:glb_acd, &acd] = [&acd, 0] | en 891 | cal ctrlp#setdir(s:crfpath) 892 | en 893 | if pmode =~ 'r' || pmode == 2 894 | let markers = ['.git', '.hg', '.svn', '.bzr', '_darcs'] 895 | let spath = pmode =~ 'd' ? s:dyncwd : pmode =~ 'w' ? s:cwd : s:crfpath 896 | if type(s:rmarkers) == 3 && !empty(s:rmarkers) 897 | if s:findroot(spath, s:rmarkers, 0, 0) != [] | retu | en 898 | cal filter(markers, 'index(s:rmarkers, v:val) < 0') 899 | en 900 | cal s:findroot(spath, markers, 0, 0) 901 | en 902 | endf 903 | " * AcceptSelection() {{{1 904 | fu! ctrlp#acceptfile(mode, line, ...) 905 | let [md, filpath] = [a:mode, fnamemodify(a:line, ':p')] 906 | cal s:PrtExit() 907 | let [bufnr, tail] = [bufnr('^'.filpath.'$'), s:tail()] 908 | let j2l = a:0 ? a:1 : matchstr(tail, '^ +\zs\d\+$') 909 | if ( s:jmptobuf =~ md || ( s:jmptobuf && md =~ '[et]' ) ) && bufnr > 0 910 | \ && !( md == 'e' && bufnr == bufnr('%') ) 911 | let [jmpb, bufwinnr] = [1, bufwinnr(bufnr)] 912 | let buftab = ( s:jmptobuf =~# '[tTVH]' || s:jmptobuf > 1 ) 913 | \ ? s:buftab(bufnr, md) : [0, 0] 914 | en 915 | " Switch to existing buffer or open new one 916 | if exists('jmpb') && bufwinnr > 0 917 | \ && !( md == 't' && ( s:jmptobuf !~# toupper(md) || buftab[0] ) ) 918 | exe bufwinnr.'winc w' 919 | if j2l | cal ctrlp#j2l(j2l) | en 920 | elsei exists('jmpb') && buftab[0] 921 | \ && !( md =~ '[evh]' && s:jmptobuf !~# toupper(md) ) 922 | exe 'tabn' buftab[0] 923 | exe buftab[1].'winc w' 924 | if j2l | cal ctrlp#j2l(j2l) | en 925 | el 926 | " Determine the command to use 927 | let useb = bufnr > 0 && buflisted(bufnr) && empty(tail) 928 | let cmd = 929 | \ md == 't' || s:splitwin == 1 ? ( useb ? 'tab sb' : 'tabe' ) : 930 | \ md == 'h' || s:splitwin == 2 ? ( useb ? 'sb' : 'new' ) : 931 | \ md == 'v' || s:splitwin == 3 ? ( useb ? 'vert sb' : 'vne' ) : 932 | \ call('ctrlp#normcmd', useb ? ['b', 'bo vert sb'] : ['e']) 933 | " Reset &switchbuf option 934 | let [swb, &swb] = [&swb, ''] 935 | " Open new window/buffer 936 | let [fid, tail] = [( useb ? bufnr : filpath ), ( a:0 ? ' +'.a:1 : tail )] 937 | let args = [cmd, fid, tail, 1, [useb, j2l]] 938 | cal call('s:openfile', args) 939 | let &swb = swb 940 | en 941 | endf 942 | 943 | fu! s:SpecInputs(str) 944 | if a:str =~ '\v^(\.\.([\/]\.\.)*[\/]?[.\/]*)$' && s:spi 945 | let cwd = s:dyncwd 946 | cal ctrlp#setdir(a:str =~ '^\.\.\.*$' ? 947 | \ '../'.repeat('../', strlen(a:str) - 2) : a:str) 948 | if cwd != s:dyncwd | cal ctrlp#setlines() | en 949 | cal s:PrtClear() 950 | retu 1 951 | elsei a:str == s:lash && s:spi 952 | cal s:SetWD({ 'mode': 'rd' }) 953 | cal ctrlp#setlines() 954 | cal s:PrtClear() 955 | retu 1 956 | elsei a:str =~ '^@.\+' && s:spi 957 | retu s:at(a:str) 958 | elsei a:str == '?' 959 | cal s:PrtExit() 960 | let hlpwin = &columns > 159 ? '| vert res 80' : '' 961 | sil! exe 'bo vert h ctrlp-mappings' hlpwin '| norm! 0' 962 | retu 1 963 | en 964 | retu 0 965 | endf 966 | 967 | fu! s:AcceptSelection(mode) 968 | if a:mode != 'e' && s:OpenMulti(a:mode) != -1 | retu | en 969 | let str = s:getinput() 970 | if a:mode == 'e' | if s:SpecInputs(str) | retu | en | en 971 | " Get the selected line 972 | let line = ctrlp#getcline() 973 | if a:mode != 'e' && !s:itemtype && line == '' 974 | \ && str !~ '\v^(\.\.([\/]\.\.)*[\/]?[.\/]*|/|\\|\?|\@.+)$' 975 | cal s:CreateNewFile(a:mode) | retu 976 | en 977 | if empty(line) | retu | en 978 | " Do something with it 979 | if s:openfunc != {} && has_key(s:openfunc, s:ctype) 980 | let actfunc = s:openfunc[s:ctype] 981 | el 982 | let actfunc = s:itemtype < 3 ? 'ctrlp#acceptfile' : s:getextvar('accept') 983 | en 984 | cal call(actfunc, [a:mode, line]) 985 | endf 986 | " - CreateNewFile() {{{1 987 | fu! s:CreateNewFile(...) 988 | let [md, str] = ['', s:getinput('n')] 989 | if empty(str) | retu | en 990 | if s:argmap && !a:0 991 | " Get the extra argument 992 | let md = s:argmaps(md, 1) 993 | if md == 'cancel' | retu | en 994 | en 995 | let str = s:sanstail(str) 996 | let [base, fname] = s:headntail(str) 997 | if fname =~ '^[\/]$' | retu | en 998 | if exists('s:marked') && len(s:marked) 999 | " Use the first marked file's path 1000 | let path = fnamemodify(values(s:marked)[0], ':p:h') 1001 | let base = path.s:lash(path).base 1002 | let str = fnamemodify(base.s:lash.fname, ':.') 1003 | en 1004 | if base != '' | if isdirectory(ctrlp#utils#mkdir(base)) 1005 | let optyp = str | en | el | let optyp = fname 1006 | en 1007 | if !exists('optyp') | retu | en 1008 | let [filpath, tail] = [fnamemodify(optyp, ':p'), s:tail()] 1009 | if !stridx(filpath, s:dyncwd) | cal s:insertcache(str) | en 1010 | cal s:PrtExit() 1011 | let cmd = md == 'r' ? ctrlp#normcmd('e') : 1012 | \ s:newfop =~ '1\|t' || ( a:0 && a:1 == 't' ) || md == 't' ? 'tabe' : 1013 | \ s:newfop =~ '2\|h' || ( a:0 && a:1 == 'h' ) || md == 'h' ? 'new' : 1014 | \ s:newfop =~ '3\|v' || ( a:0 && a:1 == 'v' ) || md == 'v' ? 'vne' : 1015 | \ ctrlp#normcmd('e') 1016 | cal s:openfile(cmd, filpath, tail, 1) 1017 | endf 1018 | " * OpenMulti() {{{1 1019 | fu! s:MarkToOpen() 1020 | if s:bufnr <= 0 || s:opmul == '0' 1021 | \ || ( s:itemtype > 2 && s:getextvar('opmul') != 1 ) 1022 | retu 1023 | en 1024 | let line = ctrlp#getcline() 1025 | if empty(line) | retu | en 1026 | let filpath = s:ispath ? fnamemodify(line, ':p') : line 1027 | if exists('s:marked') && s:dictindex(s:marked, filpath) > 0 1028 | " Unmark and remove the file from s:marked 1029 | let key = s:dictindex(s:marked, filpath) 1030 | cal remove(s:marked, key) 1031 | if empty(s:marked) | unl s:marked | en 1032 | if has('signs') 1033 | exe 'sign unplace' key 'buffer='.s:bufnr 1034 | en 1035 | el 1036 | " Add to s:marked and place a new sign 1037 | if exists('s:marked') 1038 | let vac = s:vacantdict(s:marked) 1039 | let key = empty(vac) ? len(s:marked) + 1 : vac[0] 1040 | let s:marked = extend(s:marked, { key : filpath }) 1041 | el 1042 | let [key, s:marked] = [1, { 1 : filpath }] 1043 | en 1044 | if has('signs') 1045 | exe 'sign place' key 'line='.line('.').' name=ctrlpmark buffer='.s:bufnr 1046 | en 1047 | en 1048 | sil! cal ctrlp#statusline() 1049 | endf 1050 | 1051 | fu! s:OpenMulti(...) 1052 | let has_marked = exists('s:marked') 1053 | if ( !has_marked && a:0 ) || s:opmul == '0' || !s:ispath 1054 | \ || ( s:itemtype > 2 && s:getextvar('opmul') != 1 ) 1055 | retu -1 1056 | en 1057 | " Get the options 1058 | let [nr, md] = [matchstr(s:opmul, '\d\+'), matchstr(s:opmul, '[thvi]')] 1059 | let [ur, jf] = [s:opmul =~ 'r', s:opmul =~ 'j'] 1060 | let md = a:0 ? a:1 : ( md == '' ? 'v' : md ) 1061 | let nopt = exists('g:ctrlp_open_multiple_files') 1062 | if !has_marked 1063 | let line = ctrlp#getcline() 1064 | if line == '' | retu | en 1065 | let marked = { 1 : fnamemodify(line, ':p') } 1066 | let [nr, ur, jf, nopt] = ['1', 0, 0, 1] 1067 | en 1068 | if ( s:argmap || !has_marked ) && !a:0 1069 | let md = s:argmaps(md, !has_marked ? 2 : 0) 1070 | if md == 'c' 1071 | cal s:unmarksigns() 1072 | unl! s:marked 1073 | cal s:BuildPrompt(0) 1074 | elsei !has_marked && md =~ '[axd]' 1075 | retu s:OpenNoMarks(md, line) 1076 | en 1077 | if md =~ '\v^c(ancel)?$' | retu | en 1078 | let nr = nr == '0' ? ( nopt ? '' : '1' ) : nr 1079 | let ur = !has_marked && md == 'r' ? 1 : ur 1080 | en 1081 | let mkd = values(has_marked ? s:marked : marked) 1082 | cal s:sanstail(join(s:prompt, '')) 1083 | cal s:PrtExit() 1084 | if nr == '0' || md == 'i' 1085 | retu map(mkd, "s:openfile('bad', v:val, '', 0)") 1086 | en 1087 | let tail = s:tail() 1088 | let [emptytail, bufnr] = [empty(tail), bufnr('^'.mkd[0].'$')] 1089 | let useb = bufnr > 0 && buflisted(bufnr) && emptytail 1090 | " Move to a replaceable window 1091 | let ncmd = ( useb ? ['b', 'bo vert sb'] : ['e', 'bo vne'] ) 1092 | \ + ( ur ? [] : ['ignruw'] ) 1093 | let fst = call('ctrlp#normcmd', ncmd) 1094 | " Check if the current window has a replaceable buffer 1095 | let repabl = !( md == 't' && !ur ) && empty(bufname('%')) && empty(&l:ft) 1096 | " Commands for the rest of the files 1097 | let [ic, cmds] = [1, { 'v': ['vert sb', 'vne'], 'h': ['sb', 'new'], 1098 | \ 't': ['tab sb', 'tabe'] }] 1099 | let [swb, &swb] = [&swb, ''] 1100 | if md == 't' && ctrlp#tabcount() < tabpagenr() 1101 | let s:tabct = ctrlp#tabcount() 1102 | en 1103 | " Open the files 1104 | for va in mkd 1105 | let bufnr = bufnr('^'.va.'$') 1106 | if bufnr < 0 && getftype(va) == '' | con | en 1107 | let useb = bufnr > 0 && buflisted(bufnr) && emptytail 1108 | let snd = md != '' && has_key(cmds, md) ? 1109 | \ ( useb ? cmds[md][0] : cmds[md][1] ) : ( useb ? 'vert sb' : 'vne' ) 1110 | let cmd = ic == 1 && ( !( !ur && fst =~ '^[eb]$' ) || repabl ) ? fst : snd 1111 | let conds = [( nr != '' && nr > 1 && nr < ic ) || ( nr == '' && ic > 1 ), 1112 | \ nr != '' && nr < ic] 1113 | if conds[nopt] 1114 | if !buflisted(bufnr) | cal s:openfile('bad', va, '', 0) | en 1115 | el 1116 | cal s:openfile(cmd, useb ? bufnr : va, tail, ic == 1) 1117 | if jf | if ic == 1 1118 | let crpos = [tabpagenr(), winnr()] 1119 | el 1120 | let crpos[0] += tabpagenr() <= crpos[0] 1121 | let crpos[1] += winnr() <= crpos[1] 1122 | en | en 1123 | let ic += 1 1124 | en 1125 | endfo 1126 | if jf && exists('crpos') && ic > 2 1127 | exe ( md == 't' ? 'tabn '.crpos[0] : crpos[1].'winc w' ) 1128 | en 1129 | let &swb = swb 1130 | unl! s:tabct 1131 | endf 1132 | 1133 | fu! s:OpenNoMarks(md, line) 1134 | if a:md == 'a' 1135 | let [s:marked, key] = [{}, 1] 1136 | for line in s:lines 1137 | let s:marked = extend(s:marked, { key : fnamemodify(line, ':p') }) 1138 | let key += 1 1139 | endfo 1140 | cal s:remarksigns() 1141 | cal s:BuildPrompt(0) 1142 | elsei a:md == 'x' 1143 | cal call(s:openfunc[s:ctype], [a:md, a:line], s:openfunc) 1144 | elsei a:md == 'd' 1145 | let dir = fnamemodify(a:line, ':h') 1146 | if isdirectory(dir) 1147 | cal ctrlp#setdir(dir) 1148 | cal ctrlp#switchtype(0) 1149 | cal ctrlp#recordhist() 1150 | cal s:PrtClear() 1151 | en 1152 | en 1153 | endf 1154 | " ** Helper functions {{{1 1155 | " Sorting {{{2 1156 | fu! ctrlp#complen(...) 1157 | " By length 1158 | let [len1, len2] = [strlen(a:1), strlen(a:2)] 1159 | retu len1 == len2 ? 0 : len1 > len2 ? 1 : -1 1160 | endf 1161 | 1162 | fu! s:compmatlen(...) 1163 | " By match length 1164 | let mln1 = s:shortest(s:matchlens(a:1, s:compat)) 1165 | let mln2 = s:shortest(s:matchlens(a:2, s:compat)) 1166 | retu mln1 == mln2 ? 0 : mln1 > mln2 ? 1 : -1 1167 | endf 1168 | 1169 | fu! s:comptime(...) 1170 | " By last modified time 1171 | let [time1, time2] = [getftime(a:1), getftime(a:2)] 1172 | retu time1 == time2 ? 0 : time1 < time2 ? 1 : -1 1173 | endf 1174 | 1175 | fu! s:compmreb(...) 1176 | " By last entered time (bufnr) 1177 | let [id1, id2] = [index(s:mrbs, a:1), index(s:mrbs, a:2)] 1178 | retu id1 == id2 ? 0 : id1 > id2 ? 1 : -1 1179 | endf 1180 | 1181 | fu! s:compmref(...) 1182 | " By last entered time (MRU) 1183 | let [id1, id2] = [index(g:ctrlp_lines, a:1), index(g:ctrlp_lines, a:2)] 1184 | retu id1 == id2 ? 0 : id1 > id2 ? 1 : -1 1185 | endf 1186 | 1187 | fu! s:comparent(...) 1188 | " By same parent dir 1189 | if !stridx(s:crfpath, s:dyncwd) 1190 | let [as1, as2] = [s:dyncwd.s:lash().a:1, s:dyncwd.s:lash().a:2] 1191 | let [loc1, loc2] = [s:getparent(as1), s:getparent(as2)] 1192 | if loc1 == s:crfpath && loc2 != s:crfpath | retu -1 | en 1193 | if loc2 == s:crfpath && loc1 != s:crfpath | retu 1 | en 1194 | retu 0 1195 | en 1196 | retu 0 1197 | endf 1198 | 1199 | fu! s:compfnlen(...) 1200 | " By filename length 1201 | let len1 = strlen(split(a:1, s:lash)[-1]) 1202 | let len2 = strlen(split(a:2, s:lash)[-1]) 1203 | retu len1 == len2 ? 0 : len1 > len2 ? 1 : -1 1204 | endf 1205 | 1206 | fu! s:matchlens(str, pat, ...) 1207 | if empty(a:pat) || index(['^', '$'], a:pat) >= 0 | retu {} | en 1208 | let st = a:0 ? a:1 : 0 1209 | let lens = a:0 >= 2 ? a:2 : {} 1210 | let nr = a:0 >= 3 ? a:3 : 0 1211 | if nr > 20 | retu {} | en 1212 | if match(a:str, a:pat, st) >= 0 1213 | let [mst, mnd] = [matchstr(a:str, a:pat, st), matchend(a:str, a:pat, st)] 1214 | let lens = extend(lens, { nr : [strlen(mst), mst] }) 1215 | let lens = s:matchlens(a:str, a:pat, mnd, lens, nr + 1) 1216 | en 1217 | retu lens 1218 | endf 1219 | 1220 | fu! s:shortest(lens) 1221 | retu min(map(values(a:lens), 'v:val[0]')) 1222 | endf 1223 | 1224 | fu! s:mixedsort(...) 1225 | let [cln, cml] = [ctrlp#complen(a:1, a:2), s:compmatlen(a:1, a:2)] 1226 | if s:ispath 1227 | let ms = [] 1228 | if s:height < 21 1229 | let ms += [s:compfnlen(a:1, a:2)] 1230 | if s:itemtype !~ '^[12]$' | let ms += [s:comptime(a:1, a:2)] | en 1231 | if !s:itemtype | let ms += [s:comparent(a:1, a:2)] | en 1232 | en 1233 | if s:itemtype =~ '^[12]$' 1234 | let ms += [s:compmref(a:1, a:2)] 1235 | let cln = cml ? cln : 0 1236 | en 1237 | let ms += [cml, 0, 0, 0] 1238 | let mp = call('s:multipliers', ms[:3]) 1239 | retu cln + ms[0] * mp[0] + ms[1] * mp[1] + ms[2] * mp[2] + ms[3] * mp[3] 1240 | en 1241 | retu cln + cml * 2 1242 | endf 1243 | 1244 | fu! s:multipliers(...) 1245 | let mp0 = !a:1 ? 0 : 2 1246 | let mp1 = !a:2 ? 0 : 1 + ( !mp0 ? 1 : mp0 ) 1247 | let mp2 = !a:3 ? 0 : 1 + ( !( mp0 + mp1 ) ? 1 : ( mp0 + mp1 ) ) 1248 | let mp3 = !a:4 ? 0 : 1 + ( !( mp0 + mp1 + mp2 ) ? 1 : ( mp0 + mp1 + mp2 ) ) 1249 | retu [mp0, mp1, mp2, mp3] 1250 | endf 1251 | 1252 | fu! s:compval(...) 1253 | retu a:1 - a:2 1254 | endf 1255 | " Statusline {{{2 1256 | fu! ctrlp#statusline() 1257 | if !exists('s:statypes') 1258 | let s:statypes = [ 1259 | \ ['files', 'fil'], 1260 | \ ['buffers', 'buf'], 1261 | \ ['mru files', 'mru'], 1262 | \ ] 1263 | if !empty(g:ctrlp_ext_vars) 1264 | cal map(copy(g:ctrlp_ext_vars), 1265 | \ 'add(s:statypes, [ v:val["lname"], v:val["sname"] ])') 1266 | en 1267 | en 1268 | let tps = s:statypes 1269 | let max = len(tps) - 1 1270 | let nxt = tps[s:walker(max, s:itemtype, 1)][1] 1271 | let prv = tps[s:walker(max, s:itemtype, -1)][1] 1272 | let s:ctype = tps[s:itemtype][0] 1273 | let focus = s:focus ? 'prt' : 'win' 1274 | let byfname = s:byfname ? 'file' : 'path' 1275 | let marked = s:opmul != '0' ? 1276 | \ exists('s:marked') ? ' <'.s:dismrk().'>' : ' <->' : '' 1277 | if s:status != {} 1278 | let args = [focus, byfname, s:regexp, prv, s:ctype, nxt, marked] 1279 | let &l:stl = call(s:status['main'], args, s:status) 1280 | el 1281 | let item = '%#CtrlPMode1# '.s:ctype.' %*' 1282 | let focus = '%#CtrlPMode2# '.focus.' %*' 1283 | let byfname = '%#CtrlPMode1# '.byfname.' %*' 1284 | let regex = s:regexp ? '%#CtrlPMode2# regex %*' : '' 1285 | let slider = ' <'.prv.'>={'.item.'}=<'.nxt.'>' 1286 | let dir = ' %=%<%#CtrlPMode2# %{getcwd()} %*' 1287 | let &l:stl = focus.byfname.regex.slider.marked.dir 1288 | en 1289 | endf 1290 | 1291 | fu! s:dismrk() 1292 | retu has('signs') ? len(s:marked) : 1293 | \ '%<'.join(values(map(copy(s:marked), 'split(v:val, "[\\/]")[-1]')), ', ') 1294 | endf 1295 | 1296 | fu! ctrlp#progress(enum, ...) 1297 | if has('macunix') || has('mac') | sl 1m | en 1298 | let txt = a:0 ? '(press ctrl-c to abort)' : '' 1299 | let &l:stl = s:status != {} ? call(s:status['prog'], [a:enum], s:status) 1300 | \ : '%#CtrlPStats# '.a:enum.' %* '.txt.'%=%<%#CtrlPMode2# %{getcwd()} %*' 1301 | redraws 1302 | endf 1303 | " *** Paths {{{2 1304 | " Line formatting {{{3 1305 | fu! s:formatline(str) 1306 | let str = a:str 1307 | if s:itemtype == 1 1308 | let bfnr = bufnr('^'.fnamemodify(str, ':p').'$') 1309 | let idc = ( bfnr == bufnr('#') ? '#' : '' ) 1310 | \ . ( getbufvar(bfnr, '&ma') ? '' : '-' ) 1311 | \ . ( getbufvar(bfnr, '&ro') ? '=' : '' ) 1312 | \ . ( getbufvar(bfnr, '&mod') ? '+' : '' ) 1313 | let str .= idc != '' ? ' '.idc : '' 1314 | en 1315 | let cond = s:ispath && ( s:winw - 4 ) < s:strwidth(str) 1316 | retu '> '.( cond ? s:pathshorten(str) : str ) 1317 | endf 1318 | 1319 | fu! s:pathshorten(str) 1320 | retu matchstr(a:str, '^.\{9}').'...' 1321 | \ .matchstr(a:str, '.\{'.( s:winw - 16 ).'}$') 1322 | endf 1323 | " Directory completion {{{3 1324 | fu! s:dircompl(be, sd) 1325 | if a:sd == '' | retu [] | en 1326 | let [be, sd] = a:be == '' ? [s:dyncwd, a:sd] : [a:be, a:be.s:lash(a:be).a:sd] 1327 | let dirs = ctrlp#rmbasedir(split(globpath(s:fnesc(be, 'g', ','), a:sd.'*/'), "\n")) 1328 | cal filter(dirs, '!match(v:val, escape(sd, ''~$.\''))' 1329 | \ . ' && v:val !~ ''\v(^|[\/])\.{1,2}[\/]$''') 1330 | retu dirs 1331 | endf 1332 | 1333 | fu! s:findcommon(items, seed) 1334 | let [items, id, cmn, ic] = [copy(a:items), strlen(a:seed), '', 0] 1335 | cal map(items, 'strpart(v:val, id)') 1336 | for char in split(items[0], '\zs') 1337 | for item in items[1:] 1338 | if item[ic] != char | let brk = 1 | brea | en 1339 | endfo 1340 | if exists('brk') | brea | en 1341 | let cmn .= char 1342 | let ic += 1 1343 | endfo 1344 | retu cmn 1345 | endf 1346 | " Misc {{{3 1347 | fu! s:headntail(str) 1348 | let parts = split(a:str, '[\/]\ze[^\/]\+[\/:]\?$') 1349 | retu len(parts) == 1 ? ['', parts[0]] : len(parts) == 2 ? parts : [] 1350 | endf 1351 | 1352 | fu! s:lash(...) 1353 | retu ( a:0 ? a:1 : s:dyncwd ) !~ '[\/]$' ? s:lash : '' 1354 | endf 1355 | 1356 | fu! s:ispathitem() 1357 | retu s:itemtype < 3 || ( s:itemtype > 2 && s:getextvar('type') == 'path' ) 1358 | endf 1359 | 1360 | fu! ctrlp#dirnfile(entries) 1361 | let [items, cwd] = [[[], []], s:dyncwd.s:lash()] 1362 | for each in a:entries 1363 | let etype = getftype(each) 1364 | if s:igntype >= 0 && s:usrign(each, etype) | con | en 1365 | if etype == 'dir' 1366 | if s:showhidden | if each !~ '[\/]\.\{1,2}$' 1367 | cal add(items[0], each) 1368 | en | el 1369 | cal add(items[0], each) 1370 | en 1371 | elsei etype == 'link' 1372 | if s:folsym 1373 | let isfile = !isdirectory(each) 1374 | if s:folsym == 2 || !s:samerootsyml(each, isfile, cwd) 1375 | cal add(items[isfile], each) 1376 | en 1377 | en 1378 | elsei etype == 'file' 1379 | cal add(items[1], each) 1380 | en 1381 | endfo 1382 | retu items 1383 | endf 1384 | 1385 | fu! s:usrign(item, type) 1386 | retu s:igntype == 1 ? a:item =~ s:usrign 1387 | \ : s:igntype == 4 && has_key(s:usrign, a:type) && s:usrign[a:type] != '' 1388 | \ ? a:item =~ s:usrign[a:type] : 0 1389 | endf 1390 | 1391 | fu! s:samerootsyml(each, isfile, cwd) 1392 | let resolve = fnamemodify(resolve(a:each), ':p:h') 1393 | let resolve .= s:lash(resolve) 1394 | retu !( stridx(resolve, a:cwd) && ( stridx(a:cwd, resolve) || a:isfile ) ) 1395 | endf 1396 | 1397 | fu! ctrlp#rmbasedir(items) 1398 | let cwd = s:dyncwd.( s:dyncwd !~ '[\/]$' ? s:lash : '' ) 1399 | if a:items != [] && !stridx(a:items[0], cwd) 1400 | let idx = strlen(cwd) 1401 | retu map(a:items, 'strpart(v:val, idx)') 1402 | en 1403 | retu a:items 1404 | endf 1405 | " Working directory {{{3 1406 | fu! s:getparent(item) 1407 | let parent = substitute(a:item, '[\/][^\/]\+[\/:]\?$', '', '') 1408 | if parent == '' || parent !~ '[\/]' 1409 | let parent .= s:lash 1410 | en 1411 | retu parent 1412 | endf 1413 | 1414 | fu! s:findroot(curr, mark, depth, type) 1415 | let [depth, fnd] = [a:depth + 1, 0] 1416 | if type(a:mark) == 1 1417 | let fnd = s:glbpath(s:fnesc(a:curr, 'g', ','), a:mark, 1) != '' 1418 | elsei type(a:mark) == 3 1419 | for markr in a:mark 1420 | if s:glbpath(s:fnesc(a:curr, 'g', ','), markr, 1) != '' 1421 | let fnd = 1 1422 | brea 1423 | en 1424 | endfo 1425 | en 1426 | if fnd 1427 | if !a:type | cal ctrlp#setdir(a:curr) | en 1428 | retu [exists('markr') ? markr : a:mark, a:curr] 1429 | elsei depth > s:maxdepth 1430 | cal ctrlp#setdir(s:cwd) 1431 | el 1432 | let parent = s:getparent(a:curr) 1433 | if parent != a:curr 1434 | retu s:findroot(parent, a:mark, depth, a:type) 1435 | en 1436 | en 1437 | retu [] 1438 | endf 1439 | 1440 | fu! ctrlp#setdir(path, ...) 1441 | let cmd = a:0 ? a:1 : 'lc!' 1442 | sil! exe cmd s:fnesc(a:path, 'c') 1443 | let [s:crfilerel, s:dyncwd] = [fnamemodify(s:crfile, ':.'), getcwd()] 1444 | endf 1445 | " Fallbacks {{{3 1446 | fu! s:glbpath(...) 1447 | retu call('ctrlp#utils#globpath', a:000) 1448 | endf 1449 | 1450 | fu! s:fnesc(...) 1451 | retu call('ctrlp#utils#fnesc', a:000) 1452 | endf 1453 | 1454 | fu! ctrlp#setlcdir() 1455 | if exists('*haslocaldir') 1456 | cal ctrlp#setdir(getcwd(), haslocaldir() ? 'lc!' : 'cd!') 1457 | en 1458 | endf 1459 | " Highlighting {{{2 1460 | fu! ctrlp#syntax() 1461 | if ctrlp#nosy() | retu | en 1462 | for [ke, va] in items(s:hlgrps) | cal ctrlp#hicheck('CtrlP'.ke, va) | endfo 1463 | if !hlexists('CtrlPLinePre') 1464 | \ && synIDattr(synIDtrans(hlID('Normal')), 'bg') !~ '^-1$\|^$' 1465 | sil! exe 'hi CtrlPLinePre '.( has("gui_running") ? 'gui' : 'cterm' ).'fg=bg' 1466 | en 1467 | sy match CtrlPNoEntries '^ == NO ENTRIES ==$' 1468 | if hlexists('CtrlPLinePre') 1469 | sy match CtrlPLinePre '^>' 1470 | en 1471 | endf 1472 | 1473 | fu! s:highlight(pat, grp) 1474 | if s:matcher != {} | retu | en 1475 | cal clearmatches() 1476 | if !empty(a:pat) && s:ispath 1477 | let pat = s:regexp ? substitute(a:pat, '\\\@ \\zs', 'g') : a:pat 1478 | if s:byfname 1479 | let pat = substitute(pat, '\[\^\(.\{-}\)\]\\{-}', '[^\\/\1]\\{-}', 'g') 1480 | let pat = substitute(pat, '\$\@') 1484 | en 1485 | endf 1486 | 1487 | fu! s:dohighlight() 1488 | retu s:mathi[0] && exists('*clearmatches') && !ctrlp#nosy() 1489 | endf 1490 | " Prompt history {{{2 1491 | fu! s:gethistloc() 1492 | let utilcadir = ctrlp#utils#cachedir() 1493 | let cache_dir = utilcadir.s:lash(utilcadir).'hist' 1494 | retu [cache_dir, cache_dir.s:lash(cache_dir).'cache.txt'] 1495 | endf 1496 | 1497 | fu! s:gethistdata() 1498 | retu ctrlp#utils#readfile(s:gethistloc()[1]) 1499 | endf 1500 | 1501 | fu! ctrlp#recordhist() 1502 | let str = join(s:prompt, '') 1503 | if empty(str) || !s:maxhst | retu | en 1504 | let hst = s:hstry 1505 | if len(hst) > 1 && hst[1] == str | retu | en 1506 | cal extend(hst, [str], 1) 1507 | if len(hst) > s:maxhst | cal remove(hst, s:maxhst, -1) | en 1508 | cal ctrlp#utils#writecache(hst, s:gethistloc()[0], s:gethistloc()[1]) 1509 | endf 1510 | " Signs {{{2 1511 | fu! s:unmarksigns() 1512 | if !s:dosigns() | retu | en 1513 | for key in keys(s:marked) 1514 | exe 'sign unplace' key 'buffer='.s:bufnr 1515 | endfo 1516 | endf 1517 | 1518 | fu! s:remarksigns() 1519 | if !s:dosigns() | retu | en 1520 | for ic in range(1, len(s:lines)) 1521 | let line = s:ispath ? fnamemodify(s:lines[ic - 1], ':p') : s:lines[ic - 1] 1522 | let key = s:dictindex(s:marked, line) 1523 | if key > 0 1524 | exe 'sign place' key 'line='.ic.' name=ctrlpmark buffer='.s:bufnr 1525 | en 1526 | endfo 1527 | endf 1528 | 1529 | fu! s:dosigns() 1530 | retu exists('s:marked') && s:bufnr > 0 && s:opmul != '0' && has('signs') 1531 | endf 1532 | " Lists & Dictionaries {{{2 1533 | fu! s:dictindex(dict, expr) 1534 | for key in keys(a:dict) 1535 | if a:dict[key] == a:expr | retu key | en 1536 | endfo 1537 | retu -1 1538 | endf 1539 | 1540 | fu! s:vacantdict(dict) 1541 | retu filter(range(1, max(keys(a:dict))), '!has_key(a:dict, v:val)') 1542 | endf 1543 | 1544 | fu! s:sublist(l, s, e) 1545 | retu v:version > 701 ? a:l[(a:s):(a:e)] : s:sublist7071(a:l, a:s, a:e) 1546 | endf 1547 | 1548 | fu! s:sublist7071(l, s, e) 1549 | let [newlist, id, ae] = [[], a:s, a:e == -1 ? len(a:l) - 1 : a:e] 1550 | wh id <= ae 1551 | cal add(newlist, get(a:l, id)) 1552 | let id += 1 1553 | endw 1554 | retu newlist 1555 | endf 1556 | " Buffers {{{2 1557 | fu! s:buftab(bufnr, md) 1558 | for tabnr in range(1, tabpagenr('$')) 1559 | if tabpagenr() == tabnr && a:md == 't' | con | en 1560 | let buflist = tabpagebuflist(tabnr) 1561 | if index(buflist, a:bufnr) >= 0 1562 | for winnr in range(1, tabpagewinnr(tabnr, '$')) 1563 | if buflist[winnr - 1] == a:bufnr | retu [tabnr, winnr] | en 1564 | endfo 1565 | en 1566 | endfo 1567 | retu [0, 0] 1568 | endf 1569 | 1570 | fu! s:bufwins(bufnr) 1571 | let winns = 0 1572 | for tabnr in range(1, tabpagenr('$')) 1573 | let winns += count(tabpagebuflist(tabnr), a:bufnr) 1574 | endfo 1575 | retu winns 1576 | endf 1577 | 1578 | fu! ctrlp#normcmd(cmd, ...) 1579 | if a:0 < 2 && s:nosplit() | retu a:cmd | en 1580 | let norwins = filter(range(1, winnr('$')), 1581 | \ 'empty(getbufvar(winbufnr(v:val), "&bt"))') 1582 | for each in norwins 1583 | let bufnr = winbufnr(each) 1584 | if empty(bufname(bufnr)) && empty(getbufvar(bufnr, '&ft')) 1585 | let fstemp = each | brea 1586 | en 1587 | endfo 1588 | let norwin = empty(norwins) ? 0 : norwins[0] 1589 | if norwin 1590 | if index(norwins, winnr()) < 0 1591 | exe ( exists('fstemp') ? fstemp : norwin ).'winc w' 1592 | en 1593 | retu a:cmd 1594 | en 1595 | retu a:0 ? a:1 : 'bo vne' 1596 | endf 1597 | 1598 | fu! ctrlp#modfilecond(w) 1599 | retu &mod && !&hid && &bh != 'hide' && s:bufwins(bufnr('%')) == 1 && !&cf && 1600 | \ ( ( !&awa && a:w ) || filewritable(fnamemodify(bufname('%'), ':p')) != 1 ) 1601 | endf 1602 | 1603 | fu! s:nosplit() 1604 | retu !empty(s:nosplit) && match([bufname('%'), &l:ft, &l:bt], s:nosplit) >= 0 1605 | endf 1606 | 1607 | fu! s:setupblank() 1608 | setl noswf nonu nobl nowrap nolist nospell nocuc wfh 1609 | setl fdc=0 fdl=99 tw=0 bt=nofile bh=unload 1610 | if v:version > 702 1611 | setl nornu noudf cc=0 1612 | en 1613 | endf 1614 | 1615 | fu! s:leavepre() 1616 | if exists('s:bufnr') && s:bufnr == bufnr('%') | bw! | en 1617 | if !( exists(s:ccex) && !{s:ccex} ) 1618 | \ && !( has('clientserver') && len(split(serverlist(), "\n")) > 1 ) 1619 | cal ctrlp#clra() 1620 | en 1621 | endf 1622 | 1623 | fu! s:checkbuf() 1624 | if !exists('s:init') && exists('s:bufnr') && s:bufnr > 0 1625 | exe s:bufnr.'bw!' 1626 | en 1627 | endf 1628 | 1629 | fu! s:iscmdwin() 1630 | let ermsg = v:errmsg 1631 | sil! noa winc p 1632 | sil! noa winc p 1633 | let [v:errmsg, ermsg] = [ermsg, v:errmsg] 1634 | retu ermsg =~ '^E11:' 1635 | endf 1636 | " Arguments {{{2 1637 | fu! s:at(str) 1638 | if a:str =~ '\v^\@(cd|lc[hd]?|chd).*' 1639 | let str = substitute(a:str, '\v^\@(cd|lc[hd]?|chd)\s*', '', '') 1640 | if str == '' | retu 1 | en 1641 | let str = str =~ '^%:.\+' ? fnamemodify(s:crfile, str[1:]) : str 1642 | let path = fnamemodify(expand(str, 1), ':p') 1643 | if isdirectory(path) 1644 | if path != s:dyncwd 1645 | cal ctrlp#setdir(path) 1646 | cal ctrlp#setlines() 1647 | en 1648 | cal ctrlp#recordhist() 1649 | cal s:PrtClear() 1650 | en 1651 | retu 1 1652 | en 1653 | retu 0 1654 | endf 1655 | 1656 | fu! s:tail() 1657 | if exists('s:optail') && !empty('s:optail') 1658 | let tailpref = s:optail !~ '^\s*+' ? ' +' : ' ' 1659 | retu tailpref.s:optail 1660 | en 1661 | retu '' 1662 | endf 1663 | 1664 | fu! s:sanstail(str) 1665 | let str = s:spi ? 1666 | \ substitute(a:str, '^\(@.*$\|\\\\\ze@\|\.\.\zs[.\/]\+$\)', '', 'g') : a:str 1667 | let [str, pat] = [substitute(str, '\\\\', '\', 'g'), '\([^:]\|\\:\)*$'] 1668 | unl! s:optail 1669 | if str =~ '\\\@= 0 1709 | retu char 1710 | elsei char =~# "\\v\|\|\|\|\|\" 1711 | cal s:BuildPrompt(0) 1712 | retu 'cancel' 1713 | elsei char =~# "\" && a:args != [] 1714 | retu a:args[0] 1715 | en 1716 | retu call(a:func, a:args) 1717 | endf 1718 | 1719 | fu! s:getregs() 1720 | let char = s:textdialog('Insert from register: ') 1721 | if char =~# "\\v\|\|\|\|\|\" 1722 | cal s:BuildPrompt(0) 1723 | retu -1 1724 | elsei char =~# "\" 1725 | retu s:getregs() 1726 | en 1727 | retu s:regisfilter(char) 1728 | endf 1729 | 1730 | fu! s:regisfilter(reg) 1731 | retu substitute(getreg(a:reg), "[\t\n]", ' ', 'g') 1732 | endf 1733 | " Misc {{{2 1734 | fu! s:modevar() 1735 | let s:matchtype = s:mtype() 1736 | let s:ispath = s:ispathitem() 1737 | if !s:ispath | let s:byfname = 0 | en 1738 | let s:mfunc = s:mfunc() 1739 | let s:nolim = s:getextvar('nolim') 1740 | let s:dosort = s:getextvar('sort') 1741 | let s:spi = !s:itemtype || s:getextvar('specinput') > 0 1742 | endf 1743 | 1744 | fu! s:nosort() 1745 | retu s:matcher != {} || s:nolim == 1 || ( s:itemtype == 2 && s:mrudef ) 1746 | \ || ( s:itemtype =~ '\v^(1|2)$' && s:prompt == ['', '', ''] ) || !s:dosort 1747 | endf 1748 | 1749 | fu! s:narrowable() 1750 | retu exists('s:act_add') && exists('s:matched') && s:matched != [] 1751 | \ && exists('s:mdata') && s:mdata[:2] == [s:dyncwd, s:itemtype, s:regexp] 1752 | \ && s:matcher == {} && !exists('s:did_exp') 1753 | endf 1754 | 1755 | fu! s:getinput(...) 1756 | let [prt, spi] = [s:prompt, ( a:0 ? a:1 : '' )] 1757 | if s:abbrev != {} 1758 | let gmd = has_key(s:abbrev, 'gmode') ? s:abbrev['gmode'] : '' 1759 | let str = ( gmd =~ 't' && !a:0 ) || spi == 'c' ? prt[0] : join(prt, '') 1760 | if gmd =~ 't' && gmd =~ 'k' && !a:0 && matchstr(str, '.$') =~ '\k' 1761 | retu join(prt, '') 1762 | en 1763 | let [pf, rz] = [( s:byfname ? 'f' : 'p' ), ( s:regexp ? 'r' : 'z' )] 1764 | for dict in s:abbrev['abbrevs'] 1765 | let dmd = has_key(dict, 'mode') ? dict['mode'] : '' 1766 | let pat = escape(dict['pattern'], '~') 1767 | if ( dmd == '' || ( dmd =~ pf && dmd =~ rz && !a:0 ) 1768 | \ || dmd =~ '['.spi.']' ) && str =~ pat 1769 | let [str, s:did_exp] = [join(split(str, pat, 1), dict['expanded']), 1] 1770 | en 1771 | endfo 1772 | if gmd =~ 't' && !a:0 1773 | let prt[0] = str 1774 | el 1775 | retu str 1776 | en 1777 | en 1778 | retu spi == 'c' ? prt[0] : join(prt, '') 1779 | endf 1780 | 1781 | fu! s:migemo(str) 1782 | let [str, rtp] = [a:str, s:fnesc(&rtp, 'g')] 1783 | let dict = s:glbpath(rtp, printf("dict/%s/migemo-dict", &enc), 1) 1784 | if !len(dict) 1785 | let dict = s:glbpath(rtp, "dict/migemo-dict", 1) 1786 | en 1787 | if len(dict) 1788 | let [tokens, str, cmd] = [split(str, '\s'), '', 'cmigemo -v -w %s -d %s'] 1789 | for token in tokens 1790 | let rtn = system(printf(cmd, shellescape(token), shellescape(dict))) 1791 | let str .= !v:shell_error && strlen(rtn) > 0 ? '.*'.rtn : token 1792 | endfo 1793 | en 1794 | retu str 1795 | endf 1796 | 1797 | fu! s:strwidth(str) 1798 | retu exists('*strdisplaywidth') ? strdisplaywidth(a:str) : strlen(a:str) 1799 | endf 1800 | 1801 | fu! ctrlp#j2l(nr) 1802 | exe 'norm!' a:nr.'G' 1803 | sil! norm! zvzz 1804 | endf 1805 | 1806 | fu! s:maxf(len) 1807 | retu s:maxfiles && a:len > s:maxfiles 1808 | endf 1809 | 1810 | fu! s:regexfilter(str) 1811 | let str = a:str 1812 | for key in keys(s:fpats) | if str =~ key 1813 | let str = substitute(str, s:fpats[key], '', 'g') 1814 | en | endfo 1815 | retu str 1816 | endf 1817 | 1818 | fu! s:walker(m, p, d) 1819 | retu a:d >= 0 ? a:p < a:m ? a:p + a:d : 0 : a:p > 0 ? a:p + a:d : a:m 1820 | endf 1821 | 1822 | fu! s:delent(rfunc) 1823 | if a:rfunc == '' | retu | en 1824 | let [s:force, tbrem] = [1, []] 1825 | if exists('s:marked') 1826 | let tbrem = values(s:marked) 1827 | cal s:unmarksigns() 1828 | unl s:marked 1829 | en 1830 | if tbrem == [] && ( has('dialog_gui') || has('dialog_con') ) && 1831 | \ confirm("Wipe all entries?", "&OK\n&Cancel") != 1 1832 | unl s:force 1833 | cal s:BuildPrompt(0) 1834 | retu 1835 | en 1836 | let g:ctrlp_lines = call(a:rfunc, [tbrem]) 1837 | cal s:BuildPrompt(1) 1838 | unl s:force 1839 | endf 1840 | " Entering & Exiting {{{2 1841 | fu! s:getenv() 1842 | let [s:cwd, s:winres] = [getcwd(), [winrestcmd(), &lines, winnr('$')]] 1843 | let [s:crfile, s:crfpath] = [expand('%:p', 1), expand('%:p:h', 1)] 1844 | let [s:crword, s:crline] = [expand('', 1), getline('.')] 1845 | let [s:winh, s:crcursor] = [min([s:mxheight, &lines]), getpos('.')] 1846 | let [s:crbufnr, s:crvisual] = [bufnr('%'), s:lastvisual()] 1847 | let [s:mrbs, s:crgfile] = [ctrlp#mrufiles#bufs(), expand('', 1)] 1848 | endf 1849 | 1850 | fu! s:lastvisual() 1851 | let cview = winsaveview() 1852 | let [ovreg, ovtype] = [getreg('v'), getregtype('v')] 1853 | let [oureg, outype] = [getreg('"'), getregtype('"')] 1854 | sil! norm! gv"vy 1855 | let selected = s:regisfilter('v') 1856 | cal setreg('v', ovreg, ovtype) 1857 | cal setreg('"', oureg, outype) 1858 | cal winrestview(cview) 1859 | retu selected 1860 | endf 1861 | 1862 | fu! s:log(m) 1863 | if exists('g:ctrlp_log') && g:ctrlp_log | if a:m 1864 | let cadir = ctrlp#utils#cachedir() 1865 | sil! exe 'redi! >' cadir.s:lash(cadir).'ctrlp.log' 1866 | el 1867 | sil! redi END 1868 | en | en 1869 | endf 1870 | 1871 | fu! s:buffunc(e) 1872 | if a:e && has_key(s:buffunc, 'enter') 1873 | cal call(s:buffunc['enter'], [], s:buffunc) 1874 | elsei !a:e && has_key(s:buffunc, 'exit') 1875 | cal call(s:buffunc['exit'], [], s:buffunc) 1876 | en 1877 | endf 1878 | 1879 | fu! s:openfile(cmd, fid, tail, chkmod, ...) 1880 | let cmd = a:cmd 1881 | if a:chkmod && cmd =~ '^[eb]$' && ctrlp#modfilecond(!( cmd == 'b' && &aw )) 1882 | let cmd = cmd == 'b' ? 'sb' : 'sp' 1883 | en 1884 | let cmd = cmd =~ '^tab' ? ctrlp#tabcount().cmd : cmd 1885 | let j2l = a:0 && a:1[0] ? a:1[1] : 0 1886 | exe cmd.( a:0 && a:1[0] ? '' : a:tail ) s:fnesc(a:fid, 'f') 1887 | if j2l 1888 | cal ctrlp#j2l(j2l) 1889 | en 1890 | if !empty(a:tail) 1891 | sil! norm! zvzz 1892 | en 1893 | if cmd != 'bad' 1894 | cal ctrlp#setlcdir() 1895 | en 1896 | endf 1897 | 1898 | fu! ctrlp#tabcount() 1899 | if exists('s:tabct') 1900 | let tabct = s:tabct 1901 | let s:tabct += 1 1902 | elsei !type(s:tabpage) 1903 | let tabct = s:tabpage 1904 | elsei type(s:tabpage) == 1 1905 | let tabpos = 1906 | \ s:tabpage =~ 'c' ? tabpagenr() : 1907 | \ s:tabpage =~ 'f' ? 1 : 1908 | \ s:tabpage =~ 'l' ? tabpagenr('$') : 1909 | \ tabpagenr() 1910 | let tabct = 1911 | \ s:tabpage =~ 'a' ? tabpos : 1912 | \ s:tabpage =~ 'b' ? tabpos - 1 : 1913 | \ tabpos 1914 | en 1915 | retu tabct < 0 ? 0 : tabct 1916 | endf 1917 | 1918 | fu! s:settype(type) 1919 | retu a:type < 0 ? exists('s:itemtype') ? s:itemtype : 0 : a:type 1920 | endf 1921 | " Matching {{{2 1922 | fu! s:matchfname(item, pat) 1923 | let parts = split(a:item, '[\/]\ze[^\/]\+$') 1924 | let mfn = match(parts[-1], a:pat[0]) 1925 | retu len(a:pat) == 1 ? mfn : len(a:pat) == 2 ? 1926 | \ ( mfn >= 0 && ( len(parts) == 2 ? match(parts[0], a:pat[1]) : -1 ) >= 0 1927 | \ ? 0 : -1 ) : -1 1928 | en 1929 | endf 1930 | 1931 | fu! s:matchtabs(item, pat) 1932 | retu match(split(a:item, '\t\+')[0], a:pat) 1933 | endf 1934 | 1935 | fu! s:matchtabe(item, pat) 1936 | retu match(split(a:item, '\t\+[^\t]\+$')[0], a:pat) 1937 | endf 1938 | 1939 | fu! s:buildpat(lst) 1940 | let pat = a:lst[0] 1941 | for item in range(1, len(a:lst) - 1) 1942 | let pat .= '[^'.a:lst[item - 1].']\{-}'.a:lst[item] 1943 | endfo 1944 | retu pat 1945 | endf 1946 | 1947 | fu! s:mfunc() 1948 | let mfunc = 'match' 1949 | if s:byfname && s:ispath 1950 | let mfunc = 's:matchfname' 1951 | elsei s:itemtype > 2 1952 | let matchtypes = { 'tabs': 's:matchtabs', 'tabe': 's:matchtabe' } 1953 | if has_key(matchtypes, s:matchtype) 1954 | let mfunc = matchtypes[s:matchtype] 1955 | en 1956 | en 1957 | retu mfunc 1958 | endf 1959 | 1960 | fu! s:mmode() 1961 | let matchmodes = { 1962 | \ 'match': 'full-line', 1963 | \ 's:matchfname': 'filename-only', 1964 | \ 's:matchtabs': 'first-non-tab', 1965 | \ 's:matchtabe': 'until-last-tab', 1966 | \ } 1967 | retu matchmodes[s:mfunc] 1968 | endf 1969 | " Cache {{{2 1970 | fu! s:writecache(cafile) 1971 | if ( g:ctrlp_newcache || !filereadable(a:cafile) ) && !s:nocache() 1972 | cal ctrlp#utils#writecache(g:ctrlp_allfiles) 1973 | let g:ctrlp_newcache = 0 1974 | en 1975 | endf 1976 | 1977 | fu! s:nocache(...) 1978 | if !s:caching 1979 | retu 1 1980 | elsei s:caching > 1 1981 | if !( exists(s:ccex) && !{s:ccex} ) || has_key(s:ficounts, s:dyncwd) 1982 | retu get(s:ficounts, s:dyncwd, [0, 0])[0] < s:caching 1983 | elsei a:0 && filereadable(a:1) 1984 | retu len(ctrlp#utils#readfile(a:1)) < s:caching 1985 | en 1986 | retu 1 1987 | en 1988 | retu 0 1989 | endf 1990 | 1991 | fu! s:insertcache(str) 1992 | let [data, g:ctrlp_newcache, str] = [g:ctrlp_allfiles, 1, a:str] 1993 | if data == [] || strlen(str) <= strlen(data[0]) 1994 | let pos = 0 1995 | elsei strlen(str) >= strlen(data[-1]) 1996 | let pos = len(data) - 1 1997 | el 1998 | let pos = 0 1999 | for each in data 2000 | if strlen(each) > strlen(str) | brea | en 2001 | let pos += 1 2002 | endfo 2003 | en 2004 | cal insert(data, str, pos) 2005 | cal s:writecache(ctrlp#utils#cachefile()) 2006 | endf 2007 | " Extensions {{{2 2008 | fu! s:mtype() 2009 | retu s:itemtype > 2 ? s:getextvar('type') : 'path' 2010 | endf 2011 | 2012 | fu! s:execextvar(key) 2013 | if !empty(g:ctrlp_ext_vars) 2014 | cal map(filter(copy(g:ctrlp_ext_vars), 2015 | \ 'has_key(v:val, a:key)'), 'eval(v:val[a:key])') 2016 | en 2017 | endf 2018 | 2019 | fu! s:getextvar(key) 2020 | if s:itemtype > 2 2021 | let vars = g:ctrlp_ext_vars[s:itemtype - 3] 2022 | retu has_key(vars, a:key) ? vars[a:key] : -1 2023 | en 2024 | retu -1 2025 | endf 2026 | 2027 | fu! ctrlp#getcline() 2028 | retu !empty(s:lines) ? s:lines[line('.') - 1] : '' 2029 | endf 2030 | 2031 | fu! ctrlp#getmarkedlist() 2032 | retu exists('s:marked') ? values(s:marked) : [] 2033 | endf 2034 | 2035 | fu! ctrlp#exit() 2036 | cal s:PrtExit() 2037 | endf 2038 | 2039 | fu! ctrlp#prtclear() 2040 | cal s:PrtClear() 2041 | endf 2042 | 2043 | fu! ctrlp#switchtype(id) 2044 | cal s:ToggleType(a:id - s:itemtype) 2045 | endf 2046 | 2047 | fu! ctrlp#nosy() 2048 | retu !( has('syntax') && exists('g:syntax_on') ) 2049 | endf 2050 | 2051 | fu! ctrlp#hicheck(grp, defgrp) 2052 | if !hlexists(a:grp) 2053 | exe 'hi link' a:grp a:defgrp 2054 | en 2055 | endf 2056 | 2057 | fu! ctrlp#call(func, ...) 2058 | retu call(a:func, a:000) 2059 | endf 2060 | "}}}1 2061 | " * Initialization {{{1 2062 | fu! ctrlp#setlines(...) 2063 | if a:0 | let s:itemtype = a:1 | en 2064 | cal s:modevar() 2065 | let types = ['ctrlp#files()', 'ctrlp#buffers()', 'ctrlp#mrufiles#list()'] 2066 | if !empty(g:ctrlp_ext_vars) 2067 | cal map(copy(g:ctrlp_ext_vars), 'add(types, v:val["init"])') 2068 | en 2069 | let g:ctrlp_lines = eval(types[s:itemtype]) 2070 | endf 2071 | 2072 | fu! ctrlp#init(type, ...) 2073 | if exists('s:init') || s:iscmdwin() | retu | en 2074 | let [s:ermsg, v:errmsg] = [v:errmsg, ''] 2075 | let [s:matches, s:init] = [1, 1] 2076 | cal s:Reset(a:0 ? a:1 : {}) 2077 | noa cal s:Open() 2078 | cal s:SetWD(a:0 ? a:1 : {}) 2079 | cal s:MapNorms() 2080 | cal s:MapSpecs() 2081 | cal ctrlp#syntax() 2082 | cal ctrlp#setlines(s:settype(a:type)) 2083 | cal s:SetDefTxt() 2084 | cal s:BuildPrompt(1) 2085 | if s:keyloop | cal s:KeyLoop() | en 2086 | endf 2087 | " - Autocmds {{{1 2088 | if has('autocmd') 2089 | aug CtrlPAug 2090 | au! 2091 | au BufEnter ControlP cal s:checkbuf() 2092 | au BufLeave ControlP noa cal s:Close() 2093 | au VimLeavePre * cal s:leavepre() 2094 | aug END 2095 | en 2096 | 2097 | fu! s:autocmds() 2098 | if !has('autocmd') | retu | en 2099 | if exists('#CtrlPLazy') 2100 | au! CtrlPLazy 2101 | en 2102 | if s:lazy 2103 | aug CtrlPLazy 2104 | au! 2105 | au CursorHold ControlP cal s:ForceUpdate() 2106 | aug END 2107 | en 2108 | endf 2109 | "}}} 2110 | 2111 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 2112 | --------------------------------------------------------------------------------