How to automatically update tag file in vim?

2019-03-07 19:57发布

问题:

I use vim C++ tag file for navigation using Ctrl-]. The problem is whenever some file gets modified, the links are no longer valid and I have to re-run ctags and update the tag file. Our code base is huge and it takes quite a while for generating tag file.

Is there any tool which periodically updates the tag file in background? Can I configure VIM to do the same?

I use gvim under Windows.

回答1:

Further to Blixtor's answer, you'll need to think a little carefully about the design of the script. I'd recommend segregating the design such that the autocommand uses the Windows "start" command or similar to run an external script in the background: thereby preventing Vim from being unresponsive while the tag file is generated.

That script could then generate the tag file using a different file name (i.e. not "tags": ctags -R -o newtags .) and, when ctags is complete, delete tags and rename newtags to tags. This will prevent the tag file from being unavailable in Vim while the generation is done.



回答2:

I wrote the vim-easytags plug-in to do exactly this. I initialize my tags file once by scanning a whole project (using the command :UpdateTags **/*.[hc] for example) and afterwards the plug-in will automatically update the tags file as I edit and :update my source code files in Vim. While it updates the tags file it will block Vim, but because it only scans the current file it doesn't take long.

Update (2014-07-30): Still working on the vim-easytags plug-in :-). Nowadays it supports an asynchronous mode to avoid blocking Vim. At the time I write this the asynchronous mode is not the default mode yet, but after some more feedback I'll probably switch the default mode.



回答3:

I already wrote a plugin to do all the hard job with ctags: Indexer.

It provides painless automatic tags generation for the whole project(s) and keeps tags up-to-date. Tags is generated in background, so, you do not have to wait while ctags generates tags. You can use it independently or as an add-on for another plugin project.tar.gz.

In the first way, you can declare your projects in ~/.indexer_files like this:

[CoolProject]

/home/user/cool_project

[AnotherProject]
option:ctags_params = "--languages=c++"

/home/user/another_project/src
/home/user/another_project/lib 

And then, when you open any file from /home/user/cool_project , all this project will be indexed by ctags. When you open tags from another project, tags is generated for it too. Tags from different projects is never mixed. When you save file from project, tags is silently updated. You do not have to care about it, it just works.

For detailed information, see the article: Vim: convenient code navigation for your projects, which explains the usage of Indexer + Vimprj thoroughly.

It is successfully tested on Vim 7.3, on the following systems:

  • Archlinux

  • Ubuntu 10.4

  • Windows XP

  • Mac OS X Lion



回答4:

An idea:

Use Vim autocommands (:help autocommand) to trigger running of a script every time a buffer is saved using the BufWritePost event.

This script starts the ctags generation and contains some additional small logic to not run while it's already running (or to run at most every 10 minutes, etc.).

Edit:

Something similar was asked here beforehand, see Vim auto-generate ctags



回答5:

From its repository: vim-gutentags is a plugin that takes care of the much needed management of tags files in Vim. It will (re)generate tag files as you work while staying completely out of your way. It will even do its best to keep those tag files out of your way too. It has no dependencies and just works.

You can give it a try at https://github.com/ludovicchabant/vim-gutentags.



回答6:

This logic works for most cases: When opening a new file in vim, change to the directory of that file and generate a tags file there if it does not already exist. When saving a changed buffer, generate a tags file in the directory of the file being saved:


function! GenerateTagsFile()
  if (!filereadable("tags"))
    exec ":!start /min ctags -R --c++-kinds=+p --fields=+iaS --extra=+q --sort=foldcase ."
  endif
endfunction

" Always change to directory of the buffer currently in focus.
autocmd! bufenter *.* :cd %:p:h
autocmd! bufread  *.* :cd %:p:h

" Generate tags on opening an existing file.
autocmd! bufreadpost *.cpp :call GenerateTagsFile()
autocmd! bufreadpost *.c   :call GenerateTagsFile()
autocmd! bufreadpost *.h   :call GenerateTagsFile()

" Generate tags on save. Note that this regenerates tags for all files in current folder.
autocmd! bufwritepost *.cpp :call GenerateTagsFile()
autocmd! bufwritepost *.c   :call GenerateTagsFile()
autocmd! bufwritepost *.h   :call GenerateTagsFile()


回答7:

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

function! DelTagOfFile(file)
  let fullpath = a:file
  let cwd = getcwd()
  let tagfilename = cwd . "/tags"
  let f = substitute(fullpath, cwd . "/", "", "")
  let f = escape(f, './')
  let cmd = 'sed -i "/' . f . '/d" "' . tagfilename . '"'
  let resp = system(cmd)
endfunction

function! UpdateTags()
  let f = expand("%:p")
  let cwd = getcwd()
  let tagfilename = cwd . "/tags"
  let cmd = 'ctags -a -f ' . tagfilename . ' --c++-kinds=+p --fields=+iaS --extra=+q ' . '"' . f . '"'
  call DelTagOfFile(f)
  let resp = system(cmd)
endfunction
autocmd BufWritePost *.cpp,*.h,*.c call UpdateTags()


标签: vim ctags