前置き
久々に lsp-mode のドキュメントを眺めていたら、 see-also の節に emacs-tree-sitter なるパッケージが追加されていることに気がついた。このパッケージを導入することで、バッファ中のソースコードに対してより意味論的なハイライトを行うことが出来るらしい。バックエンドに Tree-sitter という Rust 実装のインクリメンタルな構文解析ツールが使用されており、このツールによる構文解析の結果にアクセスするための API も提供されている。
このあたりは全然詳しくないのだが、 Tree-sitter はいわゆる抽象構文木(Abstract Syntax tree)を生成するのではなく、構想構文木(Concrete Syntax Tree)と呼ばれる粒度のより小さい構文木を生成するらしい。
インストール
さて、早速インストールしてみる。インストール手順は emacs-tree-sitter のドキュメントの Installation に記載されている。私は leaf.el を使っているため、 init.el に以下のような記述を追加した。
(leaf emacs-tree-sitter :url "https://github.com/ubolonton/emacs-tree-sitter" :init (straight-register-package '(tsc :host github :repo "ubolonton/emacs-tree-sitter" :files ("core/*.el"))) (straight-use-package '(tree-sitter :host github :repo "ubolonton/emacs-tree-sitter" :files ("lisp/*.el"))) (straight-use-package '(tree-sitter-langs :host github :repo "ubolonton/emacs-tree-sitter" :files ("langs/*.el" "langs/queries"))) :require tree-sitter-langs :config (global-tree-sitter-mode) (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode))
全バッファで tree-sitter-mode を起動するようにして、これの起動後に tree-sitter-hl-mode が起動するように hook している。この tree-sitter-hl-mode がハイライトを行う minor mode である。
leaf.el で straight.el を使う際のお作法がよく分かっていない (:straight キーワードが用意されているようだが…) ので、 leaf-convert の力を借りて適当に変換した。ここで straight.el がないよ〜と言われる場合は、
(leaf straight :defvar bootstrap-version :config (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)))
を追記して straight.el をインストールしておく。このインストール方法は STRAIGHT.EL で ORG MODE をインストールする を参考にしているが、もう少しスマートなやり方があるかもしれない。
動作
転がっていた競プロのソースコード(C++)で動作の様子を確認した(競プロは久しくやってないが、他にちょうど良いソースコードがなかったので…)。


マクロや関数の呼び出しが太文字になったり、クラスのメンバが斜体になったりしている。また、オペレータに色が付くようになった。他に大きな違いとして、型の色が auto 以外の予約語とその他で変わるようになった。
しばらく眺めて気がついたのだが、どうやら color-identifiers-mode.el (変数名ごとに色を割り当てるパッケージ)と中途半端に両立してしまっているらしい。変数に対して代入を行っている箇所の色が tree-sitter-hl-mode によって上書きされてしまっている。それ以外、すなわち参照を行っている箇所は color-identifiers-mode.el によって引き続きハイライトされている。ただ、これに関しては、 lsp-mode のハイライト機能や symbol-overlay.el (カーソルが変数の上になくてもハイライトし続けるパッケージ。とても便利。)で代用出来るのでそこまで不自由ではないと思う(color-identifiers-mode.el を無効にした方がいいかもしれない)。また、ハイライトのカスタマイズが可能となっているので、何かしら回避する手段がありそうにも思える。
おわりに
Tree-sitter 自体が軽いこともあって快適に使えそう。emacs-tree-sitter の API を使うことでハイライト以外にも色々出来る気がする。