ctrlp.vim 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708
  1. " =============================================================================
  2. " File: autoload/ctrlp.vim
  3. " Description: Fuzzy file, buffer, mru and tag finder.
  4. " Author: Kien Nguyen <github.com/kien>
  5. " Version: 1.7.5
  6. " =============================================================================
  7. " * Static variables {{{1
  8. fu! s:opts()
  9. " Options
  10. let hst = exists('+hi') ? &hi : 20
  11. let [pref, opts] = ['g:ctrlp_', {
  12. \ 'arg_map': ['s:argmap', 0],
  13. \ 'buffer_func': ['s:buffunc', {}],
  14. \ 'by_filename': ['s:byfname', 0],
  15. \ 'clear_cache_on_exit': ['s:clrex', 1],
  16. \ 'custom_ignore': ['s:usrign', ''],
  17. \ 'default_input': ['s:deftxt', 0],
  18. \ 'dont_split': ['s:nosplit', 'netrw'],
  19. \ 'dotfiles': ['s:dotfiles', 1],
  20. \ 'extensions': ['s:extensions', []],
  21. \ 'follow_symlinks': ['s:folsym', 0],
  22. \ 'highlight_match': ['s:mathi', [1, 'CtrlPMatch']],
  23. \ 'jump_to_buffer': ['s:jmptobuf', 2],
  24. \ 'lazy_update': ['s:lazy', 0],
  25. \ 'match_func': ['s:matcher', {}],
  26. \ 'match_window_bottom': ['s:mwbottom', 1],
  27. \ 'match_window_reversed': ['s:mwreverse', 1],
  28. \ 'max_depth': ['s:maxdepth', 40],
  29. \ 'max_files': ['s:maxfiles', 10000],
  30. \ 'max_height': ['s:mxheight', 10],
  31. \ 'max_history': ['s:maxhst', hst],
  32. \ 'mruf_default_order': ['s:mrudef', 0],
  33. \ 'open_multi': ['s:opmul', '1v'],
  34. \ 'open_new_file': ['s:newfop', 'v'],
  35. \ 'prompt_mappings': ['s:urprtmaps', 0],
  36. \ 'regexp_search': ['s:regexp', 0],
  37. \ 'root_markers': ['s:rmarkers', []],
  38. \ 'split_window': ['s:splitwin', 0],
  39. \ 'status_func': ['s:status', {}],
  40. \ 'use_caching': ['s:caching', 1],
  41. \ 'use_migemo': ['s:migemo', 0],
  42. \ 'user_command': ['s:usrcmd', ''],
  43. \ 'working_path_mode': ['s:pathmode', 2],
  44. \ }]
  45. for [ke, va] in items(opts)
  46. let {va[0]} = exists(pref.ke) ? {pref.ke} : va[1]
  47. endfo
  48. unl va
  49. let new_opts = {
  50. \ 'open_multiple_files': 's:opmul',
  51. \ 'regexp': 's:regexp',
  52. \ 'reuse_window': 's:nosplit',
  53. \ 'switch_buffer': 's:jmptobuf',
  54. \ }
  55. for [ke, va] in items(new_opts)
  56. let {va} = {exists(pref.ke) ? pref.ke : va}
  57. endfo
  58. if !exists('g:ctrlp_newcache') | let g:ctrlp_newcache = 0 | en
  59. let s:maxdepth = min([s:maxdepth, 100])
  60. let s:mxheight = max([s:mxheight, 1])
  61. let s:glob = s:dotfiles ? '.*\|*' : '*'
  62. let s:igntype = empty(s:usrign) ? -1 : type(s:usrign)
  63. " Extensions
  64. for each in s:extensions
  65. exe 'ru autoload/ctrlp/'.each.'.vim'
  66. endfo
  67. " Keymaps
  68. let [s:lcmap, s:prtmaps] = ['nn <buffer> <silent>', {
  69. \ 'PrtBS()': ['<bs>', '<c-]>'],
  70. \ 'PrtDelete()': ['<del>'],
  71. \ 'PrtDeleteWord()': ['<c-w>'],
  72. \ 'PrtClear()': ['<c-u>'],
  73. \ 'PrtSelectMove("j")': ['<c-j>', '<down>'],
  74. \ 'PrtSelectMove("k")': ['<c-k>', '<up>'],
  75. \ 'PrtSelectMove("t")': ['<Home>', '<kHome>'],
  76. \ 'PrtSelectMove("b")': ['<End>', '<kEnd>'],
  77. \ 'PrtSelectMove("u")': ['<PageUp>', '<kPageUp>'],
  78. \ 'PrtSelectMove("d")': ['<PageDown>', '<kPageDown>'],
  79. \ 'PrtHistory(-1)': ['<c-n>'],
  80. \ 'PrtHistory(1)': ['<c-p>'],
  81. \ 'AcceptSelection("e")': ['<cr>', '<2-LeftMouse>'],
  82. \ 'AcceptSelection("h")': ['<c-x>', '<c-cr>', '<c-s>'],
  83. \ 'AcceptSelection("t")': ['<c-t>'],
  84. \ 'AcceptSelection("v")': ['<c-v>', '<RightMouse>'],
  85. \ 'ToggleFocus()': ['<s-tab>'],
  86. \ 'ToggleRegex()': ['<c-r>'],
  87. \ 'ToggleByFname()': ['<c-d>'],
  88. \ 'ToggleType(1)': ['<c-f>', '<c-up>'],
  89. \ 'ToggleType(-1)': ['<c-b>', '<c-down>'],
  90. \ 'PrtExpandDir()': ['<tab>'],
  91. \ 'PrtInsert("w")': ['<F2>', '<insert>'],
  92. \ 'PrtInsert("s")': ['<F3>'],
  93. \ 'PrtInsert("v")': ['<F4>'],
  94. \ 'PrtInsert("+")': ['<F6>', '<MiddleMouse>'],
  95. \ 'PrtCurStart()': ['<c-a>'],
  96. \ 'PrtCurEnd()': ['<c-e>'],
  97. \ 'PrtCurLeft()': ['<c-h>', '<left>', '<c-^>'],
  98. \ 'PrtCurRight()': ['<c-l>', '<right>'],
  99. \ 'PrtClearCache()': ['<F5>'],
  100. \ 'PrtDeleteEnt()': ['<F7>'],
  101. \ 'CreateNewFile()': ['<c-y>'],
  102. \ 'MarkToOpen()': ['<c-z>'],
  103. \ 'OpenMulti()': ['<c-o>'],
  104. \ 'PrtExit()': ['<esc>', '<c-c>', '<c-g>'],
  105. \ }]
  106. if !has('gui_running') && ( has('win32') || has('win64') )
  107. cal add(s:prtmaps['PrtBS()'], remove(s:prtmaps['PrtCurLeft()'], 0))
  108. en
  109. if type(s:urprtmaps) == 4
  110. cal extend(s:prtmaps, s:urprtmaps)
  111. en
  112. " Global options
  113. let s:glbs = { 'magic': 1, 'to': 1, 'tm': 0, 'sb': 1, 'hls': 0, 'im': 0,
  114. \ 'report': 9999, 'sc': 0, 'ss': 0, 'siso': 0, 'mfd': 200, 'mouse': 'n',
  115. \ 'gcr': 'a:blinkon0', 'ic': 1, 'scs': 1, 'lmap': '', 'mousef': 0,
  116. \ 'imd': 1 }
  117. if s:lazy
  118. cal extend(s:glbs, { 'ut': ( s:lazy > 1 ? s:lazy : 250 ) })
  119. en
  120. endf
  121. cal s:opts()
  122. let s:lash = ctrlp#utils#lash()
  123. " Limiters
  124. let [s:compare_lim, s:nocache_lim] = [3000, 4000]
  125. " Regexp
  126. let s:fpats = {
  127. \ '^\(\\|\)\|\(\\|\)$': '\\|',
  128. \ '^\\\(zs\|ze\|<\|>\)': '^\\\(zs\|ze\|<\|>\)',
  129. \ '^\S\*$': '\*',
  130. \ '^\S\\?$': '\\?',
  131. \ }
  132. " Mappings
  133. let s:prtunmaps = [
  134. \ 'PrtBS()',
  135. \ 'PrtDelete()',
  136. \ 'PrtDeleteWord()',
  137. \ 'PrtClear()',
  138. \ 'PrtCurStart()',
  139. \ 'PrtCurEnd()',
  140. \ 'PrtCurLeft()',
  141. \ 'PrtCurRight()',
  142. \ 'PrtHistory(-1)',
  143. \ 'PrtHistory(1)',
  144. \ 'PrtInsert("w")',
  145. \ 'PrtInsert("s")',
  146. \ 'PrtInsert("v")',
  147. \ 'PrtInsert("+")',
  148. \ ]
  149. " Keypad
  150. let s:kprange = {
  151. \ 'Plus': '+',
  152. \ 'Minus': '-',
  153. \ 'Divide': '/',
  154. \ 'Multiply': '*',
  155. \ 'Point': '.',
  156. \ }
  157. " Highlight groups
  158. let s:hlgrps = {
  159. \ 'NoEntries': 'Error',
  160. \ 'Mode1': 'Character',
  161. \ 'Mode2': 'LineNr',
  162. \ 'Stats': 'Function',
  163. \ 'Match': 'Identifier',
  164. \ 'PrtBase': 'Comment',
  165. \ 'PrtText': 'Normal',
  166. \ 'PrtCursor': 'Constant',
  167. \ }
  168. " * Open & Close {{{1
  169. fu! s:Open()
  170. cal s:log(1)
  171. cal s:getenv()
  172. cal s:execextvar('enter')
  173. sil! exe 'noa keepa' ( s:mwbottom ? 'bo' : 'to' ) '1new ControlP'
  174. cal s:buffunc(1)
  175. let [s:bufnr, s:prompt, s:winw] = [bufnr('%'), ['', '', ''], winwidth(0)]
  176. abc <buffer>
  177. if !exists('s:hstry')
  178. let hst = filereadable(s:gethistloc()[1]) ? s:gethistdata() : ['']
  179. let s:hstry = empty(hst) || !s:maxhst ? [''] : hst
  180. en
  181. for [ke, va] in items(s:glbs) | if exists('+'.ke)
  182. sil! exe 'let s:glb_'.ke.' = &'.ke.' | let &'.ke.' = '.string(va)
  183. en | endfo
  184. if s:opmul != '0' && has('signs')
  185. sign define ctrlpmark text=+> texthl=Search
  186. en
  187. cal s:setupblank()
  188. endf
  189. fu! s:Close()
  190. cal s:buffunc(0)
  191. try | noa bun!
  192. cat | noa clo! | endt
  193. cal s:unmarksigns()
  194. for key in keys(s:glbs) | if exists('+'.key)
  195. sil! exe 'let &'.key.' = s:glb_'.key
  196. en | endfo
  197. if exists('s:glb_acd') | let &acd = s:glb_acd | en
  198. let g:ctrlp_lines = []
  199. if s:winres[1] >= &lines && s:winres[2] == winnr('$')
  200. exe s:winres[0]
  201. en
  202. unl! s:focus s:hisidx s:hstgot s:marked s:statypes s:cline s:init s:savestr
  203. \ s:mrbs
  204. cal ctrlp#recordhist()
  205. cal s:execextvar('exit')
  206. cal s:log(0)
  207. ec
  208. endf
  209. " * Clear caches {{{1
  210. fu! ctrlp#clr(...)
  211. let g:ctrlp_new{ a:0 ? a:1 : 'cache' } = 1
  212. endf
  213. fu! ctrlp#clra()
  214. let cache_dir = ctrlp#utils#cachedir()
  215. if isdirectory(cache_dir)
  216. let cache_files = split(s:glbpath(cache_dir, '**', 1), "\n")
  217. let eval = '!isdirectory(v:val) && fnamemodify(v:val, ":t") !~'
  218. \ . ' ''\v^<cache>[.a-z]+$|\.log$'''
  219. sil! cal map(filter(cache_files, eval), 'delete(v:val)')
  220. en
  221. cal ctrlp#clr()
  222. endf
  223. fu! ctrlp#reset()
  224. cal s:opts()
  225. cal s:autocmds()
  226. cal ctrlp#utils#opts()
  227. cal ctrlp#mrufiles#opts()
  228. cal s:execextvar('opts')
  229. endf
  230. " * Files {{{1
  231. fu! ctrlp#files()
  232. let cafile = ctrlp#utils#cachefile()
  233. if g:ctrlp_newcache || !filereadable(cafile) || !s:caching
  234. let [lscmd, s:initcwd, g:ctrlp_allfiles] = [s:lsCmd(), s:dyncwd, []]
  235. " Get the list of files
  236. if empty(lscmd)
  237. cal s:GlobPath(s:dyncwd, 0)
  238. el
  239. sil! cal ctrlp#progress('Indexing...')
  240. try | cal s:UserCmd(lscmd)
  241. cat | retu [] | endt
  242. en
  243. " Remove base directory
  244. cal ctrlp#rmbasedir(g:ctrlp_allfiles)
  245. if len(g:ctrlp_allfiles) <= s:compare_lim
  246. cal sort(g:ctrlp_allfiles, 'ctrlp#complen')
  247. en
  248. cal s:writecache(cafile)
  249. el
  250. if !( exists('s:initcwd') && s:initcwd == s:dyncwd )
  251. let s:initcwd = s:dyncwd
  252. let g:ctrlp_allfiles = ctrlp#utils#readfile(cafile)
  253. en
  254. en
  255. retu g:ctrlp_allfiles
  256. endf
  257. fu! s:GlobPath(dirs, depth)
  258. let entries = split(globpath(a:dirs, s:glob), "\n")
  259. let [dnf, depth] = [ctrlp#dirnfile(entries), a:depth + 1]
  260. cal extend(g:ctrlp_allfiles, dnf[1])
  261. if !empty(dnf[0]) && !s:maxf(len(g:ctrlp_allfiles)) && depth <= s:maxdepth
  262. sil! cal ctrlp#progress(len(g:ctrlp_allfiles))
  263. cal s:GlobPath(join(dnf[0], ','), depth)
  264. en
  265. endf
  266. fu! s:UserCmd(lscmd)
  267. let path = s:dyncwd
  268. if exists('+ssl') && &ssl
  269. let [ssl, &ssl, path] = [&ssl, 0, tr(path, '/', '\')]
  270. en
  271. let path = exists('*shellescape') ? shellescape(path) : path
  272. let g:ctrlp_allfiles = split(system(printf(a:lscmd, path)), "\n")
  273. if exists('+ssl') && exists('ssl')
  274. let &ssl = ssl
  275. cal map(g:ctrlp_allfiles, 'tr(v:val, "\\", "/")')
  276. en
  277. if exists('s:vcscmd') && s:vcscmd
  278. cal map(g:ctrlp_allfiles, 'tr(v:val, "/", "\\")')
  279. en
  280. endf
  281. fu! s:lsCmd()
  282. let cmd = s:usrcmd
  283. if type(cmd) == 1
  284. retu cmd
  285. elsei type(cmd) == 3 && len(cmd) >= 2 && cmd[:1] != ['', '']
  286. " Find a repo root
  287. cal s:findroot(s:dyncwd, cmd[0], 0, 1)
  288. if !exists('s:vcsroot')
  289. " Try the secondary_command
  290. retu len(cmd) == 3 ? cmd[2] : ''
  291. en
  292. unl s:vcsroot
  293. let s:vcscmd = s:lash == '\' ? 1 : 0
  294. retu cmd[1]
  295. elsei type(cmd) == 4 && has_key(cmd, 'types')
  296. for key in sort(keys(cmd['types']), 's:compval')
  297. cal s:findroot(s:dyncwd, cmd['types'][key][0], 0, 1)
  298. if exists('s:vcsroot') | brea | en
  299. endfo
  300. if !exists('s:vcsroot')
  301. retu has_key(cmd, 'fallback') ? cmd['fallback'] : ''
  302. en
  303. unl s:vcsroot
  304. let s:vcscmd = s:lash == '\' ? 1 : 0
  305. retu cmd['types'][key][1]
  306. en
  307. endf
  308. " - Buffers {{{1
  309. fu! ctrlp#buffers(...)
  310. let ids = filter(range(1, bufnr('$')), 'empty(getbufvar(v:val, "&bt"))'
  311. \ .' && getbufvar(v:val, "&bl") && strlen(bufname(v:val))')
  312. retu a:0 && a:1 == 'id' ? ids : map(ids, 'fnamemodify(bufname(v:val), ":.")')
  313. endf
  314. " * MatchedItems() {{{1
  315. fu! s:MatchIt(items, pat, limit, exc)
  316. let [lines, id] = [[], 0]
  317. for item in a:items
  318. let id += 1
  319. try | if !( s:ispath && item == a:exc ) && call(s:mfunc, [item, a:pat]) >= 0
  320. cal add(lines, item)
  321. en | cat | brea | endt
  322. if a:limit > 0 && len(lines) >= a:limit | brea | en
  323. endfo
  324. let s:mdata = [s:dyncwd, s:itemtype, s:regexp, s:sublist(a:items, id, -1)]
  325. retu lines
  326. endf
  327. fu! s:MatchedItems(items, pat, limit)
  328. let exc = exists('s:crfilerel') ? s:crfilerel : ''
  329. let items = s:narrowable() ? s:matched + s:mdata[3] : a:items
  330. if s:matcher != {}
  331. let argms = [items, a:pat, a:limit, s:mmode(), s:ispath, exc, s:regexp]
  332. let lines = call(s:matcher['match'], argms)
  333. el
  334. let lines = s:MatchIt(items, a:pat, a:limit, exc)
  335. en
  336. let s:matches = len(lines)
  337. retu lines
  338. endf
  339. fu! s:SplitPattern(str)
  340. let str = a:str
  341. if s:migemo && s:regexp && len(str) > 0 && executable('cmigemo')
  342. let str = s:migemo(str)
  343. en
  344. let s:savestr = str
  345. if s:regexp
  346. let pat = s:regexfilter(str)
  347. el
  348. let lst = split(str, '\zs')
  349. if exists('+ssl') && !&ssl
  350. cal map(lst, 'escape(v:val, ''\'')')
  351. en
  352. for each in ['^', '$', '.']
  353. cal map(lst, 'escape(v:val, each)')
  354. endfo
  355. en
  356. if exists('lst')
  357. let pat = ''
  358. if !empty(lst)
  359. let pat = lst[0]
  360. for item in range(1, len(lst) - 1)
  361. let pat .= '[^'.lst[item - 1].']\{-}'.lst[item]
  362. endfo
  363. en
  364. en
  365. retu escape(pat, '~')
  366. endf
  367. " * BuildPrompt() {{{1
  368. fu! s:Render(lines, pat)
  369. let [&ma, lines, s:height] = [1, a:lines, min([len(a:lines), s:winh])]
  370. " Setup the match window
  371. sil! exe '%d _ | res' s:height
  372. " Print the new items
  373. if empty(lines)
  374. let [s:matched, s:lines] = [[], []]
  375. cal setline(1, ' == NO ENTRIES ==')
  376. setl noma nocul
  377. cal s:unmarksigns()
  378. if s:dohighlight() | cal clearmatches() | en
  379. retu
  380. en
  381. " Sorting
  382. if s:dosort()
  383. let s:compat = a:pat
  384. cal sort(lines, 's:mixedsort')
  385. unl s:compat
  386. en
  387. let s:matched = copy(lines)
  388. if s:mwreverse | cal reverse(lines) | en
  389. let s:lines = copy(lines)
  390. cal map(lines, 's:formatline(v:val)')
  391. cal setline(1, lines)
  392. setl noma cul
  393. exe 'keepj norm!' ( s:mwreverse ? 'G' : 'gg' ).'1|'
  394. cal s:unmarksigns()
  395. cal s:remarksigns()
  396. if exists('s:cline') && s:nolim != 1
  397. cal cursor(s:cline, 1)
  398. en
  399. " Highlighting
  400. if s:dohighlight()
  401. cal s:highlight(a:pat, s:mathi[1])
  402. en
  403. endf
  404. fu! s:Update(str)
  405. " Get the previous string if existed
  406. let oldstr = exists('s:savestr') ? s:savestr : ''
  407. " Get the new string sans tail
  408. let str = s:sanstail(a:str)
  409. " Stop if the string's unchanged
  410. if str == oldstr && !empty(str) && !exists('s:force') | retu | en
  411. let pat = s:matcher == {} ? s:SplitPattern(str) : str
  412. let lines = s:nolim == 1 && empty(str) ? copy(g:ctrlp_lines)
  413. \ : s:MatchedItems(g:ctrlp_lines, pat, s:winh)
  414. cal s:Render(lines, pat)
  415. endf
  416. fu! s:ForceUpdate()
  417. let [estr, prt] = ['"\', copy(s:prompt)]
  418. cal map(prt, 'escape(v:val, estr)')
  419. sil! cal s:Update(join(prt, ''))
  420. endf
  421. fu! s:BuildPrompt(upd, ...)
  422. let base = ( s:regexp ? 'r' : '>' ).( s:byfname ? 'd' : '>' ).'> '
  423. let [estr, prt] = ['"\', copy(s:prompt)]
  424. cal map(prt, 'escape(v:val, estr)')
  425. let str = join(prt, '')
  426. let lazy = empty(str) || exists('s:force') || !has('autocmd') ? 0 : s:lazy
  427. if a:upd && !lazy && ( s:matches || s:regexp
  428. \ || match(str, '\(\\\(<\|>\)\|[*|]\)\|\(\\\:\([^:]\|\\:\)*$\)') >= 0 )
  429. sil! cal s:Update(str)
  430. en
  431. sil! cal ctrlp#statusline()
  432. " Toggling
  433. let [hiactive, hicursor, base] = a:0 && !a:1
  434. \ ? ['CtrlPPrtBase', 'CtrlPPrtBase', tr(base, '>', '-')]
  435. \ : ['CtrlPPrtText', 'CtrlPPrtCursor', base]
  436. let hibase = 'CtrlPPrtBase'
  437. " Build it
  438. redr
  439. exe 'echoh' hibase '| echon "'.base.'"
  440. \ | echoh' hiactive '| echon "'.prt[0].'"
  441. \ | echoh' hicursor '| echon "'.prt[1].'"
  442. \ | echoh' hiactive '| echon "'.prt[2].'" | echoh None'
  443. " Append the cursor at the end
  444. if empty(prt[1]) && !( a:0 && !a:1 )
  445. exe 'echoh' hibase '| echon "_" | echoh None'
  446. en
  447. endf
  448. " - SetDefTxt() {{{1
  449. fu! s:SetDefTxt()
  450. if s:deftxt == '0' || !s:ispath | retu | en
  451. let txt = s:deftxt
  452. if !type(txt)
  453. let txt = txt && !stridx(s:crfpath, s:dyncwd)
  454. \ ? ctrlp#rmbasedir([s:crfpath])[0] : ''
  455. let txt = txt != '' ? txt.s:lash(s:crfpath) : ''
  456. en
  457. let s:prompt[0] = txt
  458. endf
  459. " ** Prt Actions {{{1
  460. " Editing {{{2
  461. fu! s:PrtClear()
  462. unl! s:hstgot
  463. let [s:prompt, s:matches] = [['', '', ''], 1]
  464. cal s:BuildPrompt(1)
  465. endf
  466. fu! s:PrtAdd(char)
  467. unl! s:hstgot
  468. let s:act_add = 1
  469. let s:prompt[0] .= a:char
  470. cal s:BuildPrompt(1)
  471. unl s:act_add
  472. endf
  473. fu! s:PrtBS()
  474. unl! s:hstgot
  475. let [s:prompt[0], s:matches] = [substitute(s:prompt[0], '.$', '', ''), 1]
  476. cal s:BuildPrompt(1)
  477. endf
  478. fu! s:PrtDelete()
  479. unl! s:hstgot
  480. let [prt, s:matches] = [s:prompt, 1]
  481. let prt[1] = matchstr(prt[2], '^.')
  482. let prt[2] = substitute(prt[2], '^.', '', '')
  483. cal s:BuildPrompt(1)
  484. endf
  485. fu! s:PrtDeleteWord()
  486. unl! s:hstgot
  487. let [str, s:matches] = [s:prompt[0], 1]
  488. let str = match(str, '\W\w\+$') >= 0 ? matchstr(str, '^.\+\W\ze\w\+$')
  489. \ : match(str, '\w\W\+$') >= 0 ? matchstr(str, '^.\+\w\ze\W\+$')
  490. \ : match(str, '\s\+$') >= 0 ? matchstr(str, '^.*[^ \t]\+\ze\s\+$')
  491. \ : match(str, ' ') <= 0 ? '' : str
  492. let s:prompt[0] = str
  493. cal s:BuildPrompt(1)
  494. endf
  495. fu! s:PrtInsert(type)
  496. unl! s:hstgot
  497. let s:act_add = 1
  498. let s:prompt[0] .= a:type == 'w' ? s:crword
  499. \ : a:type == 's' ? getreg('/')
  500. \ : a:type == 'v' ? s:crvisual
  501. \ : a:type == '+' ? substitute(getreg('+'), '\n', '\\n', 'g') : s:prompt[0]
  502. cal s:BuildPrompt(1)
  503. unl s:act_add
  504. endf
  505. fu! s:PrtExpandDir()
  506. let prt = s:prompt
  507. if prt[0] == '' | retu | en
  508. unl! s:hstgot
  509. let s:act_add = 1
  510. let [base, seed] = s:headntail(prt[0])
  511. let dirs = s:dircompl(base, seed)
  512. if len(dirs) == 1
  513. let prt[0] = dirs[0]
  514. elsei len(dirs) > 1
  515. let prt[0] .= s:findcommon(dirs, prt[0])
  516. en
  517. cal s:BuildPrompt(1)
  518. unl s:act_add
  519. endf
  520. " Movement {{{2
  521. fu! s:PrtCurLeft()
  522. let prt = s:prompt
  523. if !empty(prt[0])
  524. let s:prompt = [substitute(prt[0], '.$', '', ''), matchstr(prt[0], '.$'),
  525. \ prt[1] . prt[2]]
  526. en
  527. cal s:BuildPrompt(0)
  528. endf
  529. fu! s:PrtCurRight()
  530. let prt = s:prompt
  531. let s:prompt = [prt[0] . prt[1], matchstr(prt[2], '^.'),
  532. \ substitute(prt[2], '^.', '', '')]
  533. cal s:BuildPrompt(0)
  534. endf
  535. fu! s:PrtCurStart()
  536. let str = join(s:prompt, '')
  537. let s:prompt = ['', matchstr(str, '^.'), substitute(str, '^.', '', '')]
  538. cal s:BuildPrompt(0)
  539. endf
  540. fu! s:PrtCurEnd()
  541. let s:prompt = [join(s:prompt, ''), '', '']
  542. cal s:BuildPrompt(0)
  543. endf
  544. fu! s:PrtSelectMove(dir)
  545. let wht = winheight(0)
  546. let dirs = {'t': 'gg','b': 'G','j': 'j','k': 'k','u': wht.'k','d': wht.'j'}
  547. exe 'keepj norm!' dirs[a:dir]
  548. if s:nolim != 1 | let s:cline = line('.') | en
  549. if line('$') > winheight(0) | cal s:BuildPrompt(0, s:Focus()) | en
  550. endf
  551. fu! s:PrtSelectJump(char, ...)
  552. let lines = copy(s:lines)
  553. if a:0
  554. cal map(lines, 'split(v:val, ''[\/]\ze[^\/]\+$'')[-1]')
  555. en
  556. " Cycle through matches, use s:jmpchr to store last jump
  557. let chr = escape(a:char, '.~')
  558. if match(lines, '\c^'.chr) >= 0
  559. " If not exists or does but not for the same char
  560. let pos = match(lines, '\c^'.chr)
  561. if !exists('s:jmpchr') || ( exists('s:jmpchr') && s:jmpchr[0] != chr )
  562. let [jmpln, s:jmpchr] = [pos, [chr, pos]]
  563. elsei exists('s:jmpchr') && s:jmpchr[0] == chr
  564. " Start of lines
  565. if s:jmpchr[1] == -1 | let s:jmpchr[1] = pos | en
  566. let npos = match(lines, '\c^'.chr, s:jmpchr[1] + 1)
  567. let [jmpln, s:jmpchr] = [npos == -1 ? pos : npos, [chr, npos]]
  568. en
  569. keepj exe jmpln + 1
  570. if s:nolim != 1 | let s:cline = line('.') | en
  571. if line('$') > winheight(0) | cal s:BuildPrompt(0, s:Focus()) | en
  572. en
  573. endf
  574. " Misc {{{2
  575. fu! s:PrtClearCache()
  576. if s:itemtype == 1 | retu | en
  577. if s:itemtype == 0
  578. cal ctrlp#clr()
  579. elsei s:itemtype > 2
  580. cal ctrlp#clr(s:statypes[s:itemtype][1])
  581. en
  582. if s:itemtype == 2
  583. let g:ctrlp_lines = ctrlp#mrufiles#refresh()
  584. el
  585. cal ctrlp#setlines()
  586. en
  587. let s:force = 1
  588. cal s:BuildPrompt(1)
  589. unl s:force
  590. endf
  591. fu! s:PrtDeleteEnt()
  592. if s:itemtype == 2
  593. cal s:PrtDeleteMRU()
  594. elsei type(s:getextvar('wipe')) == 1
  595. cal s:delent(s:getextvar('wipe'))
  596. en
  597. endf
  598. fu! s:PrtDeleteMRU()
  599. if s:itemtype == 2
  600. cal s:delent('ctrlp#mrufiles#remove')
  601. en
  602. endf
  603. fu! s:PrtExit()
  604. if !has('autocmd') | cal s:Close() | en
  605. exe s:currwin.'winc w'
  606. endf
  607. fu! s:PrtHistory(...)
  608. if !s:maxhst | retu | en
  609. let [str, hst, s:matches] = [join(s:prompt, ''), s:hstry, 1]
  610. " Save to history if not saved before
  611. let [hst[0], hslen] = [exists('s:hstgot') ? hst[0] : str, len(hst)]
  612. let idx = exists('s:hisidx') ? s:hisidx + a:1 : a:1
  613. " Limit idx within 0 and hslen
  614. let idx = idx < 0 ? 0 : idx >= hslen ? hslen > 1 ? hslen - 1 : 0 : idx
  615. let s:prompt = [hst[idx], '', '']
  616. let [s:hisidx, s:hstgot, s:force] = [idx, 1, 1]
  617. cal s:BuildPrompt(1)
  618. unl s:force
  619. endf
  620. "}}}1
  621. " * MapKeys() {{{1
  622. fu! s:MapKeys(...)
  623. " Normal keys
  624. let pfunc = a:0 && !a:1 ? 'PrtSelectJump' : 'PrtAdd'
  625. let dojmp = s:byfname && a:0 && !a:1 ? ', 1' : ''
  626. let pcmd = "nn \<buffer> \<silent> \<k%s> :\<c-u>cal \<SID>%s(\"%s\"%s)\<cr>"
  627. let cmd = substitute(pcmd, 'k%s', 'char-%d', '')
  628. for each in range(32, 126)
  629. exe printf(cmd, each, pfunc, escape(nr2char(each), '"|\'), dojmp)
  630. endfo
  631. for each in range(0, 9)
  632. exe printf(pcmd, each, pfunc, each, dojmp)
  633. endfo
  634. for [ke, va] in items(s:kprange)
  635. exe printf(pcmd, ke, pfunc, va, dojmp)
  636. endfo
  637. " Special keys
  638. if a:0 < 2
  639. cal call('s:MapSpecs', a:0 && !a:1 ? [1] : [])
  640. en
  641. endf
  642. fu! s:MapSpecs(...)
  643. " Correct arrow keys in terminal
  644. if ( has('termresponse') && match(v:termresponse, "\<ESC>") >= 0 )
  645. \ || &term =~? '\vxterm|<k?vt|gnome|screen|linux'
  646. for each in ['\A <up>','\B <down>','\C <right>','\D <left>']
  647. exe s:lcmap.' <esc>['.each
  648. endfo
  649. en
  650. if a:0
  651. for ke in s:prtunmaps | for kp in s:prtmaps[ke]
  652. exe s:lcmap kp '<Nop>'
  653. endfo | endfo
  654. el
  655. for [ke, va] in items(s:prtmaps) | for kp in va
  656. exe s:lcmap kp ':<c-u>cal <SID>'.ke.'<cr>'
  657. endfo | endfo
  658. en
  659. endf
  660. " * Toggling {{{1
  661. fu! s:Focus()
  662. retu !exists('s:focus') ? 1 : s:focus
  663. endf
  664. fu! s:ToggleFocus()
  665. let s:focus = !exists('s:focus') || s:focus ? 0 : 1
  666. cal s:MapKeys(s:focus)
  667. cal s:BuildPrompt(0, s:focus)
  668. endf
  669. fu! s:ToggleRegex()
  670. let s:regexp = s:regexp ? 0 : 1
  671. cal s:PrtSwitcher()
  672. endf
  673. fu! s:ToggleByFname()
  674. if s:ispath
  675. let s:byfname = s:byfname ? 0 : 1
  676. let s:mfunc = s:mfunc()
  677. cal s:MapKeys(s:Focus(), 1)
  678. cal s:PrtSwitcher()
  679. en
  680. endf
  681. fu! s:ToggleType(dir)
  682. let max = len(g:ctrlp_ext_vars) + 2
  683. let next = s:walker(max, s:itemtype, a:dir)
  684. cal ctrlp#syntax()
  685. cal ctrlp#setlines(next)
  686. cal s:PrtSwitcher()
  687. endf
  688. fu! s:PrtSwitcher()
  689. let [s:force, s:matches] = [1, 1]
  690. cal s:BuildPrompt(1, s:Focus())
  691. unl s:force
  692. endf
  693. " - SetWD() {{{1
  694. fu! s:SetWD(...)
  695. let pathmode = s:wpmode
  696. let [s:crfilerel, s:dyncwd] = [fnamemodify(s:crfile, ':.'), getcwd()]
  697. if a:0 && strlen(a:1) | if type(a:1)
  698. cal ctrlp#setdir(a:1) | retu
  699. el
  700. let pathmode = a:1
  701. en | en
  702. if a:0 < 2
  703. if match(s:crfile, '\v^<.+>://') >= 0 || !pathmode | retu | en
  704. if exists('+acd') | let [s:glb_acd, &acd] = [&acd, 0] | en
  705. cal ctrlp#setdir(s:crfpath)
  706. en
  707. if pathmode == 1 | retu | en
  708. let markers = ['root.dir', '.git/', '.hg/', '.svn/', '.bzr/', '_darcs/']
  709. if type(s:rmarkers) == 3 && !empty(s:rmarkers)
  710. cal extend(markers, s:rmarkers, 0)
  711. en
  712. for marker in markers
  713. cal s:findroot(s:dyncwd, marker, 0, 0)
  714. if exists('s:foundroot') | brea | en
  715. endfo
  716. unl! s:foundroot
  717. endf
  718. " * AcceptSelection() {{{1
  719. fu! ctrlp#acceptfile(mode, line, ...)
  720. let [md, filpath] = [a:mode, fnamemodify(a:line, ':p')]
  721. cal s:PrtExit()
  722. let [bufnr, tail] = [bufnr('^'.filpath.'$'), s:tail()]
  723. let j2l = a:0 ? a:1 : str2nr(matchstr(tail, '^ +\D*\zs\d\+\ze\D*'))
  724. if s:jmptobuf && bufnr > 0 && md =~ 'e\|t'
  725. let [jmpb, bufwinnr] = [1, bufwinnr(bufnr)]
  726. let buftab = s:jmptobuf > 1 ? s:buftab(bufnr, md) : [0, 0]
  727. en
  728. " Switch to existing buffer or open new one
  729. if exists('jmpb') && bufwinnr > 0 && md != 't'
  730. exe bufwinnr.'winc w'
  731. if j2l | cal ctrlp#j2l(j2l) | en
  732. elsei exists('jmpb') && buftab[0]
  733. exe 'tabn' buftab[0]
  734. exe buftab[1].'winc w'
  735. if j2l | cal ctrlp#j2l(j2l) | en
  736. el
  737. " Determine the command to use
  738. let useb = bufnr > 0 && buflisted(bufnr) && empty(tail)
  739. let cmd =
  740. \ md == 't' || s:splitwin == 1 ? ( useb ? 'tab sb' : 'tabe' ) :
  741. \ md == 'h' || s:splitwin == 2 ? ( useb ? 'sb' : 'new' ) :
  742. \ md == 'v' || s:splitwin == 3 ? ( useb ? 'vert sb' : 'vne' ) :
  743. \ call('ctrlp#normcmd', useb ? ['b', 'bo vert sb'] : ['e'])
  744. " Reset &switchbuf option
  745. let [swb, &swb] = [&swb, '']
  746. " Open new window/buffer
  747. let args = [cmd, useb ? bufnr : filpath, a:0 ? ' +'.a:1 : tail, useb, j2l]
  748. cal call('s:openfile', args)
  749. let &swb = swb
  750. en
  751. endf
  752. fu! s:SpecInputs(str)
  753. let spi = !s:itemtype || s:getextvar('specinput') > 0
  754. if a:str == '..' && spi
  755. cal s:parentdir(s:dyncwd)
  756. cal ctrlp#setlines()
  757. cal s:PrtClear()
  758. retu 1
  759. elsei a:str =~ '^[\/]$' && spi
  760. cal s:SetWD(2, 0)
  761. cal ctrlp#setlines()
  762. cal s:PrtClear()
  763. retu 1
  764. elsei a:str == '?'
  765. cal s:PrtExit()
  766. let hlpwin = &columns > 159 ? '| vert res 80' : ''
  767. sil! exe 'bo vert h ctrlp-mappings' hlpwin '| norm! 0'
  768. retu 1
  769. en
  770. retu 0
  771. endf
  772. fu! s:AcceptSelection(mode)
  773. let str = join(s:prompt, '')
  774. if a:mode == 'e' | if s:SpecInputs(str) | retu | en | en
  775. " Get the selected line
  776. let line = !empty(s:lines) ? s:lines[line('.') - 1] : ''
  777. if a:mode != 'e' && s:itemtype < 3 && line == ''
  778. \ && str !~ '\v^(\.\.|/|\\|\?)$'
  779. cal s:CreateNewFile(a:mode) | retu
  780. en
  781. if empty(line) | retu | en
  782. " Do something with it
  783. let actfunc = s:itemtype < 3 ? 'ctrlp#acceptfile' : s:getextvar('accept')
  784. cal call(actfunc, [a:mode, line])
  785. endf
  786. " - CreateNewFile() {{{1
  787. fu! s:CreateNewFile(...)
  788. let [md, str] = ['', join(s:prompt, '')]
  789. if empty(str) | retu | en
  790. if s:argmap && !a:0
  791. " Get the extra argument
  792. let md = s:argmaps(md, 1)
  793. if md == 'cancel' | retu | en
  794. en
  795. let str = s:sanstail(str)
  796. let [base, fname] = s:headntail(str)
  797. if fname =~ '^[\/]$' | retu | en
  798. if exists('s:marked') && len(s:marked)
  799. " Use the first marked file's path
  800. let path = fnamemodify(values(s:marked)[0], ':p:h')
  801. let base = path.s:lash(path).base
  802. let str = fnamemodify(base.s:lash.fname, ':.')
  803. en
  804. if base != '' | if isdirectory(ctrlp#utils#mkdir(base))
  805. let optyp = str | en | el | let optyp = fname
  806. en
  807. if !exists('optyp') | retu | en
  808. let [filpath, tail] = [fnamemodify(optyp, ':p'), s:tail()]
  809. if !stridx(filpath, s:dyncwd) | cal s:insertcache(str) | en
  810. cal s:PrtExit()
  811. let cmd = md == 'r' ? ctrlp#normcmd('e') :
  812. \ s:newfop =~ '1\|t' || ( a:0 && a:1 == 't' ) || md == 't' ? 'tabe' :
  813. \ s:newfop =~ '2\|h' || ( a:0 && a:1 == 'h' ) || md == 'h' ? 'new' :
  814. \ s:newfop =~ '3\|v' || ( a:0 && a:1 == 'v' ) || md == 'v' ? 'vne' :
  815. \ ctrlp#normcmd('e')
  816. cal s:openfile(cmd, filpath, tail)
  817. endf
  818. " * OpenMulti() {{{1
  819. fu! s:MarkToOpen()
  820. if s:bufnr <= 0 || s:opmul == '0'
  821. \ || ( s:itemtype > 2 && s:getextvar('opmul') != 1 )
  822. retu
  823. en
  824. let line = !empty(s:lines) ? s:lines[line('.') - 1] : ''
  825. if empty(line) | retu | en
  826. let filpath = s:ispath ? fnamemodify(line, ':p') : line
  827. if exists('s:marked') && s:dictindex(s:marked, filpath) > 0
  828. " Unmark and remove the file from s:marked
  829. let key = s:dictindex(s:marked, filpath)
  830. cal remove(s:marked, key)
  831. if empty(s:marked) | unl s:marked | en
  832. if has('signs')
  833. exe 'sign unplace' key 'buffer='.s:bufnr
  834. en
  835. el
  836. " Add to s:marked and place a new sign
  837. if exists('s:marked')
  838. let vac = s:vacantdict(s:marked)
  839. let key = empty(vac) ? len(s:marked) + 1 : vac[0]
  840. let s:marked = extend(s:marked, { key : filpath })
  841. el
  842. let [key, s:marked] = [1, { 1 : filpath }]
  843. en
  844. if has('signs')
  845. exe 'sign place' key 'line='.line('.').' name=ctrlpmark buffer='.s:bufnr
  846. en
  847. en
  848. sil! cal ctrlp#statusline()
  849. endf
  850. fu! s:OpenMulti()
  851. if !exists('s:marked') || s:opmul == '0' || !s:ispath | retu | en
  852. " Get the options
  853. let opts = matchlist(s:opmul, '\v^(\d+)=(\w)=(\w)=$')
  854. if opts == [] | retu | en
  855. let [nr, md, ucr] = opts[1:3]
  856. if s:argmap
  857. let md = s:argmaps(md)
  858. if md == 'cancel' | retu | en
  859. en
  860. let mkd = values(s:marked)
  861. cal s:sanstail(join(s:prompt, ''))
  862. cal s:PrtExit()
  863. " Move the cursor to a reusable window
  864. let [tail, fnesc] = [s:tail(), exists('*fnameescape') && v:version > 701]
  865. let [emptytail, nwpt] = [empty(tail), exists('g:ctrlp_open_multiple_files')]
  866. let bufnr = bufnr('^'.mkd[0].'$')
  867. let useb = bufnr > 0 && buflisted(bufnr) && emptytail
  868. let fst = call('ctrlp#normcmd', useb ? ['b', 'bo vert sb'] : ['e'])
  869. " Check if it's a replaceable buffer
  870. let repabl = ( empty(bufname('%')) && empty(&l:ft) ) || s:nosplit()
  871. " Commands for the rest of the files
  872. let [ic, cmds] = [1, { 'v': ['vert sb', 'vne'], 'h': ['sb', 'new'],
  873. \ 't': ['tab sb', 'tabe'] }]
  874. let [swb, &swb] = [&swb, '']
  875. " Open the files
  876. for va in mkd
  877. let bufnr = bufnr('^'.va.'$')
  878. if bufnr < 0 && getftype(va) == '' | con | en
  879. let useb = bufnr > 0 && buflisted(bufnr) && emptytail
  880. let snd = md != '' && has_key(cmds, md) ?
  881. \ ( useb ? cmds[md][0] : cmds[md][1] ) : ( useb ? 'vert sb' : 'vne' )
  882. let cmd = ic == 1 && ( ucr == 'r' || repabl ) ? fst : snd
  883. let conds = [( nr != '' && nr > 1 && nr < ic ) || ( nr == '' && ic > 1 ),
  884. \ nr != '' && nr < ic]
  885. if conds[nwpt]
  886. if bufnr <= 0 | if fnesc
  887. cal s:openfile('bad', fnamemodify(va, ':.'), '')
  888. el
  889. cal s:openfile(cmd, va, tail) | sil! hid clo!
  890. en | en
  891. el
  892. cal s:openfile(cmd, useb ? bufnr : va, tail) | let ic += 1
  893. en
  894. endfo
  895. let &swb = swb
  896. endf
  897. " ** Helper functions {{{1
  898. " Sorting {{{2
  899. fu! ctrlp#complen(...)
  900. " By length
  901. let [len1, len2] = [strlen(a:1), strlen(a:2)]
  902. retu len1 == len2 ? 0 : len1 > len2 ? 1 : -1
  903. endf
  904. fu! s:compmatlen(...)
  905. " By match length
  906. let mln1 = s:shortest(s:matchlens(a:1, s:compat))
  907. let mln2 = s:shortest(s:matchlens(a:2, s:compat))
  908. retu mln1 == mln2 ? 0 : mln1 > mln2 ? 1 : -1
  909. endf
  910. fu! s:comptime(...)
  911. " By last modified time
  912. let [time1, time2] = [getftime(a:1), getftime(a:2)]
  913. retu time1 == time2 ? 0 : time1 < time2 ? 1 : -1
  914. endf
  915. fu! s:compmreb(...)
  916. " By last entered time (buffer)
  917. if !exists('s:mrbs')
  918. let s:mrbs = ctrlp#mrufiles#bufs()
  919. en
  920. let id1 = index(s:mrbs, fnamemodify(a:1, ':p'))
  921. let id2 = index(s:mrbs, fnamemodify(a:2, ':p'))
  922. retu id1 == id2 ? 0 : id1 > id2 ? 1 : -1
  923. endf
  924. fu! s:compmref(...)
  925. " By last entered time (MRU)
  926. let id1 = index(g:ctrlp_lines, a:1)
  927. let id2 = index(g:ctrlp_lines, a:2)
  928. retu id1 == id2 ? 0 : id1 > id2 ? 1 : -1
  929. endf
  930. fu! s:comparent(...)
  931. " By same parent dir
  932. if match(s:crfpath, escape(s:dyncwd, '.^$*\')) >= 0
  933. let [as1, as2] = [s:dyncwd.s:lash().a:1, s:dyncwd.s:lash().a:2]
  934. let [loc1, loc2] = [s:getparent(as1), s:getparent(as2)]
  935. if loc1 == s:crfpath && loc2 != s:crfpath | retu -1 | en
  936. if loc2 == s:crfpath && loc1 != s:crfpath | retu 1 | en
  937. retu 0
  938. en
  939. retu 0
  940. endf
  941. fu! s:compfnlen(...)
  942. " By filename length
  943. let len1 = strlen(split(a:1, s:lash)[-1])
  944. let len2 = strlen(split(a:2, s:lash)[-1])
  945. retu len1 == len2 ? 0 : len1 > len2 ? 1 : -1
  946. endf
  947. fu! s:matchlens(str, pat, ...)
  948. if empty(a:pat) || index(['^', '$'], a:pat) >= 0 | retu {} | en
  949. let st = a:0 ? a:1 : 0
  950. let lens = a:0 >= 2 ? a:2 : {}
  951. let nr = a:0 >= 3 ? a:3 : 0
  952. if nr > 20 | retu {} | en
  953. if match(a:str, a:pat, st) >= 0
  954. let [mst, mnd] = [matchstr(a:str, a:pat, st), matchend(a:str, a:pat, st)]
  955. let lens = extend(lens, { nr : [strlen(mst), mst] })
  956. let lens = s:matchlens(a:str, a:pat, mnd, lens, nr + 1)
  957. en
  958. retu lens
  959. endf
  960. fu! s:shortest(lens)
  961. retu min(map(values(a:lens), 'v:val[0]'))
  962. endf
  963. fu! s:mixedsort(...)
  964. let [cln, cml] = [ctrlp#complen(a:1, a:2), s:compmatlen(a:1, a:2)]
  965. if s:ispath && s:height < 51
  966. let ms = []
  967. if s:height < 21
  968. if s:itemtype !~ '\v^(1|2)$' | let ms += [s:comptime(a:1, a:2)] | en
  969. let ms += [s:compfnlen(a:1, a:2), s:comparent(a:1, a:2)]
  970. en
  971. let time = s:itemtype == 1 ? [s:compmreb(a:1, a:2)]
  972. \ : s:itemtype == 2 ? [s:compmref(a:1, a:2)] : []
  973. let ms += time + [cml] + [0, 0, 0, 0]
  974. let mp = call('s:multipliers', ms[:3])
  975. retu cln + ms[0] * mp[0] + ms[1] * mp[1] + ms[2] * mp[2] + ms[3] * mp[3]
  976. en
  977. retu cln + cml * 2
  978. endf
  979. fu! s:multipliers(...)
  980. let mp0 = !a:1 ? 0 : 2
  981. let mp1 = !a:2 ? 0 : 1 + ( !mp0 ? 1 : mp0 )
  982. let mp2 = !a:3 ? 0 : 1 + ( !( mp0 + mp1 ) ? 1 : ( mp0 + mp1 ) )
  983. let mp3 = !a:4 ? 0 : 1 + ( !( mp0 + mp1 + mp2 ) ? 1 : ( mp0 + mp1 + mp2 ) )
  984. retu [mp0, mp1, mp2, mp3]
  985. endf
  986. fu! s:compval(...)
  987. retu a:1 - a:2
  988. endf
  989. " Statusline {{{2
  990. fu! ctrlp#statusline()
  991. if !exists('s:statypes')
  992. let s:statypes = [
  993. \ ['files', 'fil'],
  994. \ ['buffers', 'buf'],
  995. \ ['mru files', 'mru'],
  996. \ ]
  997. if !empty(g:ctrlp_ext_vars)
  998. cal map(copy(g:ctrlp_ext_vars),
  999. \ 'add(s:statypes, [ v:val["lname"], v:val["sname"] ])')
  1000. en
  1001. en
  1002. let tps = s:statypes
  1003. let max = len(tps) - 1
  1004. let nxt = tps[s:walker(max, s:itemtype, 1)][1]
  1005. let prv = tps[s:walker(max, s:itemtype, -1)][1]
  1006. let item = tps[s:itemtype][0]
  1007. let focus = s:Focus() ? 'prt' : 'win'
  1008. let byfname = s:byfname ? 'file' : 'path'
  1009. let marked = s:opmul != '0' ?
  1010. \ exists('s:marked') ? ' <'.s:dismrk().'>' : ' <->' : ''
  1011. if s:status != {}
  1012. let args = [focus, byfname, s:regexp, prv, item, nxt, marked]
  1013. let &l:stl = call(s:status['main'], args)
  1014. el
  1015. let item = '%#CtrlPMode1# '.item.' %*'
  1016. let focus = '%#CtrlPMode2# '.focus.' %*'
  1017. let byfname = '%#CtrlPMode1# '.byfname.' %*'
  1018. let regex = s:regexp ? '%#CtrlPMode2# regex %*' : ''
  1019. let slider = ' <'.prv.'>={'.item.'}=<'.nxt.'>'
  1020. let dir = ' %=%<%#CtrlPMode2# '.s:dyncwd.' %*'
  1021. let &l:stl = focus.byfname.regex.slider.marked.dir
  1022. en
  1023. endf
  1024. fu! s:dismrk()
  1025. retu has('signs') ? len(s:marked) :
  1026. \ '%<'.join(values(map(copy(s:marked), 'split(v:val, "[\\/]")[-1]')), ', ')
  1027. endf
  1028. fu! ctrlp#progress(enum)
  1029. if has('macunix') || has('mac') | sl 1m | en
  1030. let &l:stl = s:status != {} ? call(s:status['prog'], [a:enum])
  1031. \ : '%#CtrlPStats# '.a:enum.' %* %=%<%#CtrlPMode2# '.s:dyncwd.' %*'
  1032. redraws
  1033. endf
  1034. " Paths {{{2
  1035. fu! s:formatline(str)
  1036. let cond = s:ispath && ( s:winw - 4 ) < s:strwidth(a:str)
  1037. retu '> '.( cond ? pathshorten(a:str) : a:str )
  1038. endf
  1039. fu! s:dircompl(be, sd)
  1040. if a:sd == '' | retu [] | en
  1041. let [be, sd] = a:be == '' ? [s:dyncwd, a:sd] : [a:be, a:be.s:lash(a:be).a:sd]
  1042. let dirs = ctrlp#rmbasedir(split(globpath(be, a:sd.'*/'), "\n"))
  1043. cal filter(dirs, '!match(v:val, escape(sd, ''~$.\''))'
  1044. \ . ' && match(v:val, ''\v(^|[\/])\.{1,2}[\/]$'') < 0')
  1045. retu dirs
  1046. endf
  1047. fu! s:findcommon(items, seed)
  1048. let [items, id, cmn, ic] = [copy(a:items), strlen(a:seed), '', 0]
  1049. cal map(items, 'strpart(v:val, id)')
  1050. for char in split(items[0], '\zs')
  1051. for item in items[1:]
  1052. if item[ic] != char | let brk = 1 | brea | en
  1053. endfo
  1054. if exists('brk') | brea | en
  1055. let cmn .= char
  1056. let ic += 1
  1057. endfo
  1058. retu cmn
  1059. endf
  1060. fu! s:headntail(str)
  1061. let parts = split(a:str, '[\/]\ze[^\/]\+[\/:]\?$')
  1062. retu len(parts) == 1 ? ['', parts[0]] : len(parts) == 2 ? parts : []
  1063. endf
  1064. fu! s:lash(...)
  1065. retu match(a:0 ? a:1 : s:dyncwd, '[\/]$') < 0 ? s:lash : ''
  1066. endf
  1067. fu! s:ispathitem()
  1068. retu s:itemtype < 3 || ( s:itemtype > 2 && s:getextvar('type') == 'path' )
  1069. endf
  1070. fu! ctrlp#dirnfile(entries)
  1071. let [items, cwd] = [[[], []], s:dyncwd.s:lash()]
  1072. for each in a:entries
  1073. let etype = getftype(each)
  1074. if s:igntype >= 0 && s:usrign(each, etype) | con | en
  1075. if etype == 'dir'
  1076. if s:dotfiles | if match(each, '[\/]\.\{1,2}$') < 0
  1077. cal add(items[0], each)
  1078. en | el
  1079. cal add(items[0], each)
  1080. en
  1081. elsei etype == 'link'
  1082. if s:folsym
  1083. let isfile = !isdirectory(each)
  1084. if !s:samerootsyml(each, isfile, cwd)
  1085. cal add(items[isfile], each)
  1086. en
  1087. en
  1088. elsei etype == 'file'
  1089. cal add(items[1], each)
  1090. en
  1091. endfo
  1092. retu items
  1093. endf
  1094. fu! s:usrign(item, type)
  1095. retu s:igntype == 1 ? a:item =~ s:usrign
  1096. \ : s:igntype == 4 && has_key(s:usrign, a:type) && s:usrign[a:type] != ''
  1097. \ ? a:item =~ s:usrign[a:type] : 0
  1098. endf
  1099. fu! s:samerootsyml(each, isfile, cwd)
  1100. let resolve = fnamemodify(resolve(a:each), ':p:h')
  1101. let resolve .= s:lash(resolve)
  1102. retu !( stridx(resolve, a:cwd) && ( stridx(a:cwd, resolve) || a:isfile ) )
  1103. endf
  1104. fu! ctrlp#rmbasedir(items)
  1105. if a:items != [] && !stridx(a:items[0], s:dyncwd)
  1106. let idx = strlen(s:dyncwd) + ( match(s:dyncwd, '[\/]$') < 0 )
  1107. retu map(a:items, 'strpart(v:val, idx)')
  1108. en
  1109. retu a:items
  1110. endf
  1111. fu! s:parentdir(curr)
  1112. let parent = s:getparent(a:curr)
  1113. if parent != a:curr | cal ctrlp#setdir(parent) | en
  1114. endf
  1115. fu! s:getparent(item)
  1116. let parent = substitute(a:item, '[\/][^\/]\+[\/:]\?$', '', '')
  1117. if parent == '' || match(parent, '[\/]') < 0
  1118. let parent .= s:lash
  1119. en
  1120. retu parent
  1121. endf
  1122. fu! s:findroot(curr, mark, depth, type)
  1123. let [depth, notfound] = [a:depth + 1, empty(s:glbpath(a:curr, a:mark, 1))]
  1124. if !notfound || depth > s:maxdepth
  1125. if notfound | cal ctrlp#setdir(s:cwd) | en
  1126. if a:type && depth <= s:maxdepth
  1127. let s:vcsroot = a:curr
  1128. elsei !a:type && !notfound
  1129. cal ctrlp#setdir(a:curr) | let s:foundroot = 1
  1130. en
  1131. el
  1132. let parent = s:getparent(a:curr)
  1133. if parent != a:curr | cal s:findroot(parent, a:mark, depth, a:type) | en
  1134. en
  1135. endf
  1136. fu! s:glbpath(...)
  1137. let cond = v:version > 702 || ( v:version == 702 && has('patch051') )
  1138. retu call('globpath', cond ? a:000 : a:000[:1])
  1139. endf
  1140. fu! ctrlp#fnesc(path)
  1141. retu exists('*fnameescape') ? fnameescape(a:path) : escape(a:path, " %#*?|<\"\n")
  1142. endf
  1143. fu! ctrlp#setdir(path, ...)
  1144. let cmd = a:0 ? a:1 : 'lc!'
  1145. sil! exe cmd ctrlp#fnesc(a:path)
  1146. let [s:crfilerel, s:dyncwd] = [fnamemodify(s:crfile, ':.'), getcwd()]
  1147. endf
  1148. fu! ctrlp#setlcdir()
  1149. if exists('*haslocaldir')
  1150. cal ctrlp#setdir(getcwd(), haslocaldir() ? 'lc!' : 'cd!')
  1151. en
  1152. endf
  1153. " Highlighting {{{2
  1154. fu! ctrlp#syntax()
  1155. if ctrlp#nosy() | retu | en
  1156. for [ke, va] in items(s:hlgrps) | cal ctrlp#hicheck('CtrlP'.ke, va) | endfo
  1157. if !hlexists('CtrlPLinePre')
  1158. \ && synIDattr(synIDtrans(hlID('Normal')), 'bg') !~ '^-1$\|^$'
  1159. sil! exe 'hi CtrlPLinePre '.( has("gui_running") ? 'gui' : 'cterm' ).'fg=bg'
  1160. en
  1161. sy match CtrlPNoEntries '^ == NO ENTRIES ==$'
  1162. if hlexists('CtrlPLinePre')
  1163. sy match CtrlPLinePre '^>'
  1164. en
  1165. endf
  1166. fu! s:highlight(pat, grp)
  1167. if s:matcher != {} | retu | en
  1168. cal clearmatches()
  1169. if !empty(a:pat) && s:ispath
  1170. let pat = s:regexp ? substitute(a:pat, '\\\@<!\^', '^> \\zs', 'g') : a:pat
  1171. if s:byfname
  1172. " Match only filename
  1173. let pat = substitute(pat, '\[\^\(.\{-}\)\]\\{-}', '[^\\/\1]\\{-}', 'g')
  1174. let pat = substitute(pat, '\$\@<!$', '\\ze[^\\/]*$', 'g')
  1175. en
  1176. cal matchadd(a:grp, '\c'.pat)
  1177. if hlexists('CtrlPLinePre')
  1178. cal matchadd('CtrlPLinePre', '^>')
  1179. en
  1180. en
  1181. endf
  1182. fu! s:dohighlight()
  1183. retu s:mathi[0] && exists('*clearmatches')
  1184. endf
  1185. " Prompt history {{{2
  1186. fu! s:gethistloc()
  1187. let utilcadir = ctrlp#utils#cachedir()
  1188. let cache_dir = utilcadir.s:lash(utilcadir).'hist'
  1189. retu [cache_dir, cache_dir.s:lash(cache_dir).'cache.txt']
  1190. endf
  1191. fu! s:gethistdata()
  1192. retu ctrlp#utils#readfile(s:gethistloc()[1])
  1193. endf
  1194. fu! ctrlp#recordhist()
  1195. let str = join(s:prompt, '')
  1196. if empty(str) || !s:maxhst | retu | en
  1197. let hst = s:hstry
  1198. if len(hst) > 1 && hst[1] == str | retu | en
  1199. cal extend(hst, [str], 1)
  1200. if len(hst) > s:maxhst | cal remove(hst, s:maxhst, -1) | en
  1201. cal ctrlp#utils#writecache(hst, s:gethistloc()[0], s:gethistloc()[1])
  1202. endf
  1203. " Signs {{{2
  1204. fu! s:unmarksigns()
  1205. if !s:dosigns() | retu | en
  1206. for key in keys(s:marked)
  1207. exe 'sign unplace' key 'buffer='.s:bufnr
  1208. endfo
  1209. endf
  1210. fu! s:remarksigns()
  1211. if !s:dosigns() | retu | en
  1212. for ic in range(1, len(s:lines))
  1213. let line = s:ispath ? fnamemodify(s:lines[ic - 1], ':p') : s:lines[ic - 1]
  1214. let key = s:dictindex(s:marked, line)
  1215. if key > 0
  1216. exe 'sign place' key 'line='.ic.' name=ctrlpmark buffer='.s:bufnr
  1217. en
  1218. endfo
  1219. endf
  1220. fu! s:dosigns()
  1221. retu exists('s:marked') && s:bufnr > 0 && s:opmul != '0' && has('signs')
  1222. endf
  1223. " Lists & Dictionaries {{{2
  1224. fu! s:dictindex(dict, expr)
  1225. for key in keys(a:dict)
  1226. if a:dict[key] == a:expr | retu key | en
  1227. endfo
  1228. retu -1
  1229. endf
  1230. fu! s:vacantdict(dict)
  1231. retu filter(range(1, max(keys(a:dict))), '!has_key(a:dict, v:val)')
  1232. endf
  1233. fu! s:sublist(l, s, e)
  1234. retu v:version > 701 ? a:l[(a:s):(a:e)] : s:sublist7071(a:l, a:s, a:e)
  1235. endf
  1236. fu! s:sublist7071(l, s, e)
  1237. let [newlist, id, ae] = [[], a:s, a:e == -1 ? len(a:l) - 1 : a:e]
  1238. wh id <= ae
  1239. cal add(newlist, get(a:l, id))
  1240. let id += 1
  1241. endw
  1242. retu newlist
  1243. endf
  1244. " Buffers {{{2
  1245. fu! s:buftab(bufnr, md)
  1246. for tabnr in range(1, tabpagenr('$'))
  1247. if tabpagenr() == tabnr && a:md == 't' | con | en
  1248. let buflist = tabpagebuflist(tabnr)
  1249. if index(buflist, a:bufnr) >= 0
  1250. for winnr in range(1, tabpagewinnr(tabnr, '$'))
  1251. if buflist[winnr - 1] == a:bufnr | retu [tabnr, winnr] | en
  1252. endfo
  1253. en
  1254. endfo
  1255. retu [0, 0]
  1256. endf
  1257. fu! ctrlp#normcmd(cmd, ...)
  1258. if s:nosplit() | retu a:cmd | en
  1259. let norwins = filter(range(1, winnr('$')),
  1260. \ 'empty(getbufvar(winbufnr(v:val), "&bt"))')
  1261. for each in norwins
  1262. let bufnr = winbufnr(each)
  1263. if empty(bufname(bufnr)) && empty(getbufvar(bufnr, '&ft'))
  1264. let fstemp = each | brea
  1265. en
  1266. endfo
  1267. let norwin = empty(norwins) ? 0 : norwins[0]
  1268. if norwin
  1269. if index(norwins, winnr()) < 0
  1270. exe ( exists('fstemp') ? fstemp : norwin ).'winc w'
  1271. en
  1272. retu a:cmd
  1273. en
  1274. retu a:0 ? a:1 : 'bo vne'
  1275. endf
  1276. fu! s:nosplit()
  1277. retu !empty(s:nosplit) && match([bufname('%'), &l:ft, &l:bt], s:nosplit) >= 0
  1278. endf
  1279. fu! s:setupblank()
  1280. setl noswf nobl nonu nowrap nolist nospell nocuc wfh
  1281. setl fdc=0 fdl=99 tw=0 bt=nofile bh=unload
  1282. if v:version > 702
  1283. setl nornu noudf cc=0
  1284. en
  1285. endf
  1286. fu! s:leavepre()
  1287. if exists('s:bufnr') && s:bufnr == bufnr('%') | bw! | en
  1288. if s:clrex && !( has('clientserver') && len(split(serverlist(), "\n")) > 1 )
  1289. cal ctrlp#clra()
  1290. en
  1291. endf
  1292. fu! s:checkbuf()
  1293. if !exists('s:init') && exists('s:bufnr') && s:bufnr > 0
  1294. exe s:bufnr.'bw!'
  1295. en
  1296. endf
  1297. " Arguments {{{2
  1298. fu! s:tail()
  1299. if exists('s:optail') && !empty('s:optail')
  1300. let tailpref = match(s:optail, '^\s*+') < 0 ? ' +' : ' '
  1301. retu tailpref.s:optail
  1302. en
  1303. retu ''
  1304. endf
  1305. fu! s:sanstail(str)
  1306. let [str, pat] = [substitute(a:str, '\\\\', '\', 'g'), '\([^:]\|\\:\)*$']
  1307. unl! s:optail
  1308. if match(str, '\\\@<!:'.pat) >= 0
  1309. let s:optail = matchstr(str, '\\\@<!:\zs'.pat)
  1310. let str = substitute(str, '\\\@<!:'.pat, '', '')
  1311. en
  1312. retu substitute(str, '\\\ze:', '', 'g')
  1313. endf
  1314. fu! s:argmaps(md, ...)
  1315. redr
  1316. echoh MoreMsg
  1317. echon '[t]ab/[v]ertical/[h]orizontal'.( a:0 ? '/[r]eplace' : '' ).'? '
  1318. echoh None
  1319. let char = nr2char(getchar())
  1320. if index(['r', 'h', 't', 'v'], char) >= 0
  1321. retu char
  1322. elsei char =~# "\\v\<Esc>|\<C-c>|\<C-[>"
  1323. cal s:BuildPrompt(0)
  1324. retu 'cancel'
  1325. en
  1326. retu a:md
  1327. endf
  1328. " Misc {{{2
  1329. fu! s:modevar()
  1330. let s:matchtype = s:mtype()
  1331. let s:ispath = s:ispathitem()
  1332. if !s:ispath | let s:byfname = 0 | en
  1333. let s:mfunc = s:mfunc()
  1334. let s:nolim = s:getextvar('nolim')
  1335. let s:dosort = s:getextvar('sort')
  1336. endf
  1337. fu! s:dosort()
  1338. retu s:matcher == {} && ( ( s:itemtype != 2 && s:nolim != 1 )
  1339. \ || s:prompt != ['', '', ''] ) && !( s:itemtype == 2 && s:mrudef )
  1340. \ && s:dosort
  1341. endf
  1342. fu! s:narrowable()
  1343. retu exists('s:act_add') && exists('s:matched') && s:matched != []
  1344. \ && exists('s:mdata') && s:mdata[:2] == [s:dyncwd, s:itemtype, s:regexp]
  1345. \ && s:matcher == {}
  1346. endf
  1347. fu! s:migemo(str)
  1348. let str = a:str
  1349. let dict = s:glbpath(&rtp, printf("dict/%s/migemo-dict", &enc), 1)
  1350. if !len(dict)
  1351. let dict = s:glbpath(&rtp, "dict/migemo-dict", 1)
  1352. en
  1353. if len(dict)
  1354. let [tokens, str, cmd] = [split(str, '\s'), '', 'cmigemo -v -w %s -d %s']
  1355. for token in tokens
  1356. let rtn = system(printf(cmd, shellescape(token), shellescape(dict)))
  1357. let str .= !v:shell_error && strlen(rtn) > 0 ? '.*'.rtn : token
  1358. endfo
  1359. en
  1360. retu str
  1361. endf
  1362. fu! s:strwidth(str)
  1363. retu exists('*strdisplaywidth') ? strdisplaywidth(a:str) : strlen(a:str)
  1364. endf
  1365. fu! ctrlp#j2l(nr)
  1366. exe a:nr
  1367. sil! norm! zvzz
  1368. endf
  1369. fu! s:maxf(len)
  1370. retu s:maxfiles && a:len > s:maxfiles ? 1 : 0
  1371. endf
  1372. fu! s:regexfilter(str)
  1373. let str = a:str
  1374. for key in keys(s:fpats) | if match(str, key) >= 0
  1375. let str = substitute(str, s:fpats[key], '', 'g')
  1376. en | endfo
  1377. retu str
  1378. endf
  1379. fu! s:walker(m, p, d)
  1380. retu a:d > 0 ? a:p < a:m ? a:p + a:d : 0 : a:p > 0 ? a:p + a:d : a:m
  1381. endf
  1382. fu! s:delent(rfunc)
  1383. if a:rfunc == '' | retu | en
  1384. let [s:force, tbrem] = [1, []]
  1385. if exists('s:marked')
  1386. let tbrem = values(s:marked)
  1387. cal s:unmarksigns()
  1388. unl s:marked
  1389. en
  1390. if tbrem == [] && ( has('dialog_gui') || has('dialog_con') ) &&
  1391. \ confirm("Wipe all entries?", "&OK\n&Cancel") != 1
  1392. unl s:force
  1393. cal s:BuildPrompt(0)
  1394. retu
  1395. en
  1396. let g:ctrlp_lines = call(a:rfunc, [tbrem])
  1397. cal s:BuildPrompt(1)
  1398. unl s:force
  1399. endf
  1400. " Entering & Exiting {{{2
  1401. fu! s:getenv()
  1402. let [s:cwd, s:winres] = [getcwd(), [winrestcmd(), &lines, winnr('$')]]
  1403. let [s:crfile, s:crfpath] = [expand('%:p', 1), expand('%:p:h', 1)]
  1404. let [s:crword, s:crline] = [expand('<cword>'), getline('.')]
  1405. let [s:winh, s:crcursor] = [min([s:mxheight, &lines]), getpos('.')]
  1406. let [s:crbufnr, s:crvisual] = [bufnr('%'), s:lastvisual()]
  1407. let s:currwin = s:mwbottom ? winnr() : winnr() + has('autocmd')
  1408. let s:wpmode = exists('b:ctrlp_working_path_mode')
  1409. \ ? b:ctrlp_working_path_mode : s:pathmode
  1410. endf
  1411. fu! s:lastvisual()
  1412. let cview = winsaveview()
  1413. let [ovreg, ovtype] = [getreg('v'), getregtype('v')]
  1414. let [oureg, outype] = [getreg('"'), getregtype('"')]
  1415. sil! norm! gv"vy
  1416. let selected = substitute(getreg('v'), '\n', '\\n', 'g')
  1417. cal setreg('v', ovreg, ovtype)
  1418. cal setreg('"', oureg, outype)
  1419. cal winrestview(cview)
  1420. retu selected
  1421. endf
  1422. fu! s:log(m)
  1423. if exists('g:ctrlp_log') && g:ctrlp_log | if a:m
  1424. let cadir = ctrlp#utils#cachedir()
  1425. sil! exe 'redi! >' cadir.s:lash(cadir).'ctrlp.log'
  1426. el
  1427. sil! redi END
  1428. en | en
  1429. endf
  1430. fu! s:buffunc(e)
  1431. if a:e && has_key(s:buffunc, 'enter')
  1432. cal call(s:buffunc['enter'], [])
  1433. elsei !a:e && has_key(s:buffunc, 'exit')
  1434. cal call(s:buffunc['exit'], [])
  1435. en
  1436. endf
  1437. fu! s:openfile(cmd, fid, tail, ...)
  1438. let cmd = a:cmd =~ '^[eb]$' && &modified ? 'hid '.a:cmd : a:cmd
  1439. let cmd = cmd =~ '^tab' ? tabpagenr('$').cmd : cmd
  1440. let j2l = a:0 && a:1 ? a:2 : 0
  1441. exe cmd.( a:0 && a:1 ? '' : a:tail ) ctrlp#fnesc(a:fid)
  1442. if j2l
  1443. exe j2l
  1444. en
  1445. if !empty(a:tail) || j2l
  1446. sil! norm! zvzz
  1447. en
  1448. if cmd != 'bad'
  1449. cal ctrlp#setlcdir()
  1450. en
  1451. endf
  1452. fu! s:settype(type)
  1453. retu a:type < 0 ? exists('s:itemtype') ? s:itemtype : 0 : a:type
  1454. endf
  1455. " Matching {{{2
  1456. fu! s:matchfname(item, pat)
  1457. retu match(split(a:item, s:lash)[-1], a:pat)
  1458. endf
  1459. fu! s:matchtabs(item, pat)
  1460. retu match(split(a:item, '\t\+')[0], a:pat)
  1461. endf
  1462. fu! s:matchtabe(item, pat)
  1463. retu match(split(a:item, '\t\+[^\t]\+$')[0], a:pat)
  1464. endf
  1465. fu! s:mfunc()
  1466. let mfunc = 'match'
  1467. if s:byfname && s:ispath
  1468. let mfunc = 's:matchfname'
  1469. elsei s:itemtype > 2
  1470. let matchtypes = { 'tabs': 's:matchtabs', 'tabe': 's:matchtabe' }
  1471. if has_key(matchtypes, s:matchtype)
  1472. let mfunc = matchtypes[s:matchtype]
  1473. en
  1474. en
  1475. retu mfunc
  1476. endf
  1477. fu! s:mmode()
  1478. let matchmodes = {
  1479. \ 'match': 'full-line',
  1480. \ 's:matchfname': 'filename-only',
  1481. \ 's:matchtabs': 'first-non-tab',
  1482. \ 's:matchtabe': 'until-last-tab',
  1483. \ }
  1484. retu matchmodes[s:mfunc]
  1485. endf
  1486. " Cache {{{2
  1487. fu! s:writecache(cache_file)
  1488. if ( g:ctrlp_newcache || !filereadable(a:cache_file) ) && s:caching
  1489. \ || len(g:ctrlp_allfiles) > s:nocache_lim
  1490. if len(g:ctrlp_allfiles) > s:nocache_lim | let s:caching = 1 | en
  1491. cal ctrlp#utils#writecache(g:ctrlp_allfiles)
  1492. let g:ctrlp_newcache = 0
  1493. en
  1494. endf
  1495. fu! s:insertcache(str)
  1496. let [data, g:ctrlp_newcache, str] = [g:ctrlp_allfiles, 1, a:str]
  1497. if strlen(str) <= strlen(data[0])
  1498. let pos = 0
  1499. elsei strlen(str) >= strlen(data[-1])
  1500. let pos = len(data) - 1
  1501. el
  1502. let pos = 0
  1503. for each in data
  1504. if strlen(each) > strlen(str) | brea | en
  1505. let pos += 1
  1506. endfo
  1507. en
  1508. cal insert(data, str, pos)
  1509. cal s:writecache(ctrlp#utils#cachefile())
  1510. endf
  1511. " Extensions {{{2
  1512. fu! s:mtype()
  1513. retu s:itemtype > 2 ? s:getextvar('type') : 'path'
  1514. endf
  1515. fu! s:execextvar(key)
  1516. if !empty(g:ctrlp_ext_vars)
  1517. cal map(filter(copy(g:ctrlp_ext_vars),
  1518. \ 'has_key(v:val, a:key)'), 'eval(v:val[a:key])')
  1519. en
  1520. endf
  1521. fu! s:getextvar(key)
  1522. if s:itemtype > 2
  1523. let vars = g:ctrlp_ext_vars[s:itemtype - 3]
  1524. retu has_key(vars, a:key) ? vars[a:key] : -1
  1525. en
  1526. retu -1
  1527. endf
  1528. fu! ctrlp#exit()
  1529. cal s:PrtExit()
  1530. endf
  1531. fu! ctrlp#prtclear()
  1532. cal s:PrtClear()
  1533. endf
  1534. fu! ctrlp#switchtype(id)
  1535. cal s:ToggleType(a:id - s:itemtype)
  1536. endf
  1537. fu! ctrlp#nosy()
  1538. retu !( has('syntax') && exists('g:syntax_on') )
  1539. endf
  1540. fu! ctrlp#hicheck(grp, defgrp)
  1541. if !hlexists(a:grp)
  1542. exe 'hi link' a:grp a:defgrp
  1543. en
  1544. endf
  1545. fu! ctrlp#call(func, ...)
  1546. cal call(a:func, a:000)
  1547. endf
  1548. "}}}1
  1549. " * Initialization {{{1
  1550. fu! ctrlp#setlines(...)
  1551. if a:0 | let s:itemtype = a:1 | en
  1552. cal s:modevar()
  1553. let types = ['ctrlp#files()', 'ctrlp#buffers()', 'ctrlp#mrufiles#list()']
  1554. if !empty(g:ctrlp_ext_vars)
  1555. cal map(copy(g:ctrlp_ext_vars), 'add(types, v:val["init"])')
  1556. en
  1557. let g:ctrlp_lines = eval(types[s:itemtype])
  1558. endf
  1559. fu! ctrlp#init(type, ...)
  1560. if exists('s:init') | retu | en
  1561. let [s:matches, s:init] = [1, 1]
  1562. cal s:Open()
  1563. cal s:SetWD(a:0 ? a:1 : '')
  1564. cal s:MapKeys()
  1565. cal ctrlp#syntax()
  1566. cal ctrlp#setlines(s:settype(a:type))
  1567. cal s:SetDefTxt()
  1568. cal s:BuildPrompt(1)
  1569. endf
  1570. " - Autocmds {{{1
  1571. fu! s:autocmds()
  1572. if !has('autocmd') | retu | en
  1573. aug CtrlPAug
  1574. au!
  1575. au BufEnter ControlP cal s:checkbuf()
  1576. au BufLeave ControlP cal s:Close()
  1577. au VimLeavePre * cal s:leavepre()
  1578. aug END
  1579. if exists('#CtrlPLazy')
  1580. au! CtrlPLazy
  1581. en
  1582. if s:lazy
  1583. aug CtrlPLazy
  1584. au!
  1585. au CursorHold ControlP cal s:ForceUpdate()
  1586. aug END
  1587. en
  1588. endf
  1589. cal s:autocmds()
  1590. "}}}
  1591. " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2