Vimのすゝめ改

第6回 Tree-sitter について

2021.07.21

Vim 使いの「ブイ」(仮名)です。Vim のすゝめ改では、現代のテキストエディタについてのあらゆる話題をテーマに Vim の視点から見た話を行います。

今回のテーマは「Tree-sitter」です。

1 Tree-sitter とは?

https://tree-sitter.github.io/tree-sitter/

Tree-sitter は Atom のシンタックスハイライトとしても使用されている技術であり、最近になって neovim にも Tree-sitter によるシンタックスハイライトが導入されました。

https://github.blog/2018-10-31-atoms-new-parsing-system/

https://github.com/neovim/neovim/pull/11113

従来、テキストエディタの汎用的なシンタックスハイライトには正規表現が使われることが多くありました。しかし正規表現は記述が難しい上に遅い、表現が限られるので正確なパースができないといった問題点が存在していました。詳しくは 以前の SOUM/miscを参照してください。

Tree-sitter はシンタックスハイライトに特化していて、ソースファイルが更新されたときに即座に結果を返すことができ高速です。これは漸進的分析(Incremental Parsing)といい、テキストエディタで使用することが意図された解析パーサーだからだそうです。

Tree-sitter を用いた解析は簡単で、ソースコードをTree-sitter に与えると解析結果が返るのであとはテキストエディタが適切に色付けをすればよいです。

Tree-sitter はハイライト以外にも使用することができ、Tree-sitter の構文解析結果を用いて、特定の識別子を選択することも可能です。これは Vim でいうテキストオブジェクトに相当します。

Tree-sitter での構文解析処理は npm で実装されており、つまり JavaScript です。高速化のため、JavaScriptは C 言語のソースコードに変換されるようです。

Tree-sitter が対応している言語については、以下を参照してください。C, C++, C#, Rust, Go, Lua 等メジャーな言語には対応しています。

https://tree-sitter.github.io/tree-sitter/#available-parsers

Tree-sitter と LSP との違いとしては、LSP は IDE の処理をほとんど全て行う必要があるので、より処理が複雑であり時間がかかります。LSP の設定も大変です。 Tree-sitter はやることが限られていて明快なので適用できる領域は少ないものの、高速に単純に使うことができます。個人的には Tree-sitter と LSP の両方を併用するのがよいと考えます。

実は、Tree-sitter 以前にも似たようなコンセプトの Vim プラグインが存在していました。ruby_hl_lvar.vim です。

https://github.com/todesking/ruby_hl_lvar.vim

このプラグインは独自に Ruby の構文を解析し、ローカル変数をハイライトします。Vim のハイライトは構文解析を行わないのでローカル変数をハイライトするといったことが行えません。この問題を解消するためのプラグインです。

Tree-sitter はこのような「ソースコードの構文を解析してテキストエディタのハイライト等に利用する」ことを汎用的インタフェースに落としこんだものと言えるでしょう。

2 neovim における Tree-sitter の利用

neovim で Tree-sitter を使うには nvim-treesitter というプラグインをインストールする必要があります。

https://github.com/nvim-treesitter/nvim-treesitter

neovim 本体に Tree-sitter 用の基本機能は入っていますが、ユーザーにとって使いやすいようにはまとまっていません。neovim LSP と nvim-lspconfig の関係のように高レベルな機能やファイルタイプ毎の細かな設定については本体とは別になっているようです。

nvim-treesitter のインストール方法は公式のドキュメントを参照してください。

https://github.com/nvim-treesitter/nvim-treesitter#installation

nvim-treesitter をインストールした後は簡単な設定を vimrc に記述する必要があります。nvim-treesitter は Lua で書かれているので vimrc に Lua のコードを埋め込むことで設定を行います。

https://github.com/nvim-treesitter/nvim-treesitter#setup

lua <<EOF
require'nvim-treesitter.configs'.setup {
  ensure_installed = "maintained",
  highlight = {
    enable = true,
    disable = {},
  },
}
EOF

nvim-treesitter を有効にした場合、通常のハイライトプラグインの代わりに Tree-sitter を用いてハイライトが行われるようになります。

ちなみに Tree-sitter の構文情報を用いて補完を行う completion-treesitter というプラグインも存在しているようです。

https://github.com/nvim-treesitter/completion-treesitter

3 neovim における Tree-sitter の補足事項

余談ですが、外部パッケージへの依存を嫌う Vim では Tree-sitter 対応のような機能は取り込まれないだろうと思われます。本体はシンプルに、ただし使える外部ライブラリはどんどん使う方針の neovim だからこそ取り込みが実現したのでしょう。

自分は実際に Tree-sitter を使ってコードを記述しています。強力なシンタックスハイライトにより文法エラーが一発で分かるのでかなり開発効率の向上に役立っていると言えます。一度この強力なハイライトに慣れてしまうと戻ることが困難です。特に、Typescript + JSX のように複雑な解析が必要なハイライトで効力を発揮します。

Tree-sitter の欠点としては時々内部エラーが発生してシンタックスハイライトが消えたりすることです。毎日のように nvim-treesitter に更新がある開発中のプロダクトなのでそこは仕方がありません。Tree-sitter のパーサーが特定のシンタックス解析に対応してないということもあるようです。

それでも、Tree-sitter の機能はどんどん改善され使いやすくなっているので neovim を使用しているのなら使う価値はあると思います。

This article is made by Vim.

著者プロフィール

v

ブイ。社内では数少ない Vim 使い。ブログ記事の執筆により、社内でのVim の知名度を上げ、Vim を使用する人を増やそうと計画しているらしい。

記事一覧Index