Vim automatically generates ctags

I now have the following in .vimrc :

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

There are several issues with this:

  • It is slow - it regenerates tags for files that have not changed since the last tag was created.
  • I need to press the enter button again after writing the file due to the inevitable "press Enter or enter a command to continue."

When you combine these two problems, I end up pushing extra input too soon (until ctags -R completes), then see the annoying error message and press Enter again.

I know this doesn't seem like a big deal, but with the volume of files that I'm doing on a given day, it becomes very annoying. There must be a better way to do this!

+51
vim autocomplete ctags
Sep 30 '08 at 22:47
source share
12 answers

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

The disadvantage is that you will not have a useful tag file until its completion. While you are on * nix, it should be nice to make a few entries before the previous ctags have completed, but you should check this out. On Windows, it will not be placed in the background, and it will complain that the file is locked until the first ctags ends (which should not cause problems in vim, but in the end you will get a slightly outdated tag file).

Please note: you can use the --append option, as tonylo suggests, but then you have to disable tagbsearch , which may mean that searching for tags takes a lot longer, depending on the size of your tag file.

+41
Sep 30 '08 at 23:05
source share

Change A solution very similar to the following lines was published as an AutoTag vim script . Note that the script requires vim with Python support .

My solution disables awk instead, so it should work on many other systems.




 au FileType {c,cpp} au BufWritePost <buffer> silent ! [ -e tags ] && \ ( awk -F'\t' '$2\!="%:gs/'/'\''/"{print}' tags ; ctags -f- '%:gs/'/'\''/' ) \ | sort -t$'\t' -k1,1 -o tags.new && mv tags.new tags 

Please note that you can write it only in a script, otherwise it should go on one line.

Many events take place there:

  • This automatic command starts when the file was detected as C or C ++, and in turn adds a local automatic buffer command, which is triggered by the BufWritePost event.

  • It uses placeholder % , which is replaced by the name of the buffer file at runtime with the modifier :gs used for shell-quote filename (by turning any built-in single quotes into the escape code of the -quote quote).

  • Thus, it runs a shell command that checks for the presence of the tags file, and in this case its contents are printed, except for lines related to the just saved file, meanwhile ctags is called just the saved file, and the result is then sort ed and inserted into place .

Caveat Developer: this assumes everything is in the same directory and this is also the local current directory. I did not think about the confusion.

+13
02 Oct. '08 at 20:25
source share

I wrote easytags.vim to do this: automatically update and highlight tags. The plugin can be configured to update only the edited file or all files in the directory of the edited file (recursively). It can use global tag files, tag files with specific tags, and tag files for specific projects.

+10
Jan 14 '12 at 23:14
source share

I noticed that this is an old thread, however ... Use incron in * nix-like environments that support inotify. It always runs commands whenever files in a directory change. i.e.,

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

What is it.

+7
Nov 30 '10 at 5:46 a.m.
source share

Perhaps use the append argument for ctags, as shown in the figure:

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

I really can't vouch for this, since I usually use the source view to view the code, but use vim as the editor ... go figure.

+3
Sep 30 '08 at 23:01
source share

How about ctags being planned to run through crontab? If your project tree is pretty stable in it, should this be doable?

+2
Sep 30 '08 at 22:55
source share

To suppress the "press enter" prompt, use : silent .

+2
Sep 30 '08 at 23:03
source share

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 explaining how to get the standard version of ctags containing the -R option. Only it did not help me. I had to add / usr / local / bin to the PATH variable in .bash_profile to pick up bin, where Homebrew installs the programs.

+2
Sep 01 '11 at 10:45
source share

The --append option --append really a way. When using grep -v we can only update one tagged file. For example, here is a fragment of an unpolished plugin that solves this problem. (NB: this 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> <cx>tc <Plug>CTagsUpdateCurrent endif nnoremap <silent> <Plug>CTagsUpdateAll :call <sid>UpdateAll()<cr> if !hasmapto('<Plug>CTagsUpdateAll', 'n') nmap <silent> <cx>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 update the tag database for all files in the current project;
  • ^Xtc to force update the tag database for the current (unsaved) file;
  • an auto command that updates the tag database every time a file is saved; and it supports many options to turn off automatic updates where we don’t want to, configure ctags calls depending on file types ... This is not only a hint, but also a small piece of the plugin.

NTN

+1
Oct 01 '08 at 9:01
source share

There is a vim plugin called AutoTag that works very well.

If you have taglist installed, it will also update it for you.

+1
Feb 10 2018-11-21T00:
source share

In my experience, it is better to use the Indexer plugin.

http://www.vim.org/scripts/script.php?script_id=3221

It could be:

1) add-in for project.tar.gz

2) independent plugin

  • background tag generation (you don't wait while ctags is running)
  • support for multiple projects
+1
Mar 26 '11 at 9:45
source share

Auto Tag is a vim plugin that updates existing tag files when saved.

I have been using it for many years without any problems, except that it provides the maximum size in tag files. Unless you have a really large set of code, all indexed in a single tag file, you should not hit that limit.

Note that auto tag requires Python support in vim.

0
Oct 26 '11 at 10:15
source share



All Articles