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

VSCode&ccls&TabNineを使った快適な補完を目指してみた

この記事について

筆者が愛用している「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について

昨今流行りの深層学習を利用した補完エンジン
話題のツイート:

2019/09/10時点ではProfessional版もバージョンβということで無料で使用できます
詳しくは公式サイトのsubscribeを見たほうがいいです
e6e6f081e3073ce0fff201e266d90f47.png

深層学習でクラウドのGPUアクセラレートを使用して高速に補完することも可能ですが、
その場合プライベートなコードが漏れる可能性があります
デフォルトでは無効化されています
一応セルフホストでGPUアクセラレートを使用できるみたいですが、公式に問い合わせが必要となっています

勘違いするところ

筆者だけかもしれませんが、勘違いしやすいところを明記しておきます

  • cclsはLSなので「補完以外にも定義ジャンプや引数の詳細表示などを支援」してくれます
  • TabNineは「補完に特化しているので それ以外の機能はサポートしていません

TabNineのセマンティック補完

TabNineはあくまで「入力された履歴」「周りにあるコード」から推測して補完候補を表示してくれます
ただ、推測で候補表示するため正しくない情報を表示する可能性があります
(例えば、そのクラスには実装されていないメソッド名を候補に出したりなど)

TabNineにはそういった問題を解決するために「セマンティック補完」という機能が備わっています
LSと通信して言語特有の情報を取得し、補完提案するという機能です
これによりより正確な補完候補を表示してくれます
詳しくは公式ブログが参考になるかと思います

実際にVSCodeで使ってみる

VSCodeとcclsを連携させる

まずはVSCodeにcclsを入れてどの程度動くのかを確認します

VSCodeの拡張インストール画面から「ccls」を検索してインストールします
4f422abd7a5168aac4e327479e7c92d2.png

cclsの実行パスやオプションを公式Wikiに従ってVSCodeに設定します
設定例:

settings.json
{
    // 環境変数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が動いていることが確認できると思います
8c301be3dded22de4d6d9581ec2a63bc.png

デモ:
demo_ccls.gif

VSCodeとcclsとTabNineを連携させる

ここで一気にTabNineと連携させます

TabNineのVSCode拡張をインストールします
d76bc8753473c11c08cb6d8b58488b03.png

この時点ですでにTabNineは有効化されています
結構いい感じに動いてくれます

コード上に TabNine::config を入力します
するとブラウザでコンフィグ画面が立ち上がります
9500e81704cc1dfb28f141b84b6b6763.png

Configuration pathのtabnine_config.jsonと同じ場所にある
「TabNineExample.toml」をコピーして「TabNine.toml」にリネームします

デフォルトだと「cquery」をC++のLSとして使用するようになっているため
「ccls」を使用するように変更します
サンプル設定:

TabNine.toml
[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」を開き以下のような状態になっていれば有効化されています

tabnine_config.json
"semantic_status": {
    "cpp": "Enabled"
  },

念の為、 TabNine::restart を入力すればTabNineを再起動させることができます

デモ(おぼつかなくてすみません・・・):
demo_ccls_tabnine.gif

使ってみた所感

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への命令がコードに直接マジックコメントを書くしかないのが新鮮
    • マジックコメント一覧
    • ソースコードを汚すので個人的にはなにか別の方法がほしい
    • コマンドパレットから開くなど

総括

  • PCマシンがリッチであればTabNine+cclsは十分選択肢に入るのではないかと思いました
    • それが厳しいのであれば、TabNineだけでも十分かなと思いました
  • 正直、手探りで色々試したため間違っている箇所が大いにありそうです
    • コメントでご指摘いただけると幸いです
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした