My dotfiles. Period.

gutentags.vim 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. " gutentags.vim - Automatic ctags management for Vim
  2. " Utilities {{{
  3. function! gutentags#chdir(path)
  4. if has('nvim')
  5. let chdir = haslocaldir() ? 'lcd' : haslocaldir(-1, 0) ? 'tcd' : 'cd'
  6. else
  7. let chdir = haslocaldir() ? 'lcd' : 'cd'
  8. endif
  9. execute chdir a:path
  10. endfunction
  11. " Throw an exception message.
  12. function! gutentags#throw(message)
  13. throw "gutentags: " . a:message
  14. endfunction
  15. " Show an error message.
  16. function! gutentags#error(message)
  17. let v:errmsg = "gutentags: " . a:message
  18. echoerr v:errmsg
  19. endfunction
  20. " Show a warning message.
  21. function! gutentags#warning(message)
  22. echohl WarningMsg
  23. echom "gutentags: " . a:message
  24. echohl None
  25. endfunction
  26. " Prints a message if debug tracing is enabled.
  27. function! gutentags#trace(message, ...)
  28. if g:gutentags_trace || (a:0 && a:1)
  29. let l:message = "gutentags: " . a:message
  30. echom l:message
  31. endif
  32. endfunction
  33. " Strips the ending slash in a path.
  34. function! gutentags#stripslash(path)
  35. return fnamemodify(a:path, ':s?[/\\]$??')
  36. endfunction
  37. " Normalizes the slashes in a path.
  38. function! gutentags#normalizepath(path)
  39. if exists('+shellslash') && &shellslash
  40. return substitute(a:path, '\v/', '\\', 'g')
  41. elseif has('win32')
  42. return substitute(a:path, '\v/', '\\', 'g')
  43. else
  44. return a:path
  45. endif
  46. endfunction
  47. " Shell-slashes the path (opposite of `normalizepath`).
  48. function! gutentags#shellslash(path)
  49. if exists('+shellslash') && !&shellslash
  50. return substitute(a:path, '\v\\', '/', 'g')
  51. else
  52. return a:path
  53. endif
  54. endfunction
  55. " Gets a file path in the correct `plat` folder.
  56. function! gutentags#get_plat_file(filename) abort
  57. return g:gutentags_plat_dir . a:filename . g:gutentags_script_ext
  58. endfunction
  59. " Gets a file path in the resource folder.
  60. function! gutentags#get_res_file(filename) abort
  61. return g:gutentags_res_dir . a:filename
  62. endfunction
  63. " Generate a path for a given filename in the cache directory.
  64. function! gutentags#get_cachefile(root_dir, filename) abort
  65. if gutentags#is_path_rooted(a:filename)
  66. return a:filename
  67. endif
  68. let l:tag_path = gutentags#stripslash(a:root_dir) . '/' . a:filename
  69. if g:gutentags_cache_dir != ""
  70. " Put the tag file in the cache dir instead of inside the
  71. " project root.
  72. let l:tag_path = g:gutentags_cache_dir . '/' .
  73. \tr(l:tag_path, '\/: ', '---_')
  74. let l:tag_path = substitute(l:tag_path, '/\-', '/', '')
  75. let l:tag_path = substitute(l:tag_path, '[\-_]*$', '', '')
  76. endif
  77. let l:tag_path = gutentags#normalizepath(l:tag_path)
  78. return l:tag_path
  79. endfunction
  80. " Makes sure a given command starts with an executable that's in the PATH.
  81. function! gutentags#validate_cmd(cmd) abort
  82. if !empty(a:cmd) && executable(split(a:cmd)[0])
  83. return a:cmd
  84. endif
  85. return ""
  86. endfunction
  87. " Makes an appropriate command line for use with `job_start` by converting
  88. " a list of possibly quoted arguments into a single string on Windows, or
  89. " into a list of unquoted arguments on Unix/Mac.
  90. if has('win32') || has('win64')
  91. function! gutentags#make_args(cmd) abort
  92. return join(a:cmd, ' ')
  93. endfunction
  94. else
  95. function! gutentags#make_args(cmd) abort
  96. let l:outcmd = []
  97. for cmdarg in a:cmd
  98. " Thanks Vimscript... you can use negative integers for strings
  99. " in the slice notation, but not for indexing characters :(
  100. let l:arglen = strlen(cmdarg)
  101. if (cmdarg[0] == '"' && cmdarg[l:arglen - 1] == '"') ||
  102. \(cmdarg[0] == "'" && cmdarg[l:arglen - 1] == "'")
  103. call add(l:outcmd, cmdarg[1:-2])
  104. else
  105. call add(l:outcmd, cmdarg)
  106. endif
  107. endfor
  108. return l:outcmd
  109. endfunction
  110. endif
  111. " Returns whether a path is rooted.
  112. if has('win32') || has('win64')
  113. function! gutentags#is_path_rooted(path) abort
  114. return len(a:path) >= 2 && (
  115. \a:path[0] == '/' || a:path[0] == '\' || a:path[1] == ':')
  116. endfunction
  117. else
  118. function! gutentags#is_path_rooted(path) abort
  119. return !empty(a:path) && a:path[0] == '/'
  120. endfunction
  121. endif
  122. " }}}
  123. " Gutentags Setup {{{
  124. let s:known_files = []
  125. let s:known_projects = {}
  126. function! s:cache_project_root(path) abort
  127. let l:result = {}
  128. for proj_info in g:gutentags_project_info
  129. let l:filematch = get(proj_info, 'file', '')
  130. if l:filematch != '' && filereadable(a:path . '/'. l:filematch)
  131. let l:result = copy(proj_info)
  132. break
  133. endif
  134. let l:globmatch = get(proj_info, 'glob', '')
  135. if l:globmatch != '' && glob(a:path . '/' . l:globmatch) != ''
  136. let l:result = copy(proj_info)
  137. break
  138. endif
  139. endfor
  140. let s:known_projects[a:path] = l:result
  141. endfunction
  142. function! gutentags#get_project_file_list_cmd(path) abort
  143. if type(g:gutentags_file_list_command) == type("")
  144. return gutentags#validate_cmd(g:gutentags_file_list_command)
  145. elseif type(g:gutentags_file_list_command) == type({})
  146. let l:markers = get(g:gutentags_file_list_command, 'markers', [])
  147. if type(l:markers) == type({})
  148. for [marker, file_list_cmd] in items(l:markers)
  149. if !empty(globpath(a:path, marker, 1))
  150. return gutentags#validate_cmd(file_list_cmd)
  151. endif
  152. endfor
  153. endif
  154. return get(g:gutentags_file_list_command, 'default', "")
  155. endif
  156. return ""
  157. endfunction
  158. " Finds the first directory with a project marker by walking up from the given
  159. " file path.
  160. function! gutentags#get_project_root(path) abort
  161. if g:gutentags_project_root_finder != ''
  162. return call(g:gutentags_project_root_finder, [a:path])
  163. endif
  164. return gutentags#default_get_project_root(a:path)
  165. endfunction
  166. " Default implementation for finding project markers... useful when a custom
  167. " finder (`g:gutentags_project_root_finder`) wants to fallback to the default
  168. " behaviour.
  169. function! gutentags#default_get_project_root(path) abort
  170. let l:path = gutentags#stripslash(a:path)
  171. let l:previous_path = ""
  172. let l:markers = g:gutentags_project_root[:]
  173. if g:gutentags_add_ctrlp_root_markers && exists('g:ctrlp_root_markers')
  174. for crm in g:ctrlp_root_markers
  175. if index(l:markers, crm) < 0
  176. call add(l:markers, crm)
  177. endif
  178. endfor
  179. endif
  180. while l:path != l:previous_path
  181. for root in l:markers
  182. if !empty(globpath(l:path, root, 1))
  183. let l:proj_dir = simplify(fnamemodify(l:path, ':p'))
  184. let l:proj_dir = gutentags#stripslash(l:proj_dir)
  185. if l:proj_dir == ''
  186. call gutentags#trace("Found project marker '" . root .
  187. \"' at the root of your file-system! " .
  188. \" That's probably wrong, disabling " .
  189. \"gutentags for this file...",
  190. \1)
  191. call gutentags#throw("Marker found at root, aborting.")
  192. endif
  193. for ign in g:gutentags_exclude_project_root
  194. if l:proj_dir == ign
  195. call gutentags#trace(
  196. \"Ignoring project root '" . l:proj_dir .
  197. \"' because it is in the list of ignored" .
  198. \" projects.")
  199. call gutentags#throw("Ignore project: " . l:proj_dir)
  200. endif
  201. endfor
  202. return l:proj_dir
  203. endif
  204. endfor
  205. let l:previous_path = l:path
  206. let l:path = fnamemodify(l:path, ':h')
  207. endwhile
  208. call gutentags#throw("Can't figure out what tag file to use for: " . a:path)
  209. endfunction
  210. " Get info on the project we're inside of.
  211. function! gutentags#get_project_info(path) abort
  212. return get(s:known_projects, a:path, {})
  213. endfunction
  214. " Setup gutentags for the current buffer.
  215. function! gutentags#setup_gutentags() abort
  216. if exists('b:gutentags_files') && !g:gutentags_debug
  217. " This buffer already has gutentags support.
  218. return
  219. endif
  220. " Don't setup gutentags for anything that's not a normal buffer
  221. " (so don't do anything for help buffers and quickfix windows and
  222. " other such things)
  223. " Also don't do anything for the default `[No Name]` buffer you get
  224. " after starting Vim.
  225. if &buftype != '' ||
  226. \(bufname('%') == '' && !g:gutentags_generate_on_empty_buffer)
  227. return
  228. endif
  229. " Don't setup gutentags for things that don't need it, or that could
  230. " cause problems.
  231. if index(g:gutentags_exclude_filetypes, &filetype) >= 0
  232. return
  233. endif
  234. " Let the user specify custom ways to disable Gutentags.
  235. if g:gutentags_init_user_func != '' &&
  236. \!call(g:gutentags_init_user_func, [expand('%:p')])
  237. call gutentags#trace("Ignoring '" . bufname('%') . "' because of " .
  238. \"custom user function.")
  239. return
  240. endif
  241. " Try and find what tags file we should manage.
  242. call gutentags#trace("Scanning buffer '" . bufname('%') . "' for gutentags setup...")
  243. try
  244. let l:buf_dir = expand('%:p:h', 1)
  245. if g:gutentags_resolve_symlinks
  246. let l:buf_dir = fnamemodify(resolve(expand('%:p', 1)), ':p:h')
  247. endif
  248. if !exists('b:gutentags_root')
  249. let b:gutentags_root = gutentags#get_project_root(l:buf_dir)
  250. endif
  251. if !len(b:gutentags_root)
  252. call gutentags#trace("no valid project root.. no gutentags support.")
  253. return
  254. endif
  255. if filereadable(b:gutentags_root . '/.notags')
  256. call gutentags#trace("'.notags' file found... no gutentags support.")
  257. return
  258. endif
  259. if !has_key(s:known_projects, b:gutentags_root)
  260. call s:cache_project_root(b:gutentags_root)
  261. endif
  262. if g:gutentags_trace
  263. let l:projnfo = gutentags#get_project_info(b:gutentags_root)
  264. if l:projnfo != {}
  265. call gutentags#trace("Setting project type to ".l:projnfo['type'])
  266. else
  267. call gutentags#trace("No specific project type.")
  268. endif
  269. endif
  270. let b:gutentags_files = {}
  271. for module in g:gutentags_modules
  272. call call("gutentags#".module."#init", [b:gutentags_root])
  273. endfor
  274. catch /^gutentags\:/
  275. call gutentags#trace("No gutentags support for this buffer.")
  276. return
  277. endtry
  278. " We know what tags file to manage! Now set things up.
  279. call gutentags#trace("Setting gutentags for buffer '".bufname('%')."'")
  280. " Autocommands for updating the tags on save.
  281. " We need to pass the buffer number to the callback function in the rare
  282. " case that the current buffer is changed by another `BufWritePost`
  283. " callback. This will let us get that buffer's variables without causing
  284. " errors.
  285. let l:bn = bufnr('%')
  286. execute 'augroup gutentags_buffer_' . l:bn
  287. execute ' autocmd!'
  288. execute ' autocmd BufWritePost <buffer=' . l:bn . '> call s:write_triggered_update_tags(' . l:bn . ')'
  289. execute 'augroup end'
  290. " Miscellaneous commands.
  291. command! -buffer -bang GutentagsUpdate :call s:manual_update_tags(<bang>0)
  292. " Add these tags files to the known tags files.
  293. for module in keys(b:gutentags_files)
  294. let l:tagfile = b:gutentags_files[module]
  295. let l:found = index(s:known_files, l:tagfile)
  296. if l:found < 0
  297. call add(s:known_files, l:tagfile)
  298. " Generate this new file depending on settings and stuff.
  299. if g:gutentags_enabled
  300. if g:gutentags_generate_on_missing && !filereadable(l:tagfile)
  301. call gutentags#trace("Generating missing tags file: " . l:tagfile)
  302. call s:update_tags(l:bn, module, 1, 1)
  303. elseif g:gutentags_generate_on_new
  304. call gutentags#trace("Generating tags file: " . l:tagfile)
  305. call s:update_tags(l:bn, module, 1, 1)
  306. endif
  307. endif
  308. endif
  309. endfor
  310. endfunction
  311. " }}}
  312. " Job Management {{{
  313. " List of queued-up jobs, and in-progress jobs, per module.
  314. let s:update_queue = {}
  315. let s:update_in_progress = {}
  316. for module in g:gutentags_modules
  317. let s:update_queue[module] = []
  318. let s:update_in_progress[module] = []
  319. endfor
  320. function! gutentags#add_job(module, tags_file, data) abort
  321. call add(s:update_in_progress[a:module], [a:tags_file, a:data])
  322. endfunction
  323. function! gutentags#find_job_index_by_tags_file(module, tags_file) abort
  324. let l:idx = -1
  325. for upd_info in s:update_in_progress[a:module]
  326. let l:idx += 1
  327. if upd_info[0] == a:tags_file
  328. return l:idx
  329. endif
  330. endfor
  331. return -1
  332. endfunction
  333. function! gutentags#find_job_index_by_data(module, data) abort
  334. let l:idx = -1
  335. for upd_info in s:update_in_progress[a:module]
  336. let l:idx += 1
  337. if upd_info[1] == a:data
  338. return l:idx
  339. endif
  340. endfor
  341. return -1
  342. endfunction
  343. function! gutentags#get_job_tags_file(module, job_idx) abort
  344. return s:update_in_progress[a:module][a:job_idx][0]
  345. endfunction
  346. function! gutentags#get_job_data(module, job_idx) abort
  347. return s:update_in_progress[a:module][a:job_idx][1]
  348. endfunction
  349. function! gutentags#remove_job(module, job_idx) abort
  350. let l:tags_file = s:update_in_progress[a:module][a:job_idx][0]
  351. call remove(s:update_in_progress[a:module], a:job_idx)
  352. " Run the user callback for finished jobs.
  353. silent doautocmd User GutentagsUpdated
  354. " See if we had any more updates queued up for this.
  355. let l:qu_idx = -1
  356. for qu_info in s:update_queue[a:module]
  357. let l:qu_idx += 1
  358. if qu_info[0] == l:tags_file
  359. break
  360. endif
  361. endfor
  362. if l:qu_idx >= 0
  363. let l:qu_info = s:update_queue[a:module][l:qu_idx]
  364. call remove(s:update_queue[a:module], l:qu_idx)
  365. if bufexists(l:qu_info[1])
  366. call gutentags#trace("Finished ".a:module." job, ".
  367. \"running queued update for '".l:tags_file."'.")
  368. call s:update_tags(l:qu_info[1], a:module, l:qu_info[2], 2)
  369. else
  370. call gutentags#trace("Finished ".a:module." job, ".
  371. \"but skipping queued update for '".l:tags_file."' ".
  372. \"because originating buffer doesn't exist anymore.")
  373. endif
  374. else
  375. call gutentags#trace("Finished ".a:module." job.")
  376. endif
  377. endfunction
  378. function! gutentags#remove_job_by_data(module, data) abort
  379. let l:idx = gutentags#find_job_index_by_data(a:module, a:data)
  380. call gutentags#remove_job(a:module, l:idx)
  381. endfunction
  382. " }}}
  383. " Tags File Management {{{
  384. " (Re)Generate the tags file for the current buffer's file.
  385. function! s:manual_update_tags(bang) abort
  386. let l:restore_prev_trace = 0
  387. let l:prev_trace = g:gutentags_trace
  388. if &verbose > 0
  389. let g:gutentags_trace = 1
  390. let l:restore_prev_trace = 1
  391. endif
  392. try
  393. let l:bn = bufnr('%')
  394. for module in g:gutentags_modules
  395. call s:update_tags(l:bn, module, a:bang, 0)
  396. endfor
  397. silent doautocmd User GutentagsUpdating
  398. finally
  399. if l:restore_prev_trace
  400. let g:gutentags_trace = l:prev_trace
  401. endif
  402. endtry
  403. endfunction
  404. " (Re)Generate the tags file for a buffer that just go saved.
  405. function! s:write_triggered_update_tags(bufno) abort
  406. if g:gutentags_enabled && g:gutentags_generate_on_write
  407. for module in g:gutentags_modules
  408. call s:update_tags(a:bufno, module, 0, 2)
  409. endfor
  410. endif
  411. silent doautocmd User GutentagsUpdating
  412. endfunction
  413. " Update the tags file for the current buffer's file.
  414. " write_mode:
  415. " 0: update the tags file if it exists, generate it otherwise.
  416. " 1: always generate (overwrite) the tags file.
  417. "
  418. " queue_mode:
  419. " 0: if an update is already in progress, report it and abort.
  420. " 1: if an update is already in progress, abort silently.
  421. " 2: if an update is already in progress, queue another one.
  422. function! s:update_tags(bufno, module, write_mode, queue_mode) abort
  423. " Figure out where to save.
  424. let l:buf_gutentags_files = getbufvar(a:bufno, 'gutentags_files')
  425. let l:tags_file = l:buf_gutentags_files[a:module]
  426. let l:proj_dir = getbufvar(a:bufno, 'gutentags_root')
  427. " Check that there's not already an update in progress.
  428. let l:in_progress_idx = gutentags#find_job_index_by_tags_file(
  429. \a:module, l:tags_file)
  430. if l:in_progress_idx >= 0
  431. if a:queue_mode == 2
  432. let l:needs_queuing = 1
  433. for qu_info in s:update_queue[a:module]
  434. if qu_info[0] == l:tags_file
  435. let l:needs_queuing = 0
  436. break
  437. endif
  438. endfor
  439. if l:needs_queuing
  440. call add(s:update_queue[a:module],
  441. \[l:tags_file, a:bufno, a:write_mode])
  442. endif
  443. call gutentags#trace("Tag file '" . l:tags_file .
  444. \"' is already being updated. Queuing it up...")
  445. elseif a:queue_mode == 1
  446. call gutentags#trace("Tag file '" . l:tags_file .
  447. \"' is already being updated. Skipping...")
  448. elseif a:queue_mode == 0
  449. echom "gutentags: The tags file is already being updated, " .
  450. \"please try again later."
  451. else
  452. call gutentags#throw("Unknown queue mode: " . a:queue_mode)
  453. endif
  454. " Don't update the tags right now.
  455. return
  456. endif
  457. " Switch to the project root to make the command line smaller, and make
  458. " it possible to get the relative path of the filename to parse if we're
  459. " doing an incremental update.
  460. let l:prev_cwd = getcwd()
  461. call gutentags#chdir(fnameescape(l:proj_dir))
  462. try
  463. call call("gutentags#".a:module."#generate",
  464. \[l:proj_dir, l:tags_file,
  465. \ {
  466. \ 'write_mode': a:write_mode,
  467. \ }])
  468. catch /^gutentags\:/
  469. echom "Error while generating ".a:module." file:"
  470. echom v:exception
  471. finally
  472. " Restore the current directory...
  473. call gutentags#chdir(fnameescape(l:prev_cwd))
  474. endtry
  475. endfunction
  476. " }}}
  477. " Utility Functions {{{
  478. function! gutentags#rescan(...)
  479. if exists('b:gutentags_files')
  480. unlet b:gutentags_files
  481. endif
  482. if a:0 && a:1
  483. let l:trace_backup = g:gutentags_trace
  484. let l:gutentags_trace = 1
  485. endif
  486. call gutentags#setup_gutentags()
  487. if a:0 && a:1
  488. let g:gutentags_trace = l:trace_backup
  489. endif
  490. endfunction
  491. function! gutentags#toggletrace(...)
  492. let g:gutentags_trace = !g:gutentags_trace
  493. if a:0 > 0
  494. let g:gutentags_trace = a:1
  495. endif
  496. if g:gutentags_trace
  497. echom "gutentags: Tracing is enabled."
  498. else
  499. echom "gutentags: Tracing is disabled."
  500. endif
  501. echom ""
  502. endfunction
  503. function! gutentags#fake(...)
  504. let g:gutentags_fake = !g:gutentags_fake
  505. if a:0 > 0
  506. let g:gutentags_fake = a:1
  507. endif
  508. if g:gutentags_fake
  509. echom "gutentags: Now faking gutentags."
  510. else
  511. echom "gutentags: Now running gutentags for real."
  512. endif
  513. echom ""
  514. endfunction
  515. function! gutentags#default_io_cb(chan, msg) abort
  516. call gutentags#trace('[job output]: '.string(a:msg))
  517. endfunction
  518. if has('nvim')
  519. " Neovim job API.
  520. function! s:nvim_job_exit_wrapper(real_cb, job, exit_code, event_type) abort
  521. call call(a:real_cb, [a:job, a:exit_code])
  522. endfunction
  523. function! s:nvim_job_out_wrapper(real_cb, job, lines, event_type) abort
  524. call call(a:real_cb, [a:job, a:lines])
  525. endfunction
  526. function! gutentags#build_default_job_options(module) abort
  527. " Neovim kills jobs on exit, which is what we want.
  528. let l:job_opts = {
  529. \'on_exit': function(
  530. \ '<SID>nvim_job_exit_wrapper',
  531. \ ['gutentags#'.a:module.'#on_job_exit']),
  532. \'on_stdout': function(
  533. \ '<SID>nvim_job_out_wrapper',
  534. \ ['gutentags#default_io_cb']),
  535. \'on_stderr': function(
  536. \ '<SID>nvim_job_out_wrapper',
  537. \ ['gutentags#default_io_cb'])
  538. \}
  539. return l:job_opts
  540. endfunction
  541. function! gutentags#start_job(cmd, opts) abort
  542. return jobstart(a:cmd, a:opts)
  543. endfunction
  544. else
  545. " Vim8 job API.
  546. function! gutentags#build_default_job_options(module) abort
  547. let l:job_opts = {
  548. \'exit_cb': 'gutentags#'.a:module.'#on_job_exit',
  549. \'out_cb': 'gutentags#default_io_cb',
  550. \'err_cb': 'gutentags#default_io_cb',
  551. \'stoponexit': 'term'
  552. \}
  553. return l:job_opts
  554. endfunction
  555. function! gutentags#start_job(cmd, opts) abort
  556. return job_start(a:cmd, a:opts)
  557. endfunction
  558. endif
  559. " Returns which modules are currently generating something for the
  560. " current buffer.
  561. function! gutentags#inprogress()
  562. " Does this buffer have gutentags enabled?
  563. if !exists('b:gutentags_files')
  564. return []
  565. endif
  566. " Find any module that has a job in progress for any of this buffer's
  567. " tags files.
  568. let l:modules_in_progress = []
  569. for [module, tags_file] in items(b:gutentags_files)
  570. let l:jobidx = gutentags#find_job_index_by_tags_file(module, tags_file)
  571. if l:jobidx >= 0
  572. call add(l:modules_in_progress, module)
  573. endif
  574. endfor
  575. return l:modules_in_progress
  576. endfunction
  577. " }}}
  578. " Statusline Functions {{{
  579. " Prints whether a tag file is being generated right now for the current
  580. " buffer in the status line.
  581. "
  582. " Arguments can be passed:
  583. " - args 1 and 2 are the prefix and suffix, respectively, of whatever output,
  584. " if any, is going to be produced.
  585. " (defaults to empty strings)
  586. " - arg 3 is the text to be shown if tags are currently being generated.
  587. " (defaults to the name(s) of the modules currently generating).
  588. function! gutentags#statusline(...) abort
  589. let l:modules_in_progress = gutentags#inprogress()
  590. if empty(l:modules_in_progress)
  591. return ''
  592. endif
  593. let l:prefix = ''
  594. let l:suffix = ''
  595. if a:0 > 0
  596. let l:prefix = a:1
  597. endif
  598. if a:0 > 1
  599. let l:suffix = a:2
  600. endif
  601. if a:0 > 2
  602. let l:genmsg = a:3
  603. else
  604. let l:genmsg = join(l:modules_in_progress, ',')
  605. endif
  606. return l:prefix.l:genmsg.l:suffix
  607. endfunction
  608. " Same as `gutentags#statusline`, but the only parameter is a `Funcref` or
  609. " function name that will get passed the list of modules currently generating
  610. " something. This formatter function should return the string to display in
  611. " the status line.
  612. function! gutentags#statusline_cb(fmt_cb, ...) abort
  613. let l:modules_in_progress = gutentags#inprogress()
  614. if (a:0 == 0 || !a:1) && empty(l:modules_in_progress)
  615. return ''
  616. endif
  617. return call(a:fmt_cb, [l:modules_in_progress])
  618. endfunction
  619. " }}}