From: Yuan Fu Date: Fri, 13 May 2022 20:38:21 +0000 (-0700) Subject: Redefine treesit-node-at X-Git-Tag: emacs-29.0.90~1928 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=78df03329d1e942d5617c0f09f264792e24a063d;p=emacs.git 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. --- 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 @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{} # @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}. 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." (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))) 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 @@ '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