Help us understand the problem. What is going on with this article?

VimでC++のコードリーディング

More than 1 year has passed since last update.

この記事は 初心者C++er Advent Calendar 2017、20日目の記事です。

VimでC++のコードリーディング

私はC++の開発にVimを使用しています。
IDEにはさすがに負けるかもしれませんが、Vimでも結構快適にコードを読むことができます。

以下にVimを使用してC++のコードリーディングを行う際のTipsについて記載していきたいと思いますー。

環境

Windows 7

VIM - Vi IMproved 8.0 (2016 Sep 12, compiled May 2 2017 12:56:41)
MS-Windows 64 ビット GUI 版
適用済パッチ: 1-596

デフォルトで使用できるキーマップ

多用するのは以下です。

map 説明
[# カーソルが#if-#endif内ならば#if or #elseにジャンプ
]# カーソルが#if-#endif内ならば#else of #endifにジャンプ
gd 変数の定義位置にジャンプ(大抵うまくジャンプできるらしい)
gD 変数(global)の定義位置にジャンプ(大抵うまくジャンプできるらしい)
[[ 一桁目が{の行(大抵関数の開始位置(?))にジャンプ
]] 一桁目が}の行(大抵関数の終了位置(?))にジャンプ
[* or [/ C コメントの始まり(/*)に移動します。
]* or ]/ C コメントの終わり(*/)に移動します。
gf カーソル下のファイルを開く(環境によってpathの設定が必要です)
<C-^> or <C-6> 直前に開いたファイルを開く(厳密には違います。詳細は:h CTRL-6)

このあたりのマップは実はC++用ではなくC言語用のマップかもしれません。
ただ、C++でも問題なく使用できます。

定義位置ジャンプ、参照元ジャンプ

ctagscscopeを使用します
Windowsの場合にctagsはここから、cscopeはここからバイナリをダウンロードできます。
ダウンロード後はパスが通っている場所に配置すればよいだけ。
あとは以下のような設定をvimrc内に記載して、少し便利にします。
(一部vim-submodeというプラグインを使用して、<C-t>と逆方向への移動を楽にしてます。)

" cscope show/killをマッピング
nnoremap <Leader>zs :<C-u>cscope show<CR>
nnoremap <Leader>zk :<C-u>cscope kill -1<CR>

" :cscope find c <関数名> " 指定した関数を呼び出している関数を検索
" :cscope find f <ファイル名> " ファイルを検索
" :cscope find s <Cのシンボル> " シンボルを検索
" 最後に指定する文字を大文字にするとクリップボード内の文字列を使用して:cscope findを実行します。
" NOTE: @+ についてはclipboardの設定により、適宜変更してください
nnoremap <Leader>zfc :<C-u>cscope find c <C-r>=expand('<cword>')<CR><CR>
nnoremap <Leader>zfC :<C-u>cscope find c <C-r>=@+<CR><CR>
nnoremap <Leader>zfs :<C-u>cscope find s <C-r>=expand('<cword>')<CR><CR>
nnoremap <Leader>zfS :<C-u>cscope find s <C-r>=@+<CR><CR>
nnoremap <Leader>zff :<C-u>cscope find f <C-r>=expand('<cfile>')<CR><CR>
nnoremap <Leader>zfF :<C-u>cscope find f <C-r>=@+<CR><CR>

" 定義位置へのジャンプ時に複数候補表示
" クリップボード内の文字列使って:tjump
nnoremap <C-]> g<C-]>
nnoremap g<C-]> :<C-u>tjump <C-r>=@+<CR><CR>

" <C-t>と逆方向への移動をg<C-t>tttt..とできるよう設定
" NOTE: <C-t>は定義への移動前にいた場所にジャンプ。
" NOTE: vimデフォルトだと<C-t>の逆方向への移動用マップはない(<C-o>で逆移動っぽい動作はするが、少し違う)ので、定義
call submode#enter_with('tag', 'n', '', 'g<C-t>', ':<C-u>tag<CR>')
call submode#map('tag', 'n', '', 't', ':<C-u>tag<CR>')


私の場合にはSVNの各ブランチのルートディレクトリ(.svn or .gitディレクトリがある場所)でctags, cscopeを実行したかったので、
以下のような設定も追加しています。

" 特定のファイルを開いた場合にはカレントディレクトリをルートディレクトリに変更
function! s:root_dir() abort
  let search_dir_names = ['.svn', '.git']
  for dir_name in search_dir_names
    let ret_dir = finddir(dir_name, expand('%:p:h') . ';')
    if ret_dir != ''
      return substitute(fnamemodify(ret_dir, ':p:h'), dir_name . '$', '', 'g')
    endif
  endfor

  return ''
endfunction
augroup cd_project_root
  autocmd!
  autocmd BufEnter *.cpp,*.h,*.c, silent execute 'lcd' s:root_dir()
augroup END

" do ctags
function! s:do_ctags() abort
  if isdirectory('.svn') || isdirectory('.git')
    if input('now: ' . getcwd() . "\nrun ctags? (y)es or (n)o : ") =~ '^y$\|^yes$'
      silent !start ctags -R
    endif
  else
    echohl ErrorMsg | echo 'check current dir!' | echohl none
  endif
endfunction

" cscope build/add
function! s:cscope_build() abort
  if isdirectory('.svn') || isdirectory('.git')
    if input('now: ' . getcwd() . "\nrun cscope -Rb? (y)es or (n)o : ") =~ '^y$\|^yes$'
      silent !start cscope -Rb
    endif
  else
    echohl ErrorMsg | echo 'check current dir!' | echohl none
  endif
endfunction
function! s:cscope_add() abort
  if (isdirectory('.svn') || isdirectory('.git')) && filereadable('cscope.out')
    cscope add cscope.out
    echo "cscope add cscope.out!"
  else
    echohl ErrorMsg | echo 'check current dir!' | echohl none
  endif
endfunction

" ctags, cscope build/add用のマップ
nmap <Leader>ct :<C-u>call <SID>do_ctags()<CR>
nmap <Leader>zb :<C-u>call <SID>cscope_build()<CR>
nmap <Leader>za :<C-u>call <SID>cscope_add()<CR>

cscopeについて

記事を書いていく中で知ったのですが、cscopeはC言語用のパーサとして作られているようですね。。
c++でも大抵動くらしいですが、以下のような記載もあり油断は禁物らしいです。

The fuzzy parser supports C, but is flexible enough to be useful for C++ and Java, and for use as a generalized 'grep database'

現状はrtagsというのが流行っているそうですね。
どなたかWindowsでrtagsを使う方法をまとめてください(切実)

まとめ

いかがだったでしょうか?
Vimをつかえば設定しなくとも快適にコードを読めますし、設定すれば更に快適にコードを読むことができます!
他のIDEの使い方がわからないだけとは言えない

また、ここでは紹介しませんが、Vimのプラグインであるunite.vimのmru, bookmark, file機能をつかえば
ファイルを開くまでの時間を短縮できますし、unite-outlineを使用すれば
ファイル内の定義の一覧を常に表示でき、VimをIDEっぽくすることもできます。

皆様もいろいろ試してみて、Vimで快適なコードリーディングを行ってみましょー!
Happy C++ Life!

rapan931
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away