Vim自动生成标签
现在,我的.vimrc
中包含以下内容:
au BufWritePost *.c,*.cpp,*.h !ctags -R
这有一些问题:
- 速度很慢-重新生成自上次标记生成以来未更改的文件的标记。
- 由于不可避免的"按Enter或者键入命令以继续",我必须在写入文件后再次按Enter键。
当我们将这两个问题结合在一起时,我最终会过早按下添加的Enter键(在ctags -R
完成之前),然后看到烦人的错误消息,并且必须再次按下Enter键。
我知道这听起来没什么大不了的,但是由于我在某一天进行的文件写入数量很大,所以这确实很烦人。一定有更好的方法来做到这一点!
解决方案
如何安排ctags通过crontab运行?如果项目树的结构相当稳定,那应该可行吗?
也许对ctags使用append参数,如下所示:
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file
我真的不能保证这一点,因为我通常使用源代码见解进行代码浏览,但是将vim用作编辑器……如图。
要取消显示"按Enter"提示,请使用:silent。
au BufWritePost * .c,*。cpp,*。h保持沉默! !ctags -R&
不利的一面是,在文件完成之前,我们将没有有用的标签文件。只要我们在* nix系统上,就可以在以前的ctags完成之前进行多次写入,但是我们应该对此进行测试。在Windows系统上,它不会放在后台,并且会抱怨文件被锁定,直到第一个ctags完成(这不会在vim中引起问题,但最终会得到一个稍微过时的标签文件) )。
请注意,我们可以按照tonylo的建议使用--append选项,但随后必须禁用tagbsearch,这可能意味着标签搜索需要更长的时间,具体取决于标签文件的大小。
--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> <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
该代码定义:
^ Xta
强制更新当前项目中所有文件的标签库;^ Xtc
强制更新当前(未保存)文件的标签库;- 一个自动命令,每次保存文件时更新标签基础;它支持许多选项,可在不需要的地方禁用自动更新,根据文件类型调整ctags调用,...这不仅是技巧,而且是插件的一小部分摘录。
HTH,
编辑:非常符合以下内容的解决方案已作为AutoTag vim脚本发布。请注意,该脚本需要带有Python支持的vim。
我的解决方案改为使用awk,因此它应该可以在更多系统上使用。
au FileType {c,cpp} au BufWritePost <buffer> silent ! [ -e tags ] && \ ( awk -F'\t' '\!="%:gs/'/'\''/"{print}' tags ; ctags -f- '%:gs/'/'\''/' ) \ | sort -t$'\t' -k1,1 -o tags.new && mv tags.new tags
请注意,我们只能以这种方式在脚本中编写它,否则它必须在一行上。
那里发生了很多事情:
- 当检测到文件为C或者C ++时,此自动命令将触发,并依次添加由
BufWritePost
事件触发的本地缓冲区自动命令。 - 它使用
%
占位符,该占位符在执行时被缓冲区文件名替换,并使用:gs
修饰符来对文件名进行外壳引用(通过将任何嵌入的单引号转换为quote-escape-quote-quote) 。 - 这样,它运行一个shell命令,检查一个
tags'文件是否存在,在这种情况下,除了引用刚刚保存的文件的行外,它的内容会被打印出来,而
ctags`只会在刚刚保存的文件上被调用。 ,然后对结果进行"排序"并放回原处。
警告实现者:这假定所有内容都在同一目录中,并且这也是本地缓冲区的当前目录。我还没有考虑过路径修改。
我注意到这是一个旧线程,但是...
在支持inotify的* nix之类的环境中使用incron。每当目录中的文件更改时,它将始终启动命令。 IE。,
/home/me/Code/c/that_program IN_DELETE,IN_CLOSE_WRITE ctags --sort=yes *.c
而已。