この記事は 初心者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++でも問題なく使用できます。
定義位置ジャンプ、参照元ジャンプ
ctags
とcscope
を使用します
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!