Vim で C++ を書くときの逆引きリファレンス
この記事は C++ AdventCalendar 2013 の 10 日目の記事です.
本記事では Vim で C++ を書いている人を対象として,逆引きで Vim の機能やプラグインについて紹介していきます.
すべてについて細かく書いているとキリが無いので,基本的な使い方とプラグインのリポジトリへのポインタ,主要な記事へのリンクを載せています.
より詳しく知りたい場合はリポジトリ内の README
やドキュメント(/doc
内にあります),プラグインインストール後の :help
コマンドを利用してください.
また,何か問題が発生した場合など,助けが必要な場合は Lingr というチャットサービスの Vim 部屋でも対応してもらえることがあります.
目次
プラグインマネージャについて
本記事では多くのプラグインを紹介しています.Vim のプラグインを導入する際にはプラグインマネージャを利用するのが一般的になってきています. プラグインマネージャとしては下記のようなものが挙げられます.
neobundle.vim vundle vim-plug pathogen
本記事ではプラグインの読み込みを必要になるまで遅らせられるなど高機能な neobundle.vim を設定例に使います.
シンタックスハイライト
C++11 に入り,ラムダ式やいくつかのキーワードなどの拡張が行われました. Vim における C++ のシンタックスハイライトは vim-jp(日本の Vim ユーザグループ)で管理されています.
最近の Vim では C++11 が既にサポートされていますが,バグフィックスや最新版の C++ への対応がいち早く行われるので,上記リポジトリを利用するのがおすすめです.
NeoBundleLazy 'vim-jp/cpp-vim', { \ 'autoload' : {'filetypes' : 'cpp'} \ }
補完する
ワード・インクルードパス補完
変数名,関数名やクラス名,#include
時のファイル名などの補完候補するためのプラグインです.
インクルード補完を正しく動作させるためには,path
を正しく設定しておく必要があります.
以下は一例で,環境に合わせる必要があります.
augroup cpp-path autocmd! autocmd FileType cpp setlocal path=.,/usr/include,/usr/local/include,/usr/lib/c++/v1 augroup END
neocomplete
NeoBundle 'Shougo/neocomplete.vim'
neocomplete は neocomplcache の後継で,バッファ内の単語補完やインクルードパスなどの補完候補を自動生成し,ポップアップウィンドウで編集中に選択できます.
非常にカスタマイズ性が高く,様々な言語に対応しており,もちろん C++ にも対応しています.
補完を高速化するために Lua インターフェースを使用しているため,:version
で +lua
になっていることを確認する必要があります.
基本的な設定例は :help neocomplete
で確認できます.
YouCompleteMe
NeoBundleLazy 'Valloric/YouCompleteMe', { \ 'build' : { \ 'mac' : './install.sh --clang-completer', \ 'unix' : './install.sh --clang-completer', \ } \ }
YouCompleteMe は neocomplete と同様に補完を自動で行うためのプラグインです. 補完エンジンに C++ を使っており,補完生成が neocomplete よりも高速です. また,試していませんが,clang による補完も実装されているようです. ただ,あまり拡張することを考慮されておらず,neocomplete に比べるとカスタマイズ性が落ちるのと,OS によってはビルドが面倒です.
neosnippet
NeoBundle 'Shougo/neosnippet'
neosnippet は様々な言語でスニペット(コード片)を挿入できるようになるプラグインです. C++ についても多くのスニペット(lambda や range based for など)が用意されています.
また,独自にスニペットを追加することもできます.その辺りは :help neosnippet
に載っています.
- 参考リンク
stargate.vim
NeoBundleLazy 'osyo-manga/vim-stargate', { \ 'autoload' : {'filetypes' : 'cpp'} \ }
#include
を簡単に追加できるようにするプラグインです.:StargateInclude
コマンドの後に対象のライブラリ(例えば boost/optional.hpp )と入力すると,ファイルの先頭付近に自動で #include
を挿入してくれます.コマンドの補完が効きます.
文脈を考慮した賢い補完
clang の構文解析を利用した補完機能を提供するプラグインです.
オムニ補完の機能を使っており,インサートモードで .
や ::
の後に Ctrl + x → Ctrl + o と入力すると補完候補が表示されます.
neocomplete で自動で候補を表示させるには次の設定を追加する必要があります.
if !exists('g:neocomplete#force_omni_input_patterns') let g:neocomplete#force_omni_input_patterns = {} endif let g:neocomplete#force_omni_input_patterns.cpp = \ '[^.[:digit:] *\t]\%(\.\|->\)\w*\|\h\w*::\w*'
clang_complete
NeoBundleLazy 'Rip-Rip/clang_complete', { \ 'autoload' : {'filetypes' : ['c', 'cpp']} \ }
libclang の python バインディングを使って補完候補を生成する補完プラグインです. quickfix によるエラーや警告の表示,スニペット機能,カーソルしたの変数の定義位置へのジャンプなどかなり多機能ですが,最近はメンテナンスされていないようです.
- 参考リンク
marching.vim
NeoBundleLazy 'osyo-manga/vim-marching', { \ 'depends' : ['Shougo/vimproc.vim', 'osyo-manga/vim-reunions'], \ 'autoload' : {'filetypes' : ['c', 'cpp']} \ }
clang コマンドを利用して補完候補を生成するプラグインです.
vimproc.vim を利用して,非同期に補完候補を生成するため,補完生成によって Vim がブロックされません.
neocomplete と一緒に使う場合は let g:marching_enable_neocomplete = 1
とする必要があります.
名前空間の入力を簡単にする
std::
や boost::
などの名前空間を入力するのはなかなか手間ですが,いちいち using
するのもそれはそれで大変です.
よく入力する名前空間は入力を楽にしたいです.
下記のように .vimrc
で設定すると b;;
で boost::
,s;;
で std::
,d;;
で detail::
に自動で展開されるため,入力が楽になります.
augroup cpp-namespace autocmd! autocmd FileType cpp inoremap <buffer><expr>; <SID>expand_namespace() augroup END function! s:expand_namespace() let s = getline('.')[0:col('.')-1] if s =~# '\<b;$' return "\<BS>oost::" elseif s =~# '\<s;$' return "\<BS>td::" elseif s =~# '\<d;$' return "\<BS>etail::" else return ';' endif endfunction
現在のバッファを実行する
ライブラリを試しに使ってみたいときなど,簡単なコード片を書いてさっと実行したいことがよくあります. ここでは,そのためのプラグインを紹介します.
NeoBundle 'thinca/vim-quickrun'
実行したいコードを開き,:QuickRun
を実行するだけで良い感じに実行し,良い感じに表示してくれます.
また,g:quickrun_config
に設定を書くことにより,挙動を細かくカスタマイズできます.
let g:quickrun_config = get(g:, 'quickrun_config', {}) " vimproc を使って非同期に実行し,結果を quickfix に出力する let g:quickrun_config._ = { \ 'outputter' : 'quickfix', \ 'runner' : 'vimproc' \ }
デフォルトで clang を使い,好みのオプションを付けるには次のようにします
let g:quickrun_config.cpp = { \ 'command' : 'clang++', \ 'cmdopt' : '-std=c++1y -Wall -Wextra', \ }
また,gcc と結果を見比べたい場合などのために,gcc で実行する用の設定も追加で書けます.
let g:quickrun_config['cpp/gcc'] = { \ 'command' : 'g++', \ 'cmdopt' : '-std=c++11 -Wall -Wextra', \ }
この場合,:QuickRun cpp/gcc
とすると gcc で実行できます.
また,boost の一部のライブラリなど,ライブラリのリンクが必要な場合は,quickrunex-vim というプラグインが用意されています.
NeoBundle 'thinca/vim-quickrun', { \ 'depends' : 'mattn/quickrunex-vim', \ }
次のように hook を追加すると :QuickRun
時に自動でライブラリのリンクをするためのオプション(-lboost_system
とか)を行ってくれます.
let g:quickrun_config.cpp = { \ 'command' : 'clang++', \ 'cmdopt' : '-std=c++1y -Wall -Wextra', \ 'hook/quickrunex/enable' : 1, \ }
wandbox-vim
NeoBundle 'rhysd/wandbox-vim'
@melponn さんと @kikairoya さんが作成したソーシャルコンパイルサービス,Wandbox を Vim から利用するためのプラグインです.
:Wandbox
とすると現在のバッファを Wandbox で実行し,コンパイラからのエラーや警告を quickfix に,実行結果をメッセージウィンドウに表示します.
curl
または wget
コマンドと vimproc.vim をインストールしていると非同期にリクエストを投げるようになり,結果が返ってくるまでの間待たなくて良くなります.
また,:Wandbox --compiler=clang-head,gcc-head
のようにすると複数のコンパイラで一度に実行できます.
なお,上記の vim-quickrun との連携もあり,:QuickRun -runner wandbox
のようにすると quickrun の実行部分を Wandbox で行うことができます.
調べる
Boost のドキュメントを調べる
osyo-manga/unite-boost-online-doc
NeoBundleLazy 'osyo-manga/unite-boost-online-doc', { \ 'depends' : [ \ 'Shougo/unite.vim', \ 'tyru/open-browser.vim', \ 'mattn/webapi-vim', \ ], \ 'autoload' : 'cpp' \ }
Boost のドキュメントの一覧を unite.vim で開き,絞り込み,ブラウザで表示することができます.
次のように :UniteWithCursorWord
をマッピングしておくとすぐに目的のドキュメントにたどり着きます.
augroup cpp-unite autocmd! autocmd FileType cpp nnoremap <Space>ub :<C-u>UniteWithCursorWord boost-online-doc augroup END
規格書を調べる
NeoBundleLazy 'rhysd/unite-n3337', { \ 'depends' : 'Shougo/unite.vim', \ 'autoload' : {'filetypes' : 'cpp'} \ }
unite.vim で C++11 規格書直近のドラフト N3337 を章タイトルで絞り込み検索し,読みやすいようにシンタックスハイライト付きで表示するプラグインです.
勝手に n3337.pdf を同梱するのはまずそうだったため,n3337.pdf は自前で用意してもらい,それを pdftotext
コマンドで変換してもらう形になっています.
なので,poppler パッケージが必要です.
- 参考リンク
カーソル移動
カーソル下のクラス・変数などの定義位置へジャンプする
補完のところでも紹介した clang_complete を使います. Ctrl + ] を押すと,カーソル下のクラス名や変数名などの定義位置へジャンプすることができます. 他のマッピングに割り当てたい場合は次のようにします.
" Ctrl + t でカーソル下のシンボルの定義位置へジャンプ let g:clang_jumpto_declaration_key = '<C-t>'
現在のバッファのアウトラインから移動する
NeoBundle 'Shougo/unite-outline'
unite-outline.vim というプラグインを用い,unite.vim のインターフェースで現在のバッファのアウトラインを表示できます. 目的のクラスに行を合わせ,Enter でその位置にジャンプできます. 特にヘッダオンリーのライブラリなどの宣言と定義が同じファイルにある場合は特に有効です.
- 参考リンク
ヘッダファイルとソースファイルを切り替える
NeoBundleLazy 'kana/vim-altr'
vim-altr は予め定義された複数のファイル間を行き来できるようにするプラグインです.
nnoremap <Leader>a <Plug>(altr-forward)
とすると \a
で現在のヘッダファイル(.hpp
や .h
など)とソースファイル(.cpp
や .cc
など)の間を簡単に行き来できます.
さらに,挙動をかなり細かくカスタマイズできます.(詳しくは :help altr
)
- 参考リンク
インクルード先へジャンプする
Vim では標準でカーソル下のパスに飛ぶ機能があります.
#include <hoge>
の <hoge>
の部分で gf
を入力すると新しいバッファで対象のヘッダファイルを開けます.
また,<C-w>f
で新しいウィンドウ,<C-w>gf
で新しいタブで対象のヘッダファイルを開くことができます.
ソースコードを整形する
インデントルールを設定する
C や C++ における Vim のインデントルールは cinoptions
というオプションで細かく変更することができます.
例えば,ラベルでインデントを深くされたくない場合は次のようにします.
set cinoptions+=:0,g0
他にも名前空間や switch 文でインデントを深くするかなどを決めることが出来ます.
cinoptions
の設定項目は大量にあるので,:help cinoptions
や :help cinoptions-values
を参照してください.
clang-format.py
clang の付属ツールには C や C++ のコードを整形できる clang-format というコマンドラインツールがあります.これを利用すると,ソースコードを一定のスタイルに合わせて簡単に整形できます. clang-format には clang-format.py という Python スクリプトが付属しており,それを Vim から呼び出すことで Vim 内からコードを整形できます.
augroup cpp-clangformat autocmd! autocmd FileType c,cpp,objc noremap <C-K> :pyf /path/to/clang-format.py<CR> augroup END
CTRL + k と入力するとファイル全体がフォーマットされます.
vim-clang-format
NeoBundleLazy 'rhysd/vim-clang-format', { \ 'autoload' : {'filetypes' : ['c', 'cpp', 'objc']} \ }
:ClangFormat
とするとバッファ全体を整形できます.また,範囲選択するとその範囲を整形できます.
上記の clang-format.py の違いとしては,
- 整形ルールを Vim の設定として細かく記述できる(clang-format.py は整形するファイルと同じディレクトリに
.clang-format
というスタイル記述ファイルが必要になる) - vim-operator-user をインストールしておくと,Vim のオペレータマッピングが使えるようになります.(オペレータマッピングについては
:help operator
)
\1. については,.vimrc 内で次のように辞書で書けます.
let g:clang_format#style_options = { \ 'AccessModifierOffset' : -4, \ 'AllowShortIfStatementsOnASingleLine' : 'true', \ 'AlwaysBreakTemplateDeclarations' : 'true', \ 'Standard' : 'C++11', \ 'BreakBeforeBraces' : 'Stroustrup', \ }
キーと値に何を入れれば良いかは ClangFormatStyleOptions に載っています.
まとめ
Vim から C++ を利用する際に有用なものを逆引きで書いてみました. 普段から Vim を使っているけれど,あまりカスタマイズしていない方や,これから Vim を使っていきたい方が便利な設定やプラグインを知るための足がかりとなれば幸いです.
プラグインの紹介が多くなってしまいましたが,思いついたときに随時追加していきたいと思います.