GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Parser_002dbased-Indentation.html ・ emacs-doc.conao3.com

24.8.2 パーサーベースのインデント

Tree-sitterライブラリ(プログラムソースの解析を参照)を用いてビルドすると、Emacsはプログラムソースを解析して構文木を生成できます。この構文木は、プログラムソースのインデントコマンドの指針として利用できます。最大限の柔軟性を求めるなら、構文木を照会して各言語に応じてインデントを行うカスタムインデント関数を記述することも可能ですが、それには多大な手間がかかります。以下で説明するシンプルなインデントエンジンを使用する方が便利です。そうすれば、メジャーモードはインデントルールをいくつか記述するだけで済み、残りの処理はエンジンが担ってくれます。

パーサーベースのインデントエンジンを有効にするには、treesit-simple-indent-rules または treesit-indent-function のいずれかを設定し、次に treesit-major-mode-setup を呼び出します。(treesit-major-mode-setup が行うのは、indent-line-function の値を treesit-indent に、indent-region-function の値を treesit-indent-region に設定することだけです。)

変数: treesit-indent-function

この変数には、treesit-indent によって呼び出される実際の関数が格納されます。デフォルト値は treesit-simple-indent です。将来的には、より複雑な他のインデントエンジンを追加する可能性があります。

インデントルールの記述

変数: treesit-simple-indent-rules

このローカル変数には、すべての言語のインデント規則が格納されています。これは (language rule…) 形式の要素のリストであり、language は言語シンボル、各 rule は (matcher anchor offset) 形式の要素からなるリストか、あるいは関数のいずれかです。

以下にリスト型の説明、続いて関数型の説明を記載します。

First, Emacs passes the smallest tree-sitter node at the beginning of the current line to matcher; if it returns non-nil, this rule is applicable. Then Emacs passes the node to anchor, which returns a buffer position. Emacs takes the column number of that position, adds offset to it, and the result is the indentation column for the current line.

matcher と anchor は関数であり、Emacs はこれらに対して便利なデフォルト値を提供しています。

各 matcher または anchor は、node、parent、bol の3つの引数を取る関数です。引数 bol は、インデントが必要なバッファ位置、すなわち行頭以降の最初の非空白文字の位置です。引数 node は、その位置から始まる最大のノード(かつルートノードではないもの)であり、parent は node の親です。ただし、その位置が空白文字内または複数行文字列内にある場合は、その位置から始まるノードは存在しないため、node は nil となります。その場合、parent はその位置にまたがる最小のノードとなります。

matcher はルールが適用される場合に non-nil を、anchor はバッファ位置を返す必要があります。

offset は、整数、値が整数である変数、または整数を返す関数のいずれかです。関数の場合は、マッチャーやアンカーと同様に、node、parent、bol が渡されます。

ruleが関数である場合、ルールがマッチングルールとアンカーを併せて考慮する必要がある複雑なケースにおいて有用です。rule関数には、matcherと同じ引数(node、parent、bol)が渡されます。マッチした場合、ruleはコンス (anchor-pos . offset) を返す必要があり、ここでanchor-posはバッファ位置、offsetはインデントオフセットとなります。ruleがマッチしない場合は、nilを返す必要があります。

変数: treesit-simple-indent-presets

これは treesit-simple-indent-rules における matcher および anchor のデフォルト値の一覧です。それぞれ、node、parent、bol の3つの引数を取る関数を表しています。利用可能なデフォルト関数は以下の通りです:

no-node

このマッチャーは、node、parent、bol の3つの引数で呼び出される関数です。node が nil である場合、すなわち bol から始まるノードが存在しない場合に、一致を示す non-nil を返します。これは、bol が空行にある場合や、複数行文字列の中にある場合などに該当します。

parent-is

このマッチャーは1つの引数 type を取る関数であり、node、parent、bol の3つの引数で呼び出され、parent の型が正規表現 type に一致する場合に non-nil(すなわちマッチ)を返す関数を返します。

node-is

このマッチャーは1つの引数 type を取る関数であり、node、parent、bol の3つの引数で呼び出され、node の型が正規表現 type に一致する場合に non-nil を返す関数を返します。

field-is

このマッチャーは1つの引数 name を取る関数であり、node、parent、bol の3つの引数で呼び出され、parent 内の node のフィールド名が正規表現 name に一致する場合に non-nil を返す関数を返します。

query

このマッチャーは1つの引数 query を取る関数であり、node、parent、bol の3つの引数で呼び出され、query を用いて parent をクエリした際に node がキャプチャされる場合に non-nil を返す関数を返します(パターンマッチング Tree-sitter ノード を参照)。

match

このマッチャーは、5つの引数 node-type、parent-type、node-field、node-index-min、node-index-max を取る関数です。これは、3つの引数 node、parent、bol で呼び出され、node の型が正規表現 node-type に一致し、parent の型が正規表現 parent-type に一致し、node の parent におけるフィールド名が正規表現 node-field に一致し、かつ node の兄弟要素内でのインデックスが node-index-min から node-index-max の間にある場合に、non-nil を返す関数を返します。引数の値が nil である場合、このマッチャーはその引数をチェックしません。例えば、親要素が argument_list である場合の最初の子要素にマッチさせるには、次のようにします。

(match nil "argument_list" nil 0 0)

さらに、node-type は特殊値 null となる場合があり、これは node の値が nil のときに一致します。

n-p-gp

「node-parent-grandparent」の略であるこのマッチャーは、node-type、parent-type、grandparent-type の3つの引数を取る関数です。これは、node、parent、bol の3つの引数で呼び出され、(1) node-type が node の型に一致し、(2) parent-type が parent の型に一致し、(3) grandparent-type が parent の親の型に一致する場合に、nil 以外の値を返す関数を返します。node-type、parent-type、grandparent-type のいずれかが nil である場合、この関数はそれを判定しません。

comment-end

このマッチャーは、node、parent、bol の3つの引数で呼び出され、ポイントがコメント終了トークンより前にある場合に non-nil を返す関数です。コメント終了トークンは、正規表現 comment-end-skip によって定義されます。

catch-all

このマッチャーは、node、parent、bol の3つの引数で呼び出される関数です。常に non-nil を返し、マッチしたことを示します。

first-sibling

このアンカーは、node、parent、bol の3つの引数で呼び出され、parent の最初の子要素の開始位置を返す関数です。

nth-sibling

このアンカーは、2つの引数 n と、オプションの引数 named を引数とする関数です。これは、node、parent、bol の3つの引数で呼び出され、parent の n 番目の子要素の開始位置を返す関数を返します。named が nil 以外の場合、名前付きの子要素のみがカウントされます(名前付きノード を参照)。

parent

このアンカーは、node、parent、bol の3つの引数で呼び出され、parent の開始位置を返す関数です。

grand-parent

このアンカーは、node、parent、bol の3つの引数で呼び出され、parent の親の開始位置を返す関数です。

great-grand-parent

このアンカーは、node、parent、bol の3つの引数で呼び出され、parent の親の親の開始位置を返す関数です。

parent-bol

このアンカーは、node、parent、bol の3つの引数で呼び出され、parent の開始位置がある行における最初の非スペース文字を返す関数です。

standalone-parent

このアンカーは、node、parent、bol の3つの引数で呼び出される関数です。node の最初の祖先ノード(親、祖父母など)のうち、自身の行から始まっているものを探し、そのノードの開始位置を返します。「自身の行から始まっている」とは、そのノードの開始位置がある行において、ノードの前に空白文字しか存在しないことを意味します。「自身の行から始まっている」の厳密な定義は、treesit-simple-indent-standalone-predicate を設定することで緩和でき、メジャーモードによっては、メソッドチェーン時のインデントを容易にするためにそうしたい場合があります。

prev-sibling

このアンカーは、node、parent、bol の3つの引数で呼び出され、node の前の兄弟要素の開始位置を返す関数です。

no-indent

このアンカーは、node、parent、bol の3つの引数で呼び出され、node の開始位置を返す関数です。

prev-line

このアンカーは、node、parent、bol の3つの引数で呼び出され、直前の行の最初の非空白文字を返す関数です。

column-0

このアンカーは、node、parent、bol の3つの引数で呼び出され、現在の行の先頭(0列目)を返す関数です。

comment-start

このアンカーは、node、parent、bol の3つの引数で呼び出され、コメント開始トークンの後の位置を返す関数です。コメント開始トークンは、正規表現 comment-start-skip で定義されています。この関数は、parent がコメントノードであることを前提としています。

prev-adaptive-prefix

このアンカーは、node、parent、bol の3つの引数で呼び出される関数です。adaptive-fill-regexp を、直前の空でない行の先頭にあるテキストに照合しようとします。一致した場合はその一致箇所の末尾を返し、一致しなかった場合は nil を返します。ただし、現在の行が接頭辞(例:‘-’)で始まる場合は、2つの接頭辞が揃うように、代わりに直前の行の接頭辞の先頭を返します。このアンカーは、ブロックコメントにおける indent-relative のようなインデント動作を実現する際に有用です。

インデントユーティリティ

パーサーベースのインデント規則を記述する際に役立つユーティリティ関数をいくつか紹介します。

コマンド: treesit-check-indent mode

このコマンドは、現在のバッファのインデントをメジャーモード mode と照合します。mode に従って現在のバッファをインデントし、その結果を現在のインデントと比較します。その後、差分を表示するバッファをポップアップで表示します。正しいインデント(ターゲット)は緑色で、現在のインデントは赤色で表示されます。

インデント規則を記述する際には、treesit-inspect-mode(Tree-sitter Language Grammar を参照)を使用すると便利です。