webdevqa.jp.net

Vim自動生成ctags

現在、私は.vimrcに以下を持っています:

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

これにはいくつかの問題があります:

  1. 遅い-最後のタグ生成以降に変更されていないファイルのタグを再生成する。
  2. 「続行するにはEnterキーを押すか、コマンドを入力してください」という不可避なため、ファイルを書き込んだ後、Enterボタンを押す必要があります再度

これらの2つの問題を組み合わせると、追加のEnterキーをすぐに(ctags -Rが完了する前に)プッシュすることになり、迷惑なエラーメッセージが表示されるため、Enterキーをもう一度押す必要があります。

私はそれが大したことのように聞こえないことを知っていますが、ある日に私が行うファイル書き込みの量により、それは本当に迷惑になる傾向があります。それを行うためのより良い方法があるはずです!

53
cdleary

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

欠点は、完了するまでは有用なタグファイルが存在しないことです。 * nixシステムを使用している限り、以前のctagsが完了する前に複数の書き込みを行っても問題ありませんが、テストする必要があります。 Windowsシステムでは、それはバックグラウンドに置かれず、最初のctagsが終了するまでファイルがロックされているというメッセージが表示されます(vimで問題が発生することはないはずですが、タグファイルが少し古くなります。 )。

注、--append tonyloが示唆するオプションですが、その場合はtagbsearchを無効にする必要があります。これは、タグファイルのサイズによっては、タグ検索に時間がかかることを意味します。

43
Zathrus

編集する:次のような非常に多くの解決策がthe AutoTag vim scriptとして投稿されています。ただし、スクリプトは、Python support)で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行で記述する必要があります。

そこにはたくさんのことが起こっています:

  1. この自動コマンドは、ファイルがCまたはC++であることが検出されたときにトリガーし、BufWritePostイベントによってトリガーされるバッファーローカルの自動コマンドを追加します。

  2. %プレースホルダーは、実行時にバッファのファイル名に置き換えられ、:gs修飾子は、ファイル名をシェル引用するために使用されます(埋め込まれた単一引用符をquote-escape-quote-quoteに変換することにより)。

  3. このようにして、tagsファイルが存在するかどうかを確認するシェルコマンドを実行します。この場合、保存されたばかりのファイルを参照する行を除いてその内容が出力されますが、保存されたばかりのファイルに対してctagsが呼び出され、結果次にsortedになり、元の場所に戻されます。

警告の実装者:これは、すべてが同じディレクトリにあり、それがバッファーローカルの現在のディレクトリであることを前提としています。パスのマングル化については何も考えていません。

14

これを行うために easytags.vim と書きました。タグを自動的に更新してハイライト表示します。プラグインは、編集中のファイルのみ、または編集中のファイルのディレクトリにあるすべてのファイルを(再帰的に)更新するように設定できます。グローバルタグファイル、ファイルタイプ固有のタグファイル、プロジェクト固有のタグファイルを使用できます。

11
xolox

私はこれが古いスレッドであることに気づきましたが... inotifyをサポートする* nixのような環境ではincronを使用してください。ディレクトリ内のファイルが変更されると、常にコマンドを起動します。つまり、

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

それでおしまい。

7
code933k

おそらく、次のようにctagsに追加引数を使用します。

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

私は通常、コードブラウジングにソースインサイトを使用しているため、これを実際に保証することはできませんが、vimをエディターとして使用しています...

3
tonylo

Crontabを介して実行するようにctagsをスケジュールするのはどうですか?プロジェクトツリーがその構造でかなり安定している場合、それは可能でしょうか?

2
zigdon

OSXでは、このコマンドはそのままでは機能しません。少なくとも私にとってはそうではありません。

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

post が見つかりました。これは、-Rオプションを含む標準のctagsバージョンを取得する方法を説明しています。これだけではうまくいきませんでした。 Homebrewがプログラムをインストールするビンを選択するために、.bash_profileのPATH変数に/ usr/local/binを追加する必要がありました。

2
rand_acs

「Enterキーを押す」プロンプトを抑制するには、 :silent を使用します。

2
Greg Hewgill

--appendオプションは実際に進むべき道です。 grep -vと共に使用すると、1つのtaggedファイルのみを更新できます。たとえば、この問題に対処する 洗練されていないプラグイン の抜粋を次に示します。 (注:「外部」 ライブラリプラグイン が必要です)

" 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、

1
Luc Hermitte

AutoTag と呼ばれるvimプラグインがあり、これは非常にうまく機能します。

Taglistがインストールされている場合は、タグリストも更新されます。

1
Marcus

私の意見では、プラグインインデクサーの方が優れています。

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

かもね:

1)project.tar.gzのアドオン

2)独立したプラグイン

  • 背景タグの生成(ctagsが機能する間、あなたは待っていません)
  • 複数のプロジェクトをサポート
1
dimonomid

自動タグは、保存時に既存のタグファイルを更新するvimプラグインです。

私は何年も問題なく使用していますが、タグファイルに最大サイズを適用する点が異なります。同じタグファイルですべてのインデックスが作成された非常に大きなコードセットがない限り、その制限に達してはなりません。

自動タグ付けには、vimでのPythonサポートが必要です。

0
Greg Jandl