55

现在我有以下内容.vimrc

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

这样做有几个问题:

  1. 它很慢 - 为自上次标记生成以来未更改的文件重新生成标记。
  2. 由于不可避免的“按 Enter 或键入命令继续”,我必须在写入文件后再次按下 Enter 按钮。

当您将这两个问题结合起来时,我最终会过早地按下额外的输入(在ctags -R完成之前),然后看到烦人的错误消息,并且不得不再次按下输入。

我知道这听起来没什么大不了的,但是根据我在特定日期执行的文件写入量,它往往会变得非常烦人。必须有更好的方法来做到这一点!

4

12 回答 12

45

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

缺点是在完成之前您不会拥有有用的标签文件。只要您在 *nix 系统上,在之前的 ctags 完成之前进行多次写入应该是可以的,但您应该测试它。在 Windows 系统上,它不会把它放在后台,它会抱怨文件被锁定直到第一个 ctags 完成(这不应该在 vim 中引起问题,但你最终会得到一个稍微过时的标签文件)。

请注意,您可以--append按照 tonylo 的建议使用该选项,但是您必须禁用tagbsearch这可能意味着标签搜索需要更长的时间,具体取决于标签文件的大小。

于 2008-09-30T23:05:04.220 回答
15

编辑: 一个非常类似于以下行的解决方案已发布为AutoTag vim脚本。但是请注意,该脚本需要一个支持 Python 的 vim

我的解决方案改为使用 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. 它使用%在执行时被缓冲区的文件名替换的占位符,以及:gs用于对文件名进行外壳引用的修饰符(通过将任何嵌入的单引号转换为quote-escape-quote-quote)。

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

警告实现者:这假设所有内容都在同一个目录中,并且这也是缓冲区本地当前目录。我没有考虑过路径修改。

于 2008-10-02T20:25:33.213 回答
11

我写了easytags.vim 就是为了做到这一点:自动更新和高亮标签。该插件可以配置为仅更新正在编辑的文件或正在编辑的文件目录中的所有文件(递归)。它可以使用全局标签文件、文件类型特定标签文件和项目特定标签文件。

于 2012-01-14T23:14:58.677 回答
7

我注意到这是一个旧线程,但是......在 *nix 中使用incron,例如支持 inotify 的环境。每当目录中的文件更改时,它总是会启动命令。IE,

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

就是这样。

于 2010-11-30T05:46:46.453 回答
3

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

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

我不能真正保证这一点,因为我通常使用源代码浏览来进行代码浏览,但使用 vim 作为编辑器......看图。

于 2008-09-30T23:01:38.957 回答
2

让 ctags 计划通过 crontab 运行怎么样?如果您的项目树的结构相当稳定,那应该可行吗?

于 2008-09-30T22:55:34.057 回答
2

要禁止“按 Enter”提示,请使用:silent

于 2008-09-30T23:03:15.847 回答
2

在 OSX 上,这个命令不能开箱即用,至少对我来说不是。

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

我找到了一篇文章,它解释了如何获取包含 -R 选项的标准 ctags 版本。仅此一项对我不起作用。我必须将 /usr/local/bin 添加到 .bash_profile 中的 PATH 变量中,以便获取 Homebrew 安装程序的 bin。

于 2011-09-01T10:45:09.150 回答
1

--append选项确实是要走的路。与 a 一起使用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 调用,......这不仅仅是一个提示,而是一个插件的一小部分摘录。

高温下,

于 2008-10-01T09:01:28.357 回答
1

有一个名为AutoTag的 vim 插件非常有效。

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

于 2011-02-10T20:22:22.623 回答
1

在我看来,插件索引器更好。

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

有可能:

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

2)独立插件

  • 背景标签生成(您无需等待 ctags 工作)
  • 支持多个项目
于 2011-03-26T09:45:47.123 回答
0

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

我多年来一直在使用它,没有任何问题,除了它对标签文件强制执行最大大小。除非你有一大组代码都在同一个标​​签文件中被索引,否则你不应该达到这个限制。

请注意,自动标记需要 vim 中的 Python 支持。

于 2011-10-26T22:15:27.570 回答