Vim auto-generate ctags

前端 未结 12 1849
醉话见心
醉话见心 2020-11-29 16:18

Right now I have the following in my .vimrc:

au BufWritePost *.c,*.cpp,*.h !ctags -R

There are a few problems with this:

相关标签:
12条回答
  • 2020-11-29 17:03

    Auto Tag is a vim plugin that updates existing tag files on save.

    I've been using it for years without problems, with the exception that it enforces a maximum size on the tags files. Unless you have a really large set of code all indexed in the same tags file, you shouldn't hit that limit, though.

    Note that Auto Tag requires Python support in vim.

    0 讨论(0)
  • 2020-11-29 17:06

    I've noticed this is an old thread, however... Use incron in *nix like environments supporting inotify. It will always launch commands whenever files in a directory change. i.e.,

    /home/me/Code/c/that_program IN_DELETE,IN_CLOSE_WRITE ctags --sort=yes *.c
    

    That's it.

    0 讨论(0)
  • 2020-11-29 17:09

    On OSX this command will not work out of the box, at least not for me.

    au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
    

    I found a post, which explains how to get the standard ctags version that contains the -R option. This alone did not work for me. I had to add /usr/local/bin to the PATH variable in .bash_profile in order to pick up the bin where Homebrew installs programs.

    0 讨论(0)
  • 2020-11-29 17:10

    The --append option is indeed the way to go. Used with a grep -v, we can update only one tagged file. For instance, here is a excerpt of an unpolished plugin that addresses this issue. (NB: It will require an "external" library plugin)

    " Options {{{1
    let g:tags_options_cpp = '--c++-kinds=+p --fields=+imaS --extra=+q'
    
    function! s:CtagsExecutable()
      let tags_executable = lh#option#Get('tags_executable', s:tags_executable, 'bg')
      return tags_executable
    endfunction
    
    function! s:CtagsOptions()
      let ctags_options = lh#option#Get('tags_options_'.&ft, '')
      let ctags_options .= ' '.lh#option#Get('tags_options', '', 'wbg')
      return ctags_options
    endfunction
    
    function! s:CtagsDirname()
      let ctags_dirname = lh#option#Get('tags_dirname', '', 'b').'/'
      return ctags_dirname
    endfunction
    
    function! s:CtagsFilename()
      let ctags_filename = lh#option#Get('tags_filename', 'tags', 'bg')
      return ctags_filename
    endfunction
    
    function! s:CtagsCmdLine(ctags_pathname)
      let cmd_line = s:CtagsExecutable().' '.s:CtagsOptions().' -f '.a:ctags_pathname
      return cmd_line
    endfunction
    
    
    " ######################################################################
    " Tag generating functions {{{1
    " ======================================================================
    " Interface {{{2
    " ======================================================================
    " Mappings {{{3
    " inoremap <expr> ; <sid>Run('UpdateTags_for_ModifiedFile',';')
    
    nnoremap <silent> <Plug>CTagsUpdateCurrent :call <sid>UpdateCurrent()<cr>
    if !hasmapto('<Plug>CTagsUpdateCurrent', 'n')
      nmap <silent> <c-x>tc  <Plug>CTagsUpdateCurrent
    endif
    
    nnoremap <silent> <Plug>CTagsUpdateAll     :call <sid>UpdateAll()<cr>
    if !hasmapto('<Plug>CTagsUpdateAll', 'n')
      nmap <silent> <c-x>ta  <Plug>CTagsUpdateAll
    endif
    
    
    " ======================================================================
    " Auto command for automatically tagging a file when saved {{{3
    augroup LH_TAGS
      au!
      autocmd BufWritePost,FileWritePost * if ! lh#option#Get('LHT_no_auto', 0) | call s:Run('UpdateTags_for_SavedFile') | endif
    aug END
    
    " ======================================================================
    " Internal functions {{{2
    " ======================================================================
    " generate tags on-the-fly {{{3
    function! UpdateTags_for_ModifiedFile(ctags_pathname)
      let source_name    = expand('%')
      let temp_name      = tempname()
      let temp_tags      = tempname()
    
      " 1- purge old references to the source name
      if filereadable(a:ctags_pathname)
        " it exists => must be changed
        call system('grep -v "  '.source_name.' " '.a:ctags_pathname.' > '.temp_tags.
          \ ' && mv -f '.temp_tags.' '.a:ctags_pathname)
      endif
    
      " 2- save the unsaved contents of the current file
      call writefile(getline(1, '$'), temp_name, 'b')
    
      " 3- call ctags, and replace references to the temporary source file to the
      " real source file
      let cmd_line = s:CtagsCmdLine(a:ctags_pathname).' '.source_name.' --append'
      let cmd_line .= ' && sed "s#\t'.temp_name.'\t#\t'.source_name.'\t#" > '.temp_tags
      let cmd_line .= ' && mv -f '.temp_tags.' '.a:ctags_pathname
      call system(cmd_line)
      call delete(temp_name)
    
      return ';'
    endfunction
    
    " ======================================================================
    " generate tags for all files {{{3
    function! s:UpdateTags_for_All(ctags_pathname)
      call delete(a:ctags_pathname)
      let cmd_line  = 'cd '.s:CtagsDirname()
      " todo => use project directory
      "
      let cmd_line .= ' && '.s:CtagsCmdLine(a:ctags_pathname).' -R'
      echo cmd_line
      call system(cmd_line)
    endfunction
    
    " ======================================================================
    " generate tags for the current saved file {{{3
    function! s:UpdateTags_for_SavedFile(ctags_pathname)
      let source_name    = expand('%')
      let temp_tags      = tempname()
    
      if filereadable(a:ctags_pathname)
        " it exists => must be changed
        call system('grep -v "  '.source_name.' " '.a:ctags_pathname.' > '.temp_tags.' && mv -f '.temp_tags.' '.a:ctags_pathname)
      endif
      let cmd_line = 'cd '.s:CtagsDirname()
      let cmd_line .= ' && ' . s:CtagsCmdLine(a:ctags_pathname).' --append '.source_name
      " echo cmd_line
      call system(cmd_line)
    endfunction
    
    " ======================================================================
    " (public) Run a tag generating function {{{3
    function! LHTagsRun(tag_function)
      call s:Run(a:tag_function)
    endfunction
    
    " ======================================================================
    " (private) Run a tag generating function {{{3
    " See this function as a /template method/.
    function! s:Run(tag_function)
      try
        let ctags_dirname  = s:CtagsDirname()
        if strlen(ctags_dirname)==1
          throw "tags-error: empty dirname"
        endif
        let ctags_filename = s:CtagsFilename()
        let ctags_pathname = ctags_dirname.ctags_filename
        if !filewritable(ctags_dirname) && !filewritable(ctags_pathname)
          throw "tags-error: ".ctags_pathname." cannot be modified"
        endif
    
        let Fn = function("s:".a:tag_function)
        call Fn(ctags_pathname)
      catch /tags-error:/
        " call lh#common#ErrorMsg(v:exception)
        return 0
      finally
      endtry
    
      echo ctags_pathname . ' updated.'
      return 1
    endfunction
    
    function! s:Irun(tag_function, res)
      call s:Run(a:tag_function)
      return a:res
    endfunction
    
    " ======================================================================
    " Main function for updating all tags {{{3
    function! s:UpdateAll()
      let done = s:Run('UpdateTags_for_All')
    endfunction
    
    " Main function for updating the tags from one file {{{3
    " @note the file may be saved or "modified".
    function! s:UpdateCurrent()
      if &modified
        let done = s:Run('UpdateTags_for_ModifiedFile')
      else
        let done = s:Run('UpdateTags_for_SavedFile')
      endif
    endfunction
    

    This code defines:

    • ^Xta to force the update of the tags base for all the files in the current project ;
    • ^Xtc to force the update of the tags base for the current (unsaved) file ;
    • an autocommand that updates the tags base every time a file is saved ; and it supports and many options to disable the automatic update where we don't want it, to tune ctags calls depending on filetypes, ... It is not just a tip, but a small excerpt of a plugin.

    HTH,

    0 讨论(0)
  • 2020-11-29 17:15

    Perhaps use the append argument to ctags as demonstrated by:

    http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file

    I can't really vouch for this as I generally use source insight for code browsing, but use vim as an editor... go figure.

    0 讨论(0)
  • 2020-11-29 17:16

    au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &

    The downside is that you won't have a useful tags file until it completes. As long as you're on a *nix system it should be ok to do multiple writes before the previous ctags has completed, but you should test that. On a Windows system it won't put it in the background and it'll complain that the file is locked until the first ctags finishes (which shouldn't cause problems in vim, but you'll end up with a slightly outdated tags file).

    Note, you could use the --append option as tonylo suggests, but then you'll have to disable tagbsearch which could mean that tag searches take a lot longer, depending on the size of your tag file.

    0 讨论(0)
提交回复
热议问题