インデント関数の例を以下に示します。
(defun sample-smie-rules (kind token)
(pcase (cons kind token)
(`(:elem . basic) sample-indent-basic)
(`(,_ . ",") (smie-rule-separator kind))
(`(:after . ":=") sample-indent-basic)
(`(:before . ,(or `"begin" `"(" `"{"))
(if (smie-rule-hanging-p) (smie-rule-parent)))
(`(:before . "if")
(and (not (smie-rule-bolp)) (smie-rule-prev-p "else")
(smie-rule-parent)))))
いくつか注意点があります:
sample-indent-basic
が nil の場合、SMIE はグローバル設定の smie-indent-basic を使用します。メジャーモードが代わりにバッファローカルに smie-indent-basic を設定することも可能ですが、それは推奨されません。
","
のルールにより、カンマ区切り記号が行頭に配置された場合、SMIEはより巧妙な処理を試みます。具体的には、カンマ以降のコードを揃えるために、区切り記号をインデントして配置しようとします。例えば:
x = longfunctionname (
arg1
, arg2
);
":=" 以降のインデントに関する規則が存在するのは、そうしないと SMIE が
":=" を中置演算子として扱い、右引数を左引数と揃えてしまうためです。
"begin"
の前のインデントに関するルールは、仮想インデントの使用例です。このルールは、"begin" がぶら下がっている場合にのみ適用されますが、これは "begin" が行頭にない場合にのみ起こり得ます。したがって、このルールは "begin" 自体をインデントする際に使われるのではなく、この "begin"
を基準として何かをインデントする際にのみ使用されます。具体的には、このルールによってインデントが次のように変更されます:
if x > 0 then begin
dosomething(x);
end
へ
if x > 0 then begin
dosomething(x);
end
"if" より前のインデントに関するルールは "begin" の場合と同様ですが、ここでは "else if"
を一つの単位として扱い、各テストをさらに右にインデントするのではなく、一連のテストを揃えることを目的としています。この機能は、"if" が別行に配置されていない場合にのみ適用され、それによって smie-rule-bolp のテストが実現されます。
"else"が常に"if"と揃っており、かつ常に行頭にあることが分かっているなら、より効率的なルールを使用できます:
((equal token "if")
(and (not (smie-rule-bolp))
(smie-rule-prev-p "else")
(save-excursion
(sample-smie-backward-token)
(cons 'column (current-column)))))
この記述方式の利点は、シーケンスの最初の "if" まで遡るのではなく、直前の
"else" のインデントを再利用する点にあります。