Make sure NODE is not the root node in tree-sitter indent (bug#60602)

There are two possible ways to solve the problem raised in the bug
report: either make sure NODE is never the root (so that parent is
never nil), or allow parent to be nil.

If we go with the latter, a lot of matcher and anchor functions need
change (they need to guard against a null parent).  I tried it, and
needing to check for null parent is pretty annoying.  In comparison,
if NODE is never the root, it is very convenient for the user, and it
doesn't complicate the rule that much (and it's rather intuitive,
people usually don't think of the case where NODE is the root node).
So that's what I choose.

* doc/lispref/modes.texi (Parser-based Indentation): Update manual.
* lisp/treesit.el (treesit-indent-function): Update docstring.
(treesit--indent-1): Make sure NODE is not the root.
This commit is contained in:
Yuan Fu 2023-01-08 19:05:19 -08:00
parent 1238fa8e49
commit ef87c75566
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
2 changed files with 12 additions and 9 deletions

View file

@ -4936,10 +4936,10 @@ Each @var{matcher} or @var{anchor} is a function that takes three
arguments: @var{node}, @var{parent}, and @var{bol}. The argument arguments: @var{node}, @var{parent}, and @var{bol}. The argument
@var{bol} is the buffer position whose indentation is required: the @var{bol} is the buffer position whose indentation is required: the
position of the first non-whitespace character after the beginning of position of the first non-whitespace character after the beginning of
the line. The argument @var{node} is the largest (highest-in-tree) the line. The argument @var{node} is the largest node that starts at
node that starts at that position; and @var{parent} is the parent of that position (and is not a root node); and @var{parent} is the parent
@var{node}. However, when that position is in a whitespace or inside of @var{node}. However, when that position is in a whitespace or
a multi-line string, no node can start at that position, so inside a multi-line string, no node can start at that position, so
@var{node} is @code{nil}. In that case, @var{parent} would be the @var{node} is @code{nil}. In that case, @var{parent} would be the
smallest node that spans that position. smallest node that spans that position.

View file

@ -1341,10 +1341,10 @@ and returns
(ANCHOR . OFFSET). (ANCHOR . OFFSET).
BOL is the position of the beginning of the line; NODE is the BOL is the position of the beginning of the line; NODE is the
\"largest\" node that starts at BOL; PARENT is its parent; ANCHOR \"largest\" node that starts at BOL (and isn't a root node);
is a point (not a node), and OFFSET is a number. Emacs finds the PARENT is its parent; ANCHOR is a point (not a node), and OFFSET
column of ANCHOR and adds OFFSET to it as the final indentation is a number. Emacs finds the column of ANCHOR and adds OFFSET to
of the current line.") it as the final indentation of the current line.")
(defun treesit--indent-1 () (defun treesit--indent-1 ()
"Indent the current line. "Indent the current line.
@ -1362,10 +1362,13 @@ Return (ANCHOR . OFFSET). This function is used by
((treesit-language-at (point)) ((treesit-language-at (point))
(treesit-node-at bol (treesit-language-at (point)))) (treesit-node-at bol (treesit-language-at (point))))
(t (treesit-node-at bol)))) (t (treesit-node-at bol))))
(root (treesit-parser-root-node
(treesit-node-parser smallest-node)))
(node (treesit-parent-while (node (treesit-parent-while
smallest-node smallest-node
(lambda (node) (lambda (node)
(eq bol (treesit-node-start node)))))) (and (eq bol (treesit-node-start node))
(not (treesit-node-eq node root)))))))
(let* (let*
((parser (if smallest-node ((parser (if smallest-node
(treesit-node-parser smallest-node) (treesit-node-parser smallest-node)