Vim自动生成ctags

现在我的.vimrc有以下内容:

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

这有几个问题:

  1. 这很慢 – 重新生成自上次生成代码以来没有改变的文件的标签。
  2. 写入文件之后,我必须再次按下回车button因为不可避免会出现“按Enter或键入命令继续”的提示。

当你把这两个问题结合在一起时,我最终推迟了额外的input(在ctags -R完成之前),然后看到令人讨厌的错误信息,并且不得不再次input。

我知道这听起来不是什么大不了的事情,但是在特定的日子里,我所做的文件写入量往往会变得非常烦人。 有一个更好的方法来做到这一点!

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

不足之处在于,在完成之前,您将不会拥有有用的标签文件。 只要你在一个* nix系统上,应该可以在前面的ctags完成之前做多个写操作,但是你应该testing一下。 在Windows系统上,它不会把它放在后台,它会抱怨文件被locking,直到第一个ctags完成(这不应该在vim中造成问题,但是最终会有一个过时的标签文件)。

注意,你可以像tonylo所说的那样使用--append选项,但是你必须禁用tagbsearch ,这可能意味着标签search需要更长的时间,这取决于你的标签文件的大小。

编辑 :非常多的解决scheme已经发布为AutoTag vim脚本 。 请注意,脚本需要支持Python的vim ,但是。

我的解决scheme取而代之的awk,所以它应该在更多的系统上工作。


 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 

请注意,您只能以脚本方式将其写入,否则必须单行写入。

那里有很多东西:

  1. 当检测到文件为C或C ++时,此自动命令触发,并依次添加由BufWritePost事件触发的缓冲区本地自动命令。

  2. 它使用在执行时被缓冲区文件名replace的%占位符,以及用于shell引用文件名的:gs修饰符(通过将任何embedded的单引号转换为quote-escape-quote-quote)。

  3. 那样的话,它会运行一个shell命令来检查一个tags文件是否存在,在这种情况下,除了引用刚刚保存的文件的行之外,其内容将被打印,同时ctags仅在刚刚保存的文件上被调用,结果然后被sort并放回原处。

Caveat实现者:这里假定一切都在同一个目录下,并且也是当前缓冲区的目录。 我没有想到path的修改。

我写了easytags.vim来做到这一点:自动更新和突出显示标签。 该插件可以configuration为只更新正在编辑的文件或正在编辑的文件的目录中的所有文件(recursion)。 它可以使用全局标签文件,文件types特定标签文件和项目特定标签文件。

我注意到这是一个古老的线程,但是…使用incron在* nix像支持inotify的环境。 只要目录中的文件发生更改,它就会始终启动命令。 即

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

而已。

也许使用ctags的append参数如下所示:

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

我不能真正保证这一点,因为我通常使用源代码洞察代码浏览,但使用vim作为编辑器…去图。

如何计划通过crontab运行ctags? 如果你的项目树在结构上相当稳定,那应该可行吗?

要禁止“按回车”提示,请使用:silent 。

在OSX上,这个命令不会起作用,至less不适合我。

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

我find了一篇文章 ,解释了如何获得包含-R选项的标准ctags版本。 这本身并不适合我。 我必须将/ usr / local / bin添加到.bash_profile中的PATHvariables,以便获取Homebrew安装程序的bin。

在我的opninion中,插件Indexer是更好的。

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

有可能:

1)project.tar.gz的附加组件

2)独立的插件

  • 背景标签生成(你没有等待,而ctags的作品)
  • 支持多个项目

有一个叫做AutoTag的vim插件可以很好地工作。

如果你安装了taglist,它也会为你更新。

--append选项的确是要走的路。 与grep -v ,我们只能更新一个标记文件。 例如,下面是一个解决这个问题的未经处理的插件的摘录。 (注意:这将需要一个“外部” 库插件 )

 " 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 

此代码定义:

  • ^Xta强制更新当前项目中所有文件的标签基础;
  • ^Xtc强制更新当前(未保存)文件的标签基础;
  • 每次保存文件时都会自动更新标签的自动命令; 它支持和许多选项,以禁用自动更新,我们不希望它,根据文件types调整标签调用,…这不只是一个提示,而是一个插件的一小段摘录。

HTH,

Auto Tag是一个vim插件,可以在保存时更新现有的标签文件。

我一直在使用它没有问题,除了强制标签文件的最大尺寸。 除非你有一大堆代码都在相同的标签文件中被索引,否则你不应该达到这个限制。

请注意,Auto Tag需要vim中的Python支持。