emacs29以降のコード支援機能

Emacs29で tree-sittereglotが標準機能としてバンドルされました。
ただし、emacsは各自の環境をコードでセットアップする暗黙の仮定があり、elispで適切に設定できた場合に使えるという状況です。

Tree-sitter

Tree-sitterは、主にsyntax highlightingを高速に処理できるパーサを提供しています。
emacsの場合、tree-sitterと統合した新しいメジャーモードを起動すると動作します。

emacs29.1同梱のパッケージはtreesit機能を提供しており、元のtree-sitterパッケージの全機能が含まれているわけではないようです。
また、各言語に対応するgrammerは別途追加する必要があり、.emacs.d/tree-sitter/などに入ります。

treesit-autoを追加することにより、必要なタイミングでgrammerのビルドが走ります。
サポートしている言語は treesit-auto.eltreesit-auto-recipe-listにリストしています。

パッケージをインストールしたうえで、emacs29.1から同梱された use-packageを利用して設定できます。
treesit-auto-installを変更して自動実行する挙動を指定しておきます。

(use-package treesit-auto
  :config
  (setq treesit-auto-install t)
  (global-treesit-auto-mode))

より詳細な挙動は、 How to Get Started with Tree-Sitterの解説が参考になります。

Spacemacsの場合

パッケージじたいは、dotspacemacs-additional-packagesに追加することでインストールできます。

   dotspacemacs-additional-packages
   '(
     treesit-auto
     )

パッケージ設定は先ほどのuse-package式をuser-configに追加すると動作します。

treesit-autoは、たとえばrust-modeが呼ばれた際にrust-ts-modeを起動する挙動を提供するのですが、Spacemacsはまた別のメジャーモードを起動することが多いため、手動で変更する必要があります。

(defun dotspacemacs/user-config ()
  (add-to-list 'major-mode-remap-alist '(rustic-mode . rust-mode))

当然ながらこの例ではrustic-modeが提供していた機能は使えなくなります。
現在有効なモード構成は、M-x describe-modeで確認できます。

また、利用できるgrammerをあらかじめ一括で追加したい場合には、scratchバッファで以下のコードを手動実行すると入ります。

(require 'treesit-auto)
(treesit-auto-install-all)

eglot

eglotは、LSPクライアントです。
lsp-modeは自前でメッセージ類を表示する部分が多いのですが、eglotはFlymakeやEldocに出力を渡す挙動が主になっています。

M-x eglotで手動起動できるほか、対応するモードの起動時にeglot-ensureを呼ぶことで自動起動できます。

(add-hook 'rust-ts-mode-hook 'eglot-ensure)

Spacemacsの場合

Spacemacsでも、user-configでhookを定義しておくと、eglotを起動できます。

(defun dotspacemacs/user-config ()
  (add-hook 'rust-ts-mode-hook 'eglot-ensure)

Spacemacsの各言語レイヤーはLSP設定を提供しているのですが、その多くがlsp-modeとlsp-uiを対象としており、eglotをサポートしていません。
lsp-modeについては、 Spacemacs導入で解説しています。

lsp-modeを抑止する統一的な設定もないのですが、Rust Layerの例ではrust-backendに無効な値をセットすることで停止できています。

dot-spacemacs-configuration-layers
'(
  (rust :variables rust-backend 'eglot)

deno lsp

Denoの公式ドキュメントにeglot向けの設定があります。
ただし、emacs起動時にはeglotをロードしていないのでuse-packageでラップした方が良いことと、tree-sitterのメジャーモードを追加すべき点を考慮すると、次のような設定になります。

(use-package eglot
  :config
  (add-to-list 'eglot-server-programs '((js-mode js-ts-mode typescript-mode typescript-ts-mode) . (eglot-deno "deno" "lsp")))
  (defclass eglot-deno (eglot-lsp-server) ()
    :documentation "A custom class for deno lsp.")
  (cl-defmethod eglot-initialization-options ((server eglot-deno))
    "Passes through required deno initialization options"
    (list :enable t
    :lint t)))

さらにプロジェクト別により細かく設定したいケースについては、 Deno + Tree Sitter + Emacsが参考になります。

emacsのIDE機能拡充がSpacemacsと干渉しつつある

emacsのリリース履歴を見ると、27.1でJSONのネイティブパース、28.1でLispパッケージのネイティブコンパイルを経て、29.1でシンタックス表示のネイティブパースと標準LSPクライアントのバンドルを進めてきています。
バニラ状態のemacsがIDE機能をアグレッシブに統合し、処理スピードも向上しています。

当初からemacs -nwはターミナルで動作するため、とくにCUIのIDEとしては驚異的な進化を継続している例といえます。

これまでもelispによる拡張パッケージで同様の環境は作れていたため、Spacemacsのようなディストリビューションが成立しているのですが、近年のemacs本体の選択とずれが増えてきています。
Spacemacsについては、各レイヤーがeglotなどemacs標準の構成をサポートした方が良い状況ですが、そのように進まない可能性もあります。

レイヤーが提供していた機能がコアに統合されていった場合、Spacemacsの最後の特徴はviキーバインドを提供するevil-modeに絞られるでしょう。
長い目で見ると、evil-modeのキーバインド集に絞ったパッケージとバニラのemacsの構成に回帰した方が良いかもしれません。

⁋ 2023/10/15↻ 2024/12/18
中馬崇尋
Chuma Takahiro