diff options
| author | Yuan Fu | 2022-05-13 13:38:21 -0700 |
|---|---|---|
| committer | Yuan Fu | 2022-05-13 14:36:37 -0700 |
| commit | 78df03329d1e942d5617c0f09f264792e24a063d (patch) | |
| tree | badb03713f25a02e0d3d74020fa1878fd54d6b43 | |
| parent | eebe5a1d6114ed54eb3cdd5576f43da76590b8fa (diff) | |
| download | emacs-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.texi | 33 | ||||
| -rw-r--r-- | lisp/treesit.el | 46 | ||||
| -rw-r--r-- | test/src/treesit-tests.el | 6 |
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 |
| 475 | This function returns the @emph{smallest} node that covers the span | 475 | This function returns the @emph{smallest} node that starts at or after |
| 476 | from @var{beg} to @var{end}. In other words, the start of the node | 476 | the @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 | 477 | greater than @var{point}. |
| 478 | @var{end} is omitted, it defaults to the value of @var{beg}. | ||
| 479 | 478 | ||
| 480 | When @var{parser-or-lang} is nil, this function uses the first parser | 479 | When @var{parser-or-lang} is nil, this function uses the first parser |
| 481 | in @var{treesit-parser-list} in the current buffer. If | 480 | in @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 | ||
| 498 | This function returns the @emph{smallest} node that covers the span | ||
| 499 | from @var{beg} to @var{end}. In other words, the start of the node is | ||
| 500 | less or equal to @var{beg}, and the end of the node is greater or | ||
| 501 | equal to @var{end}. | ||
| 502 | |||
| 503 | @emph{Beware}, Calling this function on an empty line that is not | ||
| 504 | inside any top-level construct (function definition, etc) most | ||
| 505 | probably will give you the root node, because the root node is the | ||
| 506 | smallest node that covers that empty line. You probably want to use | ||
| 507 | @code{treesit-node-at} instead. | ||
| 508 | |||
| 509 | When @var{parser-or-lang} is nil, this function uses the first parser | ||
| 510 | in @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 | ||
| 513 | that language in @var{treesit-parser-list} and use that. | ||
| 514 | |||
| 515 | If @var{named} is non-nil, this function looks for a named node | ||
| 516 | instead (@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 |
| 499 | This function returns the root node of the syntax tree generated by | 520 | This 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 | ||
| 135 | greater or larger than POINT. Return nil if none find. If NAMED | ||
| 136 | non-nil, only look for named node. | ||
| 137 | |||
| 138 | If PARSER-OR-LANG is nil, use the first parser in | ||
| 139 | `treesit-parser-list'; if PARSER-OR-LANG is a parser, use | ||
| 140 | that parser; if PARSER-OR-LANG is a language, find a parser using | ||
| 141 | that 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 | ||
| 134 | If omitted, END defaults to BEG. Return nil if none find. If | 157 | BEWARE! Calling this function on an empty line that is not |
| 135 | NAMED non-nil, only look for named node. NAMED defaults to nil. | 158 | inside any top-level construct (function definition, etc) most |
| 159 | probably will give you the root node, because the root node is | ||
| 160 | the smallest node that covers that empty line. You probably want | ||
| 161 | to use `treesit-node-at' instead. | ||
| 162 | |||
| 163 | Return nil if none find. If NAMED non-nil, only look for named | ||
| 164 | node. | ||
| 136 | 165 | ||
| 137 | If PARSER-OR-LANG is nil, use the first parser in | 166 | If 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. |
| 505 | These presets that can be used as MATHER and ANCHOR in | 534 | These 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 |