From: Yuan Fu Date: Sun, 25 Sep 2022 03:42:03 +0000 (-0700) Subject: Improve treesit-search-forward-goto X-Git-Tag: emacs-29.0.90~1870 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=ef6e18a6b9ab103f3f076b35100d09cff1687396;p=emacs.git Improve treesit-search-forward-goto * doc/lispref/parsing.texi (Retrieving Node): Update manual. * lisp/treesit.el (treesit-search-forward-goto): Instead of taking a node, use the node at point, and make sure we make progress. --- diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 868b9bc0744..32fc6a69a54 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -623,33 +623,12 @@ If @var{up} is non-nil, this function will only traverse to siblings and parents. In that case, only 1 3 4 8 would be traversed. @end defun -@defun treesit-search-forward-goto start predicate side &optional all backward up -For those who want to not only search for a node but also move to it, -this is the function to use. Parameter @var{start}, @var{predicate}, -@var{all}, @var{backward}, and @var{up} are the same as in +@defun treesit-search-forward-goto predicate side &optional all backward up +This function jumps to the start or end of the next node in buffer +that matches @var{predicate}. Parameters @var{predicate}, @var{all}, +@var{backward}, and @var{up} are the same as in @code{treesit-search-forward}. And @var{side} controls which side of the matched no do we stop at, it can be @code{'start} or @code{'end}. - -Beware of this common pitfall: - -@example -@group -;; This will not move point forward. -(while (treesit-search-forward-goto - (treesit-node-at (point)) - "xxx" - 'start) - ...) - -;; This is will move point forward. -(let ((node (treesit-node-at (point)))) - (while (setq node (treesit-search-forward-goto - node "xxx" 'start)) - ...)) -@end group -@end example - -The exact reason why is left as an exercise for the reader. @end defun @defun treesit-induce-sparse-tree root predicate &optional process-fn limit diff --git a/lisp/treesit.el b/lisp/treesit.el index def2e6259e9..001404d88d2 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -723,13 +723,13 @@ indentation (target) is in green, current indentation is in red." ;;; Search (defun treesit-search-forward-goto - (start predicate side &optional all backward up) - "Search for node in the parse tree and move point to it. + (predicate side &optional all backward up) + "Search forward for a node and move to it. -Start traversing the tree from node START, and match PREDICATE with -each node along the way (except START). PREDICATE can be either a -regexp that matches against each node's type, or a function that takes -a node and returns nil/non-nil for match/no match. +Stops at the first node after point that matches PREDICATE. +PREDICATE can be either a regexp that matches against each node's +type, or a function that takes a node and returns nil/non-nil for +match/no match. If a node matches, move to that node and return the node, otherwise return nil. SIDE controls whether we move to the start @@ -737,11 +737,24 @@ or end of the matches node, it can be either \\='start or \\='end. ALL, BACKWARD, and UP are the same as in `treesit-search-forward'." - (when-let ((node (treesit-search-forward - start predicate all backward up))) - (pcase side - ('start (goto-char (treesit-node-start node))) - ('end (goto-char (treesit-node-end node)))) + (let ((node (treesit-node-at (point))) + (start (point))) + ;; When searching forward, it is possible for (point) < start, + ;; because `treesit-search-forward' goes to parents. + (while (and node (if backward + (>= (point) start) + (<= (point) start))) + (setq node (treesit-search-forward + node predicate all backward up)) + (if-let ((pos (pcase side + ('start (treesit-node-start node)) + ('end (treesit-node-end node))))) + (goto-char pos))) + ;; If we made reverse progress, go back to where we started. + (when (if backward + (>= (point) start) + (<= (point) start)) + (goto-char start)) node)) ;;; Debugging