aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuan Fu2022-05-13 13:38:21 -0700
committerYuan Fu2022-05-13 14:36:37 -0700
commit78df03329d1e942d5617c0f09f264792e24a063d (patch)
treebadb03713f25a02e0d3d74020fa1878fd54d6b43
parenteebe5a1d6114ed54eb3cdd5576f43da76590b8fa (diff)
downloademacs-78df03329d1e942d5617c0f09f264792e24a063d.tar.gz
emacs-78df03329d1e942d5617c0f09f264792e24a063d.zip
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.
-rw-r--r--doc/lispref/parsing.texi33
-rw-r--r--lisp/treesit.el46
-rw-r--r--test/src/treesit-tests.el6
3 files changed, 69 insertions, 16 deletions
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index bbe70ff9b1f..72be91877b6 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -471,11 +471,10 @@ is retrieved. Using an outdated node throws
471 471
472@heading Retrieving node from syntax tree 472@heading Retrieving node from syntax tree
473 473
474@defun treesit-node-at beg &optional end parser-or-lang named 474@defun treesit-node-at beg end &optional parser-or-lang named
475This function returns the @emph{smallest} node that covers the span 475This function returns the @emph{smallest} node that starts at or after
476from @var{beg} to @var{end}. In other words, the start of the node 476the @var{point}. In other words, the start of the node is equal or
477@code{<=} @var{beg}, and the end of the node @code{>=} @var{end}. If 477greater than @var{point}.
478@var{end} is omitted, it defaults to the value of @var{beg}.
479 478
480When @var{parser-or-lang} is nil, this function uses the first parser 479When @var{parser-or-lang} is nil, this function uses the first parser
481in @var{treesit-parser-list} in the current buffer. If 480in @var{treesit-parser-list} in the current buffer. If
@@ -489,12 +488,34 @@ instead (@pxref{tree-sitter named node, named node}).
489@example 488@example
490@group 489@group
491;; Find the node at point in a C parser's syntax tree. 490;; Find the node at point in a C parser's syntax tree.
492(treesit-node-at (point) (point) 'c) 491(treesit-node-on (point) 'c)
493 @c @result{} #<treesit-node from 1 to 4 in *scratch*> 492 @c @result{} #<treesit-node from 1 to 4 in *scratch*>
494@end group 493@end group
495@end example 494@end example
496@end defun 495@end defun
497 496
497@defun treesit-node-on beg end &optional parser-or-lang named
498This function returns the @emph{smallest} node that covers the span
499from @var{beg} to @var{end}. In other words, the start of the node is
500less or equal to @var{beg}, and the end of the node is greater or
501equal to @var{end}.
502
503@emph{Beware}, Calling this function on an empty line that is not
504inside any top-level construct (function definition, etc) most
505probably will give you the root node, because the root node is the
506smallest node that covers that empty line. You probably want to use
507@code{treesit-node-at} instead.
508
509When @var{parser-or-lang} is nil, this function uses the first parser
510in @var{treesit-parser-list} in the current buffer. If
511@var{parser-or-lang} is a parser object, it use that parser; if
512@var{parser-or-lang} is a language, it finds the first parser using
513that language in @var{treesit-parser-list} and use that.
514
515If @var{named} is non-nil, this function looks for a named node
516instead (@pxref{tree-sitter named node, named node}).
517@end defun
518
498@defun treesit-parser-root-node parser 519@defun treesit-parser-root-node parser
499This function returns the root node of the syntax tree generated by 520This function returns the root node of the syntax tree generated by
500@var{parser}. 521@var{parser}.
diff --git a/lisp/treesit.el b/lisp/treesit.el
index eaaa1316af2..dbbe0e409a8 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -90,7 +90,7 @@ Return the root node of the syntax tree."
90(defun treesit-language-at (point) 90(defun treesit-language-at (point)
91 "Return the language used at POINT." 91 "Return the language used at POINT."
92 (cl-loop for parser in treesit-parser-list 92 (cl-loop for parser in treesit-parser-list
93 if (treesit-node-at point nil parser) 93 if (treesit-node-on point point parser)
94 return (treesit-parser-language parser))) 94 return (treesit-parser-language parser)))
95 95
96(defun treesit-set-ranges (parser-or-lang ranges) 96(defun treesit-set-ranges (parser-or-lang ranges)
@@ -128,11 +128,40 @@ Return the root node of the syntax tree."
128 (treesit-parser-language 128 (treesit-parser-language
129 (treesit-node-parser node))) 129 (treesit-node-parser node)))
130 130
131(defun treesit-node-at (beg &optional end parser-or-lang named) 131(defun treesit-node-at (point &optional parser-or-lang named)
132 "Return the smallest node that starts at or after POINT.
133
134\"Starts at or after POINT\" means the start of the node is
135greater or larger than POINT. Return nil if none find. If NAMED
136non-nil, only look for named node.
137
138If PARSER-OR-LANG is nil, use the first parser in
139`treesit-parser-list'; if PARSER-OR-LANG is a parser, use
140that parser; if PARSER-OR-LANG is a language, find a parser using
141that language in the current buffer, and use that."
142 (let ((node (if (treesit-parser-p parser-or-lang)
143 (treesit-parser-root-node parser-or-lang)
144 (treesit-buffer-root-node parser-or-lang))))
145 ;; TODO: We might want a `treesit-node-decendant-for-pos' in C.
146 (while (cond ((< (treesit-node-end node) point)
147 (setq node (treesit-node-next-sibling node))
148 t)
149 ((treesit-node-child node 0 named)
150 (setq node (treesit-node-child node 0 named))
151 t)))
152 node))
153
154(defun treesit-node-on (beg end &optional parser-or-lang named)
132 "Return the smallest node covering BEG to END. 155 "Return the smallest node covering BEG to END.
133 156
134If omitted, END defaults to BEG. Return nil if none find. If 157BEWARE! Calling this function on an empty line that is not
135NAMED non-nil, only look for named node. NAMED defaults to nil. 158inside any top-level construct (function definition, etc) most
159probably will give you the root node, because the root node is
160the smallest node that covers that empty line. You probably want
161to use `treesit-node-at' instead.
162
163Return nil if none find. If NAMED non-nil, only look for named
164node.
136 165
137If PARSER-OR-LANG is nil, use the first parser in 166If PARSER-OR-LANG is nil, use the first parser in
138`treesit-parser-list'; if PARSER-OR-LANG is a parser, use 167`treesit-parser-list'; if PARSER-OR-LANG is a parser, use
@@ -358,7 +387,7 @@ If LOUDLY is non-nil, message some debugging information."
358 (when-let* ((language (nth 0 setting)) 387 (when-let* ((language (nth 0 setting))
359 (match-pattern (nth 1 setting)) 388 (match-pattern (nth 1 setting))
360 (parser (treesit-get-parser-create language))) 389 (parser (treesit-get-parser-create language)))
361 (when-let ((node (treesit-node-at start end parser))) 390 (when-let ((node (treesit-node-on start end parser)))
362 (let ((captures (treesit-query-capture 391 (let ((captures (treesit-query-capture
363 node match-pattern 392 node match-pattern
364 ;; Specifying the range is important. More 393 ;; Specifying the range is important. More
@@ -500,7 +529,7 @@ See `treesit-simple-indent-presets'.")
500 (forward-line -1) 529 (forward-line -1)
501 (skip-chars-forward " \t") 530 (skip-chars-forward " \t")
502 (treesit-node-start 531 (treesit-node-start
503 (treesit-node-at (point) nil nil t)))))) 532 (treesit-node-at (point) nil t))))))
504 "A list of presets. 533 "A list of presets.
505These presets that can be used as MATHER and ANCHOR in 534These presets that can be used as MATHER and ANCHOR in
506`treesit-simple-indent-rules'. 535`treesit-simple-indent-rules'.
@@ -622,8 +651,7 @@ of the current line.")
622 (point))) 651 (point)))
623 (smallest-node 652 (smallest-node
624 (cl-loop for parser in treesit-parser-list 653 (cl-loop for parser in treesit-parser-list
625 for node = (treesit-node-at 654 for node = (treesit-node-at bol parser)
626 bol nil parser)
627 if node return node)) 655 if node return node))
628 (node (treesit-parent-while 656 (node (treesit-parent-while
629 smallest-node 657 smallest-node
@@ -639,7 +667,7 @@ of the current line.")
639 (parent (cond ((and node parser) 667 (parent (cond ((and node parser)
640 (treesit-node-parent node)) 668 (treesit-node-parent node))
641 (parser 669 (parser
642 (treesit-node-at bol nil parser)) 670 (treesit-node-at bol parser))
643 (t nil))) 671 (t nil)))
644 (`(,anchor . ,offset) 672 (`(,anchor . ,offset)
645 (funcall treesit-indent-function node parent bol))) 673 (funcall treesit-indent-function node parent bol)))
diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el
index eb6e85c3fd6..c995542a2ae 100644
--- a/test/src/treesit-tests.el
+++ b/test/src/treesit-tests.el
@@ -331,7 +331,11 @@
331 'json)) 331 'json))
332 ;; `treesit-node-at'. 332 ;; `treesit-node-at'.
333 (should (equal (treesit-node-string 333 (should (equal (treesit-node-string
334 (treesit-node-at 1 2 'json)) 334 (treesit-node-at 1 'json))
335 "(\"[\")"))
336 ;; `treesit-node-on'
337 (should (equal (treesit-node-string
338 (treesit-node-on 1 2 'json))
335 "(\"[\")")) 339 "(\"[\")"))
336 ;; `treesit-buffer-root-node'. 340 ;; `treesit-buffer-root-node'.
337 (should (treesit-node-eq 341 (should (treesit-node-eq