この記事について
筆者が愛用している「VSCode」と
C++のLanguage Server(以下、LSと略)である「ccls」を連携して使ってみた感想と
最近少し話題になっている「TabNine」を連携させて使ってみた感想を記します
cclsについて
一言で言えば「C++専用のLS」です
C++用LSは他に「clangd」と「cquery」が存在します
「clangd」は動作が不安定らしいです
※ただし、後述する「ccls」の作者も「clangd」のコミッターの一人なので、今後良くなっていく可能性があります
「cquery」は結構快適に動作するようですが、masterブランチへのマージコミットが2018/11/27で更新が停止してしまっています
「ccls」は「cquery」の快適さをそのままに色々改善したLSらしく、作者がその良さを語っています
今回は、あまり日本語記事が存在しないので「ccls」を取り上げてみることにします
TabNineについて
昨今流行りの深層学習を利用した補完エンジン
話題のツイート:
これはすごい!ソースコードを解析しあらゆる言語のオートコンプリートを提供するのが、TabNine 。新しいリリースでは、
— Sangmin @ChoimiraiSchool (@gijigae) July 19, 2019
①GitHubにある2万本以上のファイルを分析
②GPT-2で次に予想されるコードを提案(Pythonの例↓)
プログラミングのハードルもだいぶ下がるはず🐍。https://t.co/gIroluRwcK pic.twitter.com/vXD4D9B18W
2019/09/10時点ではProfessional版もバージョンβということで無料で使用できます
詳しくは公式サイトのsubscribeを見たほうがいいです
深層学習でクラウドのGPUアクセラレートを使用して高速に補完することも可能ですが、
その場合プライベートなコードが漏れる可能性があります
デフォルトでは無効化されています
一応セルフホストでGPUアクセラレートを使用できるみたいですが、公式に問い合わせが必要となっています
勘違いするところ
筆者だけかもしれませんが、勘違いしやすいところを明記しておきます
- cclsはLSなので「補完以外にも定義ジャンプや引数の詳細表示などを支援」してくれます
- TabNineは「補完に特化しているので それ以外の機能はサポートしていません 」
TabNineのセマンティック補完
TabNineはあくまで「入力された履歴」「周りにあるコード」から推測して補完候補を表示してくれます
ただ、推測で候補表示するため正しくない情報を表示する可能性があります
(例えば、そのクラスには実装されていないメソッド名を候補に出したりなど)
TabNineにはそういった問題を解決するために「セマンティック補完」という機能が備わっています
LSと通信して言語特有の情報を取得し、補完提案するという機能です
これによりより正確な補完候補を表示してくれます
詳しくは公式ブログが参考になるかと思います
実際にVSCodeで使ってみる
VSCodeとcclsを連携させる
まずはVSCodeにcclsを入れてどの程度動くのかを確認します
VSCodeの拡張インストール画面から「ccls」を検索してインストールします
cclsの実行パスやオプションを公式Wikiに従ってVSCodeに設定します
設定例:
{
// 環境変数PATHにcclsまでの実行パスが入っていれば以下の設定で動きます
"ccls.launch.command": "ccls.exe",
// デフォルトでこのパスになっているそうです
"ccls.cache.directory": "${workspaceFolder}/.ccls-cache/",
// セマンティックハイライト各種有効化フラグ
// お好みでどうぞ(めっちゃカラフルになります)
// "ccls.highlighting.enabled.types": true,
// "ccls.highlighting.enabled.freeStandingFunctions": true,
// "ccls.highlighting.enabled.memberFunctions": true,
// "ccls.highlighting.enabled.freeStandingVariables": true,
// "ccls.highlighting.enabled.memberVariables": true,
// "ccls.highlighting.enabled.namespaces": true,
// "ccls.highlighting.enabled.macros": true,
// "ccls.highlighting.enabled.enums": true,
// "ccls.highlighting.enabled.typeAliases": true,
// "ccls.highlighting.enabled.enumConstants": true,
// "ccls.highlighting.enabled.staticMemberFunctions": true,
// "ccls.highlighting.enabled.parameters": true,
// "ccls.highlighting.enabled.templateParameters": true,
// "ccls.highlighting.enabled.staticMemberVariables": true,
// "ccls.highlighting.enabled.globalVariables": true,
// C/C++拡張をインストールしている場合競合するので
// 以下の設定をする必要がある
"C_Cpp.updateChannel": "Insiders",
"C_Cpp.autocomplete": "Disabled",
"C_Cpp.formatting": "Disabled",
"C_Cpp.errorSquiggles": "Disabled",
"C_Cpp.intelliSenseEngine": "Disabled",
}
実際に試したいC++プロジェクトを立ち上げてみます
今回はC++の静的解析として有名なcppcheckをcloneして試してみます
念の為、最新リリース版である1.89タグで実行します
git clone https://github.com/danmar/cppcheck
cd cppcheck
git checkout 1.89
cclsはコンパイルコマンドから、indexとなるキャッシュファイルを生成していい感じに補完を出す手がかりを探すみたいです
そのため、公式Wikiにもあるようにcompile_commands.jsonを生成します
cmake -H. -BDebug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES
ln -s Debug/compile_commands.json
Visual Studioのclコマンドを経由する場合、CMakeの CMAKE_EXPORT_COMPILE_COMMANDS は対応していないようですので
ninjaを経由するような感じにします
cmake -H. -BDebug -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_CXX_COMPILER="clang-cl.exe"
ninja -C Debug -t compdb cxx cc > compile_commands.json
ここまでできれば設定完了です
VSCodeをcompile_commands.jsonと同じディレクトリで起動ですれば
元気にcclsが動いていることが確認できると思います
VSCodeとcclsとTabNineを連携させる
ここで一気にTabNineと連携させます
この時点ですでにTabNineは有効化されています
結構いい感じに動いてくれます
コード上に TabNine::config
を入力します
するとブラウザでコンフィグ画面が立ち上がります
Configuration pathのtabnine_config.jsonと同じ場所にある
「TabNineExample.toml」をコピーして「TabNine.toml」にリネームします
デフォルトだと「cquery」をC++のLSとして使用するようになっているため
「ccls」を使用するように変更します
サンプル設定:
[language.cpp]
command = "ccls.exe"
args = ["-init={}"]
synchronous_triggers = ["."]
synchronous_timeout_ms = 200
num_server_instances = 2
always_prefer = false
コード上で TabNine::sem
と入力すれば入力したソースコードのセマンティック補完が有効になります
ちゃんと確認したい場合は「tabnine_config.json」を開き以下のような状態になっていれば有効化されています
"semantic_status": {
"cpp": "Enabled"
},
念の為、 TabNine::restart
を入力すればTabNineを再起動させることができます
使ってみた所感
ccls
- いい感じにタグジャンプや補完は機能している
- 規模によるが、キャッシュファイル生成とそれの読み込みにCPUとメモリを持っていかれる
- 試したところ、2000ファイルを超えるとかなりPCリソースを食う感じになりました
- セマンティックハイライト標準装備は個人的に嬉しい
-
C_Cpp.intelliSenseEngine
を無効化してしまうと Alt+oでヘッダー⇔ソースの切り替えまで封じてしまうので不便- 一応ソースとヘッダーを切り替えるだけのプラグイン が存在するがそれだけのために入れるのが微妙・・・
-
.ccls-cache
をバージョン管理除外に入れておかないと大量に変更差分が出てしまうので注意が必要- 単純に .gitignoreファイルに入れればOK
TabNine + ccls
- TabNineの補完がかなり強力
- 特にstd::find_if()の補完は相当便利
- むちゃくちゃ重い&メモリ食われる
- TabNineをセマンティック補完有効化したときcppcheckの規模で約2.5GB程度のメモリを食う
- これはcclsも影響しているかもしれない
- 重いのはLS自体が結構レスポンスが重いものが多いらしく、それのせいらしい
- ただ、VSCode + ccls起動した時はそこまで重くなかった
- VSCode + TabNine単体でもそこまで重くなかった
- TabNineをセマンティック補完有効化したときcppcheckの規模で約2.5GB程度のメモリを食う
- TabNineへの命令がコードに直接マジックコメントを書くしかないのが新鮮
- マジックコメント一覧
- ソースコードを汚すので個人的にはなにか別の方法がほしい
- コマンドパレットから開くなど
総括
- PCマシンがリッチであればTabNine+cclsは十分選択肢に入るのではないかと思いました
- それが厳しいのであれば、TabNineだけでも十分かなと思いました
- 正直、手探りで色々試したため間違っている箇所が大いにありそうです
- コメントでご指摘いただけると幸いです