2008-09-30 87 views
52

現在我已經在我的.vimrc如下:Vim的自動生成的ctags

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

有幾個問題是:

  1. 這是緩慢的 - 重新生成標籤文件避風港」自從最後一個標籤生成以來已經改變
  2. 由於不可避免的「按Enter鍵或輸入命令繼續」,我必須在寫入文件後再次按下輸入按鈕

當你把這兩個問題我最終推動更多的進入太早(前ctags -R已完成),然後看到討厭的錯誤信息,並有推再次輸入。

我知道這聽起來不是什麼大不了的事情,但是在特定的日子裏,我所做的文件寫入量往往會變得非常煩人。有一個更好的方法來做到這一點!

回答

41

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

缺點是,你不會有一個有用的標籤文件,直到它完成。只要你在* nix系統上,應該可以在前面的ctags完成之前做多個寫操作,但是你應該測試它。在Windows系統中,它不會把它放在後臺,它會抱怨文件被鎖定,直到第一個ctags結束(這不應該在vim中導致問題,但是最終會有一個過時的標籤文件)。

請注意,您可以按照tonylo的建議使用--append選項,但是您必須禁用tagbsearch,這意味着根據標記文件的大小,標記搜索需要更長的時間。

+0

啊...很好的解決方案。我正在使用沉默! ctags -R並不明白爲什麼什麼事情都沒有發生......我想你需要第二次爆炸。 – cdleary 2008-10-01 00:54:20

+2

在Windows上,您始終可以使用'start ctags -R'。它會在背景中啓動ctags。 – devemouse 2011-09-01 11:12:40

2

如何讓ctags計劃通過crontab運行?如果你的項目樹在結構上相當穩定,那應該是可行的?

+0

+1,KISS。下面是我在每天凌晨2:10設置的一個cronjob示例。顯然,你可以擁有儘可能多的數量。我的ctags選項適用於drupal,可能比您需要的要多。 10 2 * * * cd/var/www/yoursite/&&/usr/bin/ctags --langmap = php:.engine.inc.module.theme.install.php --php-kinds = cdf --languages = php --recurse – roberttstephens 2012-08-09 18:50:48

2

要禁止「按回車」提示,請使用:silent

1

--append選項確實是要走的路。與grep -v一起使用,我們只能更新一個標記爲的文件。例如,以下是解決此問題的unpolished plugin的摘錄。(注:這將需要一個「外部」 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> <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,

13

編輯:非常沿着已經張貼AutoTag Vim腳本以下的線A的解決方案。請注意,腳本需要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改性劑(通過轉動任何嵌入式單引號到報價轉義引號引號) 。

  3. 它運行來檢查,如果一個tags文件存在外殼命令通過這種方式,在這種情況下,印刷不同的是指剛剛保存文件中的行它的內容,同時ctags上調用只是剛剛保存文件,然後結果sort編輯並放回原位。

Caveat實現者:這裏假定所有的東西都在同一個目錄下,並且它也是緩衝區本地的當前目錄。我沒有考慮路徑損壞。

7

我注意到這是一箇舊的線程,但是... 使用incron在* nix喜歡的環境支持inotify。只要目錄中的文件發生更改,它就會始終啓動命令。即,

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

就是這樣。

1

有一個叫做AutoTag的vim插件,它的功能非常好。

如果您安裝了taglist,它也會爲您更新。

2

在OSX上,這個命令不能用於開箱即用,至少不適用於我。

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

我發現了一個post,這也解釋瞭如何獲得包含-R選項標準CTAGS版本。這本身並不適合我。我必須將/ usr/local/bin添加到.bash_profile中的PATH變量中,以便獲取Homebrew安裝程序的bin。

0

Auto Tag是一個vim插件,用於在保存時更新現有標籤文件。

我一直在使用它多年沒有問題,除了它強制標籤文件的最大尺寸。除非你有一大堆代碼都在相同的標籤文件中被索引,否則你不應該達到這個限制。

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

10

我寫easytags.vim做到這一點:自動更新和突出顯示標籤。該插件可以配置爲僅更新正在編輯的文件或正在編輯的文件的目錄中的所有文件(遞歸地)。它可以使用全局標籤文件,文件類型特定標籤文件和項目特定標籤文件。