Redefine treesit-node-at

The old 'treesit-node-at' becomes 'treesit-node-on'.  The new
'treesit-node-at' has slightly different semantics.  Now
'treesit-node-on' gets the smallest node covering a range and
'treesit-node-at' gets the smallest node after a position.

The reason of change can be found in the docstring of
'treesit-node-on' (the BEWARE part): its result can be sometimes
surprising/unexpected.

* doc/lispref/parsing.texi (Retrieving Node): Update manual.
* lisp/treesit.el (treesit-node-at): Change to new definition.
(treesit-node-on): Inherits the old definition of
'treesit-node-at'.  Parameter END is now mandatory.
(treesit-language-at, treesit-node-field-name): Use the new '-on'
function.
(treesit-font-lock-fontify-region, treesit-simple-indent-presets,
treesit-indent): Use the new '-at' function.
* test/src/treesit-tests.el (treesit-node-supplemental): Update tests.
This commit is contained in:
Yuan Fu 2022-05-13 13:38:21 -07:00
parent eebe5a1d61
commit 78df03329d
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
3 changed files with 69 additions and 16 deletions

View file

@ -471,11 +471,10 @@ is retrieved. Using an outdated node throws
@heading Retrieving node from syntax tree
@defun treesit-node-at beg &optional end parser-or-lang named
This function returns the @emph{smallest} node that covers the span
from @var{beg} to @var{end}. In other words, the start of the node
@code{<=} @var{beg}, and the end of the node @code{>=} @var{end}. If
@var{end} is omitted, it defaults to the value of @var{beg}.
@defun treesit-node-at beg end &optional parser-or-lang named
This function returns the @emph{smallest} node that starts at or after
the @var{point}. In other words, the start of the node is equal or
greater than @var{point}.
When @var{parser-or-lang} is nil, this function uses the first parser
in @var{treesit-parser-list} in the current buffer. If
@ -489,12 +488,34 @@ instead (@pxref{tree-sitter named node, named node}).
@example
@group
;; Find the node at point in a C parser's syntax tree.
(treesit-node-at (point) (point) 'c)
(treesit-node-on (point) 'c)
@c @result{} #<treesit-node from 1 to 4 in *scratch*>
@end group
@end example
@end defun
@defun treesit-node-on beg end &optional parser-or-lang named
This function returns the @emph{smallest} node that covers the span
from @var{beg} to @var{end}. In other words, the start of the node is
less or equal to @var{beg}, and the end of the node is greater or
equal to @var{end}.
@emph{Beware}, Calling this function on an empty line that is not
inside any top-level construct (function definition, etc) most
probably will give you the root node, because the root node is the
smallest node that covers that empty line. You probably want to use
@code{treesit-node-at} instead.
When @var{parser-or-lang} is nil, this function uses the first parser
in @var{treesit-parser-list} in the current buffer. If
@var{parser-or-lang} is a parser object, it use that parser; if
@var{parser-or-lang} is a language, it finds the first parser using
that language in @var{treesit-parser-list} and use that.
If @var{named} is non-nil, this function looks for a named node
instead (@pxref{tree-sitter named node, named node}).
@end defun
@defun treesit-parser-root-node parser
This function returns the root node of the syntax tree generated by
@var{parser}.

View file

@ -90,7 +90,7 @@ Return the root node of the syntax tree."
(defun treesit-language-at (point)
"Return the language used at POINT."
(cl-loop for parser in treesit-parser-list
if (treesit-node-at point nil parser)
if (treesit-node-on point point parser)
return (treesit-parser-language parser)))
(defun treesit-set-ranges (parser-or-lang ranges)
@ -128,11 +128,40 @@ Return the root node of the syntax tree."
(treesit-parser-language
(treesit-node-parser node)))
(defun treesit-node-at (beg &optional end parser-or-lang named)
(defun treesit-node-at (point &optional parser-or-lang named)
"Return the smallest node that starts at or after POINT.
\"Starts at or after POINT\" means the start of the node is
greater or larger than POINT. Return nil if none find. If NAMED
non-nil, only look for named node.
If PARSER-OR-LANG is nil, use the first parser in
`treesit-parser-list'; if PARSER-OR-LANG is a parser, use
that parser; if PARSER-OR-LANG is a language, find a parser using
that language in the current buffer, and use that."
(let ((node (if (treesit-parser-p parser-or-lang)
(treesit-parser-root-node parser-or-lang)
(treesit-buffer-root-node parser-or-lang))))
;; TODO: We might want a `treesit-node-decendant-for-pos' in C.
(while (cond ((< (treesit-node-end node) point)
(setq node (treesit-node-next-sibling node))
t)
((treesit-node-child node 0 named)
(setq node (treesit-node-child node 0 named))
t)))
node))
(defun treesit-node-on (beg end &optional parser-or-lang named)
"Return the smallest node covering BEG to END.
If omitted, END defaults to BEG. Return nil if none find. If
NAMED non-nil, only look for named node. NAMED defaults to nil.
BEWARE! Calling this function on an empty line that is not
inside any top-level construct (function definition, etc) most
probably will give you the root node, because the root node is
the smallest node that covers that empty line. You probably want
to use `treesit-node-at' instead.
Return nil if none find. If NAMED non-nil, only look for named
node.
If PARSER-OR-LANG is nil, use the first parser in
`treesit-parser-list'; if PARSER-OR-LANG is a parser, use
@ -358,7 +387,7 @@ If LOUDLY is non-nil, message some debugging information."
(when-let* ((language (nth 0 setting))
(match-pattern (nth 1 setting))
(parser (treesit-get-parser-create language)))
(when-let ((node (treesit-node-at start end parser)))
(when-let ((node (treesit-node-on start end parser)))
(let ((captures (treesit-query-capture
node match-pattern
;; Specifying the range is important. More
@ -500,7 +529,7 @@ See `treesit-simple-indent-presets'.")
(forward-line -1)
(skip-chars-forward " \t")
(treesit-node-start
(treesit-node-at (point) nil nil t))))))
(treesit-node-at (point) nil t))))))
"A list of presets.
These presets that can be used as MATHER and ANCHOR in
`treesit-simple-indent-rules'.
@ -622,8 +651,7 @@ of the current line.")
(point)))
(smallest-node
(cl-loop for parser in treesit-parser-list
for node = (treesit-node-at
bol nil parser)
for node = (treesit-node-at bol parser)
if node return node))
(node (treesit-parent-while
smallest-node
@ -639,7 +667,7 @@ of the current line.")
(parent (cond ((and node parser)
(treesit-node-parent node))
(parser
(treesit-node-at bol nil parser))
(treesit-node-at bol parser))
(t nil)))
(`(,anchor . ,offset)
(funcall treesit-indent-function node parent bol)))

View file

@ -331,7 +331,11 @@
'json))
;; `treesit-node-at'.
(should (equal (treesit-node-string
(treesit-node-at 1 2 'json))
(treesit-node-at 1 'json))
"(\"[\")"))
;; `treesit-node-on'
(should (equal (treesit-node-string
(treesit-node-on 1 2 'json))
"(\"[\")"))
;; `treesit-buffer-root-node'.
(should (treesit-node-eq