~gpanders/dotfiles

81c5cb060ee6dbfa6f41add80662f973dd6fea60 — Greg Anders 19 days ago b7152c8
vim: create C/C++ tags per file

I think this will be a much better solution because it only creates tags
for header files used in the actual source file. This means we have to
re-create the tags files often as headers are added/removed, but since
it's done asynchronously I don't think it's a big deal. This is better
than the prior solution which generated a single enormous tags file for
all of the system headers -- this made looking for tags slow and made
tag completion unusable.
2 files changed, 27 insertions(+), 17 deletions(-)

M .vim/after/ftplugin/c.vim
M .vim/autoload/ft/c.vim
M .vim/after/ftplugin/c.vim => .vim/after/ftplugin/c.vim +9 -1
@@ 16,7 16,15 @@ setlocal comments+=:///,://
" Set path
call ft#c#set_path()

let b:undo_ftplugin .= '|setl cms< def< inc< inex< path< tw< com<'
" Create and set tags file
call ft#c#tags(v:false)

augroup ftplugin_c
  autocmd!
  autocmd BufWritePost <buffer> call ft#c#tags(v:true)
augroup END

let b:undo_ftplugin .= '|setl cms< def< inc< inex< path< tw< com<|au! ftplugin_c'

" Use improved :Man command as keywordprg
if exists(':Man') == 2

M .vim/autoload/ft/c.vim => .vim/autoload/ft/c.vim +18 -16
@@ 25,26 25,28 @@ function! s:path(ft) abort
  " Ensure directory of current file is always first on the path
  setlocal path-=.
  setlocal path^=.

  " Add tags file for compiler
  call s:tags(a:ft)
endfunction

function! s:tags(ft) abort
  let compiler = a:ft ==# 'cpp' ? s:cxx : s:cc
  let machine = systemlist(compiler . ' -dumpmachine')[0]
  let tagfile = vim#cachedir() . '/tags.' . machine
  let &l:tags .= ',' . tagfile

  if !filereadable(tagfile)
    let cmd = ['ctags', '-R', '-o', tagfile] + split(g:{a:ft}_path, ',')
    if a:ft ==# 'c'
        let cmd += ['--c-kinds=+p', '--langmap=c:.h', '--languages=c']
function! ft#c#tags(update) abort
  let compiler = &filetype ==# 'cpp' ? s:cxx : s:cc
  let tagfile = vim#cachedir() . '/tags/' . substitute(expand('%:p'), '/', '%', 'g') . '.tags'
  execute 'setlocal tags+=' . tagfile
  let &l:tags = join(uniq(split(&l:tags, ',')), ',')

  if !filereadable(tagfile) || a:update
    call mkdir(fnamemodify(tagfile, ':h'), 'p')
    let cmd = [compiler, '-M', '-I', 'include', expand('%'),
                \ '|', 'awk', '''gsub(" ", "\n")''',
                \ '|', 'sed', '-e', '''/^\//!d''', '-e', '''/^\\*\s*$/d''',
                \ '|', 'ctags', '-L', '-', '-o', tagfile]
    if &filetype ==# 'c'
      let cmd += ['--c-kinds=+px', '--langmap=c:+.h', '--languages=c']
    else
        let cmd += ['--c++-kinds=+p', '--languages=c++']
      let cmd += ['--c++-kinds=+px', '--extras=+q', '--language-force=c++', '--languages=c++']
    endif
    let cmd += split(g:{a:ft}_path, ',')
    call async#run(cmd, '')

    let fullcmd = split(&shell) + split(&shellcmdflag) + [join(cmd)]
    call async#run(fullcmd, '')
  endif
endfunction