【发布时间】:2010-11-12 13:06:39
【问题描述】:
我使用 vim C++ 标记文件使用 Ctrl-] 进行导航。问题是每当修改某些文件时,链接不再有效,我必须重新运行 ctags 并更新标记文件。我们的代码库很大,生成标签文件需要相当长的时间。
是否有任何工具可以在后台定期更新标签文件?我可以配置 VIM 来做同样的事情吗?
我在 Windows 下使用 gvim。
【问题讨论】:
我使用 vim C++ 标记文件使用 Ctrl-] 进行导航。问题是每当修改某些文件时,链接不再有效,我必须重新运行 ctags 并更新标记文件。我们的代码库很大,生成标签文件需要相当长的时间。
是否有任何工具可以在后台定期更新标签文件?我可以配置 VIM 来做同样的事情吗?
我在 Windows 下使用 gvim。
【问题讨论】:
除了 Blixtor 的回答之外,您还需要仔细考虑脚本的设计。我建议分离设计,以便自动命令使用 Windows“启动”命令或类似命令在在后台运行外部脚本:从而防止 Vim 在生成标记文件时无响应。
然后,该脚本可以使用不同的文件名(即不是“标签”:ctags -R -o newtags .)生成标签文件,并且当 ctags 完成时,删除 tags 并将 newtags 重命名为 tags。这将防止标签文件在生成完成时在 Vim 中不可用。
【讨论】:
我写了vim-easytags 插件就是为了做到这一点。我通过扫描整个项目来初始化我的标签文件一次(例如使用命令:UpdateTags **/*.[hc]),然后插件将在我编辑时自动更新标签文件和:update我在Vim中的源代码文件。虽然它会更新标签文件,但它会阻止 Vim,但因为它只扫描当前文件,所以不会花费很长时间。
更新 (2014-07-30): 仍在开发 vim-easytags 插件 :-)。现在它支持异步模式以避免阻塞 Vim。在我写这篇文章的时候,异步模式还不是默认模式,但是在更多的反馈之后我可能会切换默认模式。
【讨论】:
我已经编写了一个插件来使用 ctags 完成所有艰巨的工作:Indexer。
它为整个项目提供了无痛的自动标签生成,并使标签保持最新。标签是在后台生成的,因此,您不必等待 ctags 生成标签。您可以独立使用它,也可以作为另一个插件的附加组件project.tar.gz。
在第一种方式中,您可以像这样在~/.indexer_files 中声明您的项目:
[CoolProject]
/home/user/cool_project
[AnotherProject]
option:ctags_params = "--languages=c++"
/home/user/another_project/src
/home/user/another_project/lib
然后,当您从 /home/user/cool_project 打开任何文件时,所有该项目都将被 ctags 索引。当您从另一个项目打开标签时,也会为其生成标签。来自不同项目的标签永远不会混合。当您从项目中保存文件时,标签会静默更新。你不必关心它,它只是工作。
详细内容请看文章:Vim: convenient code navigation for your projects,详细讲解Indexer + Vimprj的使用方法。
已在 Vim 7.3 上成功测试,在以下系统上:
Archlinux
Ubuntu 10.4
Windows XP
Mac OS X Lion
【讨论】:
一个想法:
每次使用 BufWritePost 事件保存缓冲区时,使用 Vim 自动命令 (:help autocommand) 触发脚本运行。
此脚本启动 ctags 生成并包含一些额外的小逻辑,在它已经运行时不运行(或最多每 10 分钟运行一次等)。
编辑:
之前在这里询问过类似的问题,请参阅Vim auto-generate ctags
【讨论】:
来自它的存储库:vim-gutentags 是一个插件,负责管理 Vim 中非常需要的标签文件。它会在您工作时(重新)生成标记文件,同时完全不妨碍您。它甚至会尽最大努力让这些标签文件远离你。它没有依赖关系,可以正常工作。
【讨论】:
这个逻辑适用于大多数情况:当在 vim 中打开一个新文件时,切换到该文件的目录并在那里生成一个标签文件,如果它不存在的话。保存更改的缓冲区时,在保存文件的目录下生成标签文件:
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()
【讨论】:
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()
【讨论】: