Here is an example of an indentation function:
(eval-when-compile (require 'cl)) ;For the `case' macro.
(defun sample-smie-rules (kind token)
(case kind
(:elem (case token
(basic sample-indent-basic)))
(:after
(cond
((equal token ",") (smie-rule-separator kind))
((equal token ":=") sample-indent-basic)))
(:before
(cond
((equal token ",") (smie-rule-separator kind))
((member token '("begin" "(" "{"))
(if (smie-rule-hanging-p) (smie-rule-parent)))
((equal token "if")
(and (not (smie-rule-bolp)) (smie-rule-prev-p "else")
(smie-rule-parent)))))))
A few things to note:
sample-indent-basic is nil, then SMIE uses the global
setting smie-indent-basic. The major mode could have set
smie-indent-basic buffer-locally instead, but that
is discouraged.
"," make SMIE try to be
more clever when the comma separator is placed at the beginning of
lines. It tries to outdent the separator so as to align the code after
the comma; for example:
x = longfunctionname (
arg1
, arg2
);
":=" exists because otherwise
SMIE would treat ":=" as an infix operator and would align the
right argument with the left one.
"begin" is an example of the use
of virtual indentation: This rule is used only when "begin" is
hanging, which can happen only when "begin" is not at the
beginning of a line. So this is not used when indenting
"begin" itself but only when indenting something relative to this
"begin". Concretely, this rule changes the indentation from:
if x > 0 then begin
dosomething(x);
end
to
if x > 0 then begin
dosomething(x);
end
"if" is similar to the one for
"begin", but where the purpose is to treat "else if"
as a single unit, so as to align a sequence of tests rather than indent
each test further to the right. This function does this only in the
case where the "if" is not placed on a separate line, hence the
smie-rule-bolp test.
If we know that the "else" is always aligned with its "if"
and is always at the beginning of a line, we can use a more efficient
rule:
((equal token "if")
(and (not (smie-rule-bolp)) (smie-rule-prev-p "else")
(save-excursion
(sample-smie-backward-token) ;Jump before the "else".
(cons 'column (current-column)))))
The advantage of this formulation is that it reuses the indentation of
the previous "else", rather than going all the way back to the
first "if" of the sequence.