buffertag.vim 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. " =============================================================================
  2. " File: autoload/ctrlp/buffertag.vim
  3. " Description: Buffer Tag extension
  4. " Maintainer: Kien Nguyen <github.com/kien>
  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. " Init {{{1
  10. if exists('g:loaded_ctrlp_buftag') && g:loaded_ctrlp_buftag
  11. fini
  12. en
  13. let g:loaded_ctrlp_buftag = 1
  14. cal add(g:ctrlp_ext_vars, {
  15. \ 'init': 'ctrlp#buffertag#init(s:crfile)',
  16. \ 'accept': 'ctrlp#buffertag#accept',
  17. \ 'lname': 'buffer tags',
  18. \ 'sname': 'bft',
  19. \ 'exit': 'ctrlp#buffertag#exit()',
  20. \ 'type': 'tabs',
  21. \ 'opts': 'ctrlp#buffertag#opts()',
  22. \ })
  23. let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars)
  24. let [s:pref, s:opts] = ['g:ctrlp_buftag_', {
  25. \ 'systemenc': ['s:enc', &enc],
  26. \ 'ctags_bin': ['s:bin', ''],
  27. \ 'types': ['s:usr_types', {}],
  28. \ }]
  29. let s:bins = [
  30. \ 'ctags-exuberant',
  31. \ 'exuberant-ctags',
  32. \ 'exctags',
  33. \ '/usr/local/bin/ctags',
  34. \ '/opt/local/bin/ctags',
  35. \ 'ctags',
  36. \ 'ctags.exe',
  37. \ 'tags',
  38. \ ]
  39. let s:types = {
  40. \ 'asm' : '%sasm%sasm%sdlmt',
  41. \ 'aspperl': '%sasp%sasp%sfsv',
  42. \ 'aspvbs' : '%sasp%sasp%sfsv',
  43. \ 'awk' : '%sawk%sawk%sf',
  44. \ 'beta' : '%sbeta%sbeta%sfsv',
  45. \ 'c' : '%sc%sc%sdgsutvf',
  46. \ 'cpp' : '%sc++%sc++%snvdtcgsuf',
  47. \ 'cs' : '%sc#%sc#%sdtncEgsipm',
  48. \ 'cobol' : '%scobol%scobol%sdfgpPs',
  49. \ 'eiffel' : '%seiffel%seiffel%scf',
  50. \ 'erlang' : '%serlang%serlang%sdrmf',
  51. \ 'expect' : '%stcl%stcl%scfp',
  52. \ 'fortran': '%sfortran%sfortran%spbceiklmntvfs',
  53. \ 'html' : '%shtml%shtml%saf',
  54. \ 'java' : '%sjava%sjava%spcifm',
  55. \ 'javascript': '%sjavascript%sjavascript%sf',
  56. \ 'lisp' : '%slisp%slisp%sf',
  57. \ 'lua' : '%slua%slua%sf',
  58. \ 'make' : '%smake%smake%sm',
  59. \ 'ocaml' : '%socaml%socaml%scmMvtfCre',
  60. \ 'pascal' : '%spascal%spascal%sfp',
  61. \ 'perl' : '%sperl%sperl%sclps',
  62. \ 'php' : '%sphp%sphp%scdvf',
  63. \ 'python' : '%spython%spython%scmf',
  64. \ 'rexx' : '%srexx%srexx%ss',
  65. \ 'ruby' : '%sruby%sruby%scfFm',
  66. \ 'scheme' : '%sscheme%sscheme%ssf',
  67. \ 'sh' : '%ssh%ssh%sf',
  68. \ 'csh' : '%ssh%ssh%sf',
  69. \ 'zsh' : '%ssh%ssh%sf',
  70. \ 'slang' : '%sslang%sslang%snf',
  71. \ 'sml' : '%ssml%ssml%secsrtvf',
  72. \ 'sql' : '%ssql%ssql%scFPrstTvfp',
  73. \ 'tcl' : '%stcl%stcl%scfmp',
  74. \ 'vera' : '%svera%svera%scdefgmpPtTvx',
  75. \ 'verilog': '%sverilog%sverilog%smcPertwpvf',
  76. \ 'vim' : '%svim%svim%savf',
  77. \ 'yacc' : '%syacc%syacc%sl',
  78. \ }
  79. cal map(s:types, 'printf(v:val, "--language-force=", " --", "-types=")')
  80. if executable('jsctags')
  81. cal extend(s:types, { 'javascript': { 'args': '-f -', 'bin': 'jsctags' } })
  82. en
  83. fu! ctrlp#buffertag#opts()
  84. for [ke, va] in items(s:opts)
  85. let {va[0]} = exists(s:pref.ke) ? {s:pref.ke} : va[1]
  86. endfo
  87. " Ctags bin
  88. if empty(s:bin)
  89. for bin in s:bins | if executable(bin)
  90. let s:bin = bin
  91. brea
  92. en | endfo
  93. el
  94. let s:bin = expand(s:bin, 1)
  95. en
  96. " Types
  97. cal extend(s:types, s:usr_types)
  98. endf
  99. " Utilities {{{1
  100. fu! s:validfile(fname, ftype)
  101. if ( !empty(a:fname) || !empty(a:ftype) ) && filereadable(a:fname)
  102. \ && index(keys(s:types), a:ftype) >= 0 | retu 1 | en
  103. retu 0
  104. endf
  105. fu! s:exectags(cmd)
  106. if exists('+ssl')
  107. let [ssl, &ssl] = [&ssl, 0]
  108. en
  109. if &sh =~ 'cmd\.exe'
  110. let [sxq, &sxq, shcf, &shcf] = [&sxq, '"', &shcf, '/s /c']
  111. en
  112. let output = system(a:cmd)
  113. if &sh =~ 'cmd\.exe'
  114. let [&sxq, &shcf] = [sxq, shcf]
  115. en
  116. if exists('+ssl')
  117. let &ssl = ssl
  118. en
  119. retu output
  120. endf
  121. fu! s:exectagsonfile(fname, ftype)
  122. let [ags, ft] = ['-f - --sort=no --excmd=pattern --fields=nKs ', a:ftype]
  123. if type(s:types[ft]) == 1
  124. let ags .= s:types[ft]
  125. let bin = s:bin
  126. elsei type(s:types[ft]) == 4
  127. let ags = s:types[ft]['args']
  128. let bin = expand(s:types[ft]['bin'], 1)
  129. en
  130. if empty(bin) | retu '' | en
  131. let cmd = s:esctagscmd(bin, ags, a:fname)
  132. if empty(cmd) | retu '' | en
  133. let output = s:exectags(cmd)
  134. if v:shell_error || output =~ 'Warning: cannot open' | retu '' | en
  135. retu output
  136. endf
  137. fu! s:esctagscmd(bin, args, ...)
  138. if exists('+ssl')
  139. let [ssl, &ssl] = [&ssl, 0]
  140. en
  141. let fname = a:0 ? shellescape(a:1) : ''
  142. let cmd = shellescape(a:bin).' '.a:args.' '.fname
  143. if &sh =~ 'cmd\.exe'
  144. let cmd = substitute(cmd, '[&()@^<>|]', '^\0', 'g')
  145. en
  146. if exists('+ssl')
  147. let &ssl = ssl
  148. en
  149. if has('iconv')
  150. let last = s:enc != &enc ? s:enc : !empty( $LANG ) ? $LANG : &enc
  151. let cmd = iconv(cmd, &enc, last)
  152. en
  153. retu cmd
  154. endf
  155. fu! s:process(fname, ftype)
  156. if !s:validfile(a:fname, a:ftype) | retu [] | endif
  157. let ftime = getftime(a:fname)
  158. if has_key(g:ctrlp_buftags, a:fname)
  159. \ && g:ctrlp_buftags[a:fname]['time'] >= ftime
  160. let lines = g:ctrlp_buftags[a:fname]['lines']
  161. el
  162. let data = s:exectagsonfile(a:fname, a:ftype)
  163. let [raw, lines] = [split(data, '\n\+'), []]
  164. for line in raw
  165. if line !~# '^!_TAG_' && len(split(line, ';"')) == 2
  166. let parsed_line = s:parseline(line)
  167. if parsed_line != ''
  168. cal add(lines, parsed_line)
  169. en
  170. en
  171. endfo
  172. let cache = { a:fname : { 'time': ftime, 'lines': lines } }
  173. cal extend(g:ctrlp_buftags, cache)
  174. en
  175. retu lines
  176. endf
  177. fu! s:parseline(line)
  178. let vals = matchlist(a:line,
  179. \ '\v^([^\t]+)\t(.+)\t[?/]\^?(.{-1,})\$?[?/]\;\"\t(.+)\tline(no)?\:(\d+)')
  180. if vals == [] | retu '' | en
  181. let [bufnr, bufname] = [bufnr('^'.vals[2].'$'), fnamemodify(vals[2], ':p:t')]
  182. retu vals[1].' '.vals[4].'|'.bufnr.':'.bufname.'|'.vals[6].'| '.vals[3]
  183. endf
  184. fu! s:syntax()
  185. if !ctrlp#nosy()
  186. cal ctrlp#hicheck('CtrlPTagKind', 'Title')
  187. cal ctrlp#hicheck('CtrlPBufName', 'Directory')
  188. cal ctrlp#hicheck('CtrlPTabExtra', 'Comment')
  189. sy match CtrlPTagKind '\zs[^\t|]\+\ze|\d\+:[^|]\+|\d\+|'
  190. sy match CtrlPBufName '|\d\+:\zs[^|]\+\ze|\d\+|'
  191. sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName,CtrlPTagKind
  192. en
  193. endf
  194. fu! s:chknearby(pat)
  195. if match(getline('.'), a:pat) < 0
  196. let [int, forw, maxl] = [1, 1, line('$')]
  197. wh !search(a:pat, 'W'.( forw ? '' : 'b' ))
  198. if !forw
  199. if int > maxl | brea | en
  200. let int += int
  201. en
  202. let forw = !forw
  203. endw
  204. en
  205. endf
  206. " Public {{{1
  207. fu! ctrlp#buffertag#init(fname)
  208. let bufs = exists('s:btmode') && s:btmode
  209. \ ? filter(ctrlp#buffers(), 'filereadable(v:val)')
  210. \ : [exists('s:bufname') ? s:bufname : a:fname]
  211. let lines = []
  212. for each in bufs
  213. let bname = fnamemodify(each, ':p')
  214. let tftype = get(split(getbufvar('^'.bname.'$', '&ft'), '\.'), 0, '')
  215. cal extend(lines, s:process(bname, tftype))
  216. endfo
  217. cal s:syntax()
  218. retu lines
  219. endf
  220. fu! ctrlp#buffertag#accept(mode, str)
  221. let vals = matchlist(a:str,
  222. \ '\v^[^\t]+\t+[^\t|]+\|(\d+)\:[^\t|]+\|(\d+)\|\s(.+)$')
  223. let bufnr = str2nr(get(vals, 1))
  224. if bufnr
  225. cal ctrlp#acceptfile(a:mode, bufnr)
  226. exe 'norm!' str2nr(get(vals, 2, line('.'))).'G'
  227. cal s:chknearby('\V\C'.get(vals, 3, ''))
  228. sil! norm! zvzz
  229. en
  230. endf
  231. fu! ctrlp#buffertag#cmd(mode, ...)
  232. let s:btmode = a:mode
  233. if a:0 && !empty(a:1)
  234. let s:btmode = 0
  235. let bname = a:1 =~# '^%$\|^#\d*$' ? expand(a:1) : a:1
  236. let s:bufname = fnamemodify(bname, ':p')
  237. en
  238. retu s:id
  239. endf
  240. fu! ctrlp#buffertag#exit()
  241. unl! s:btmode s:bufname
  242. endf
  243. "}}}
  244. " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2