はじめに
前回、自作の Tree-sitter パーサー (tree-sitter-unreal-cpp
) の構文解析はうまくいったのに、どうしてもハイライトが効かない…というポエムのような記事を投稿しました。
あれから一日、リベンジを誓って再びデバッグに挑んだ結果、ついにハイライトを有効にすることに成功しました。しかし、その原因はあまりにも単純なケアレスミス。この恥ずかしさと、ついに解決した安堵が入り混じった気持ちをここに記します。
長く険しいデバッグの旅路
今回も、問題の切り分けからスタートしました。
1. クエリファイルは正しく読み込まれているか?
nvim-treesitter
の main
ブランチでは、デバッグ用のコマンドが整理され、Neovim 本体の API を直接叩くのが確実です。まずは、現在のファイルタイプ (cpp
) に対して、どの highlights.scm
が読み込まれているかを確認しました。
-- コマンドモードで実行
:lua print(vim.inspect(vim.treesitter.query.get_files(vim.bo.filetype, "highlights")))
結果として、自作のクエリファイル (.../queries/cpp/highlights_unreal.scm
など) のパスがきちんと表示されました。クエリファイルの読み込みは成功している、ということが確定しました。
2. ハイライトグループは適用されているか?
次に、ハイライトさせたいキーワード(Blueprintable
など)の上で、どのハイライトグループが適用されているかを確認します。
:Inspect
しかし、結果は Syntax - cParen
のような無関係なものだけ。Tree-sitter 由来のハイライトグループは何も適用されていませんでした。
3. ドキュメントの再読と深まる謎
クエリは読み込まれている。パーサーも :InspectTree
で見る限り正しく動いている。それなのにハイライトが適用されない...。
Neovim の Tree-sitter 公式ドキュメントを何度も読み返しましたが、.scm
ファイルの構文に間違いは見当たりません。
「master
ブランチでは動いていたのに、なぜ...?」という気持ちが強くなり、今回も諦めムードが漂い始めた、まさにその時でした。ふと、あることに気が付きます。
「そういえば、Unreal C++ 以外のハイライトも効いていない…?」
灯台下暗し!すべての原因
ensure_installed
を設定しているはずなのに、なぜ cpp
以外のパーサーがインストールされていないのか?
その疑問をきっかけに main
ブランチの README を改めて熟読した結果、自分の思い込みに愕然としました。
main
ブランチは master
ブランチとは全くの別物になっていたのです。
-
setup
テーブルに記述していたensure_installed
は廃止。 - 同じく
highlight = { enable = true }
やindent = { enable = true }
といった機能の自動有効化スイッチも廃止。
nvim-treesitter
はもはや多機能フレームワークではなく、パーサー管理とクエリ提供に特化した、よりシンプルなプラグインへと役割を変えていました。そして、ハイライトなどの機能を有効にするのは、ユーザー自身の責任となっていたのです。
まさに灯台下暗し。部品(クエリファイル)ばかりを調べていましたが、そもそも電源スイッチが入っていなかったのでした。
最終的な設定コード
README を読み、これまでのデバッグで得た知見をすべて反映した最終的な設定コードがこちらです。
-- lazy.nvim での設定例
{
'nvim-treesitter/nvim-treesitter',
branch = 'main',
build = ':TSUpdate', -- プラグイン更新時にパーサーも更新する
config = function()
-- インストールしたいパーサーのリスト
local langs = { "c", "cpp", "c_sharp", "lua", "vim", "vimdoc" }
-- 1. パーサーをインストールする
-- buildステップで自動化されるが、手動実行も可能
require("nvim-treesitter").install(langs)
-- 2. 機能の有効化 (ここが最重要ポイント!)
-- autocmdでファイルタイプごとにTreesitterの機能を起動する
local group = vim.api.nvim_create_augroup('MyTreesitterSetup', { clear = true })
vim.api.nvim_create_autocmd('FileType', {
group = group,
pattern = langs,
callback = function(args)
-- ハイライトを有効にする
vim.treesitter.start(args.buf)
-- インデントを有効にする
vim.bo[args.buf].indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
end,
}
この設定を適用したことで、長かった戦いに終止符が打たれ、無事にすべてのハイライトが正しく表示されるようになりました。
まとめ
nvim-treesitter
の main
ブランチへ移行する際は、master
ブランチの知識は一度忘れる必要があります。
-
setup
テーブルは大幅に簡素化されました。 - パーサーのインストールは
require("nvim-treesitter").install()
で行います。 - ハイライトやインデントなどの機能は、自分で
autocmd
を設定してvim.treesitter.start()
などを呼び出す必要があります。
最新のプラグインを追いかけるのは大変ですが、その分 Neovim 本体の進化を直接感じられる良い機会になりました。何より、自分のケアレスミスに気づけて本当に良かったです(とても恥ずかしいですが…)。
この記事が、同じように main
ブランチで迷子になった誰かの助けになれば幸いです。
さて今回もgemini proに下書きを正書してもらって記事を投稿しています。
今回はアメリカン感がすくなく下書きの雰囲気がすこーしのこっているので画像の追加以外一切の加筆&修正なし純度100%のgeimini文章です
treesitterのデバッグをしていたチャット部屋で文章も書いてもらったので私がわすれていたデバッグの章も加筆してくれました。これを思うに用途で部屋を分けるよりかは一つのチャット部屋で完結したほうがいいのか?と思いつつ、大量のソースコードのやり取りをしているとgemini側がどのソースが最新の状態なのか?がだんだんわからなくなっていくような挙動もするので見極めつつ今後も geminiを使っていこうと思います。
(copilotも課金してますがなんか性格が好きになれない)