以下是一个缩进函数示例:
(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)))))
这种写法的优点是直接复用前一个 "else" 的缩进,
而不必回溯到整个判断序列的第一个 "if"。