]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new tactic to treesit-navigate-thing (bug#78703)
authorYuan Fu <casouri@gmail.com>
Tue, 10 Jun 2025 04:41:17 +0000 (21:41 -0700)
committerEshel Yaron <me@eshelyaron.com>
Wed, 18 Jun 2025 08:01:44 +0000 (10:01 +0200)
* doc/emacs/programs.texi (Moving by Defuns):
* doc/lispref/parsing.texi (User-defined Things): Describe the
new tactic.
* lisp/treesit.el (treesit-navigate-thing): Add new tactic.

(cherry picked from commit 0a629abfbbdb34efcefe7b7d6f933bc7d90b5501)

doc/emacs/programs.texi
doc/lispref/parsing.texi
lisp/treesit.el

index f8ad7596b4e1c1d317a6f06130a4d0ad1e96bc70..609fc3ee4a29b71fa47017ae8c5691cbc9e05241 100644 (file)
@@ -241,13 +241,17 @@ bindings for that purpose.
 @cindex nested defuns
 @vindex treesit-defun-tactic
   Some programming languages supported @dfn{nested defuns}, whereby a
-defun (such as a function or a method or a class) can be defined
-inside (i.e., as part of the body) of another defun.  The commands
-described above by default find the beginning and the end of the
-@emph{innermost} defun around point.  Major modes based on the
-tree-sitter library provide control of this behavior: if the variable
-@code{treesit-defun-tactic} is set to the value @code{top-level}, the
-defun commands will find the @emph{outermost} defuns instead.
+defun (such as a function or a method or a class) can be defined inside
+(i.e., as part of the body) of another defun.  The commands described
+above by default find the beginning and the end of the @emph{innermost}
+defun around point.  Major modes based on the tree-sitter library
+provide control of this behavior: by default, the value of
+@code{treesit-defun-tactic} is set to @code{nested}; if it's set
+to@code{top-level}, the defun commands will find the @emph{outermost}
+defuns instead; if the value is set to @code{parent-first}, the defun
+command always tries to move out of the current enclosing defun rather
+than moving to the previous or next defun around point; if there's no
+enclosing defun, it moves to the previous or next defun.
 
 @node Moving by Sentences
 @subsection Moving by Sentences
index f155bdbd1dd74b9a42239f3113b95853da73ec78..922ba217920ef7a43a44899b7dc840dcfe1fb01e 100644 (file)
@@ -1787,15 +1787,17 @@ Like in @code{treesit-thing-prev}, @var{thing} can be a thing symbol
 defined in @code{treesit-thing-settings}, or a predicate.
 
 @var{tactic} determines how this function moves between things.  It can
-be @code{nested}, @code{top-level}, @code{restricted}, or @code{nil}.
-@code{nested} or @code{nil} means normal nested navigation: first try to
-move across siblings; if there aren't any siblings left in the current
-level, move to the parent, then its siblings, and so on.
-@code{top-level} means only navigate across top-level things and ignore
-nested things.  @code{restricted} means movement is restricted within
-the thing that encloses @var{position}, if there is such a thing.  This
-tactic is useful for commands that want to stop at the current nesting
-level and not move up.
+be @code{nested}, @code{top-level}, @code{restricted},
+@code{parent-first}, or @code{nil}.  @code{nested} or @code{nil} means
+normal nested navigation: first try to move across siblings; if there
+aren't any siblings left in the current level, move to the parent, then
+its siblings, and so on.  @code{top-level} means only navigate across
+top-level things and ignore nested things.  @code{restricted} means
+movement is restricted within the thing that encloses @var{position}, if
+there is such a thing.  This tactic is useful for commands that want to
+stop at the current nesting level and not move up.  @var{parent-first}
+means move to the parent if there is one; and move to siblings if
+there's no parent.
 @end defun
 
 @defun treesit-thing-at position thing &optional strict
index 9526a075296bd4a1b3d88170d5eff586b786863a..5d16433c0e5ce4665a00b54f4f87c616d23d71bd 100644 (file)
@@ -3687,15 +3687,15 @@ across, return nil.
 THING can be a regexp, a predicate function, and more.  See
 `treesit-thing-settings' for details.
 
-TACTIC determines how does this function move between things.  It
-can be `nested', `top-level', `restricted', or nil.  `nested'
-means normal nested navigation: try to move to siblings first,
-and if there aren't enough siblings, move to the parent and its
-siblings.  `top-level' means only consider top-level things, and
-nested things are ignored.  `restricted' means movement is
-restricted inside the thing that encloses POS (i.e., parent),
-should there be one.  If omitted, TACTIC is considered to be
-`nested'.
+TACTIC determines how does this function move between things.  It can be
+`nested', `top-level', `restricted', `parent-first' or nil.  `nested'
+means normal nested navigation: try to move to siblings first, and if
+there aren't enough siblings, move to the parent and its siblings.
+`top-level' means only consider top-level things, and nested things are
+ignored.  `restricted' means movement is restricted inside the thing
+that encloses POS (i.e., parent), should there be one.  `parent' means
+move to the parent if there is one; and move to siblings if there's no
+parent.  If omitted, TACTIC is considered to be `nested'.
 
 RECURSING is an internal parameter, if non-nil, it means this
 function is called recursively."
@@ -3729,6 +3729,11 @@ function is called recursively."
             (setq parent (treesit-node-top-level parent thing t)
                   prev nil
                   next nil))
+          ;; When PARENT is nil, `nested' and `parent-first' are the
+          ;; same, if there is a PARENT, pretend there is no nested PREV
+          ;; and NEXT so the following code moves to the parent.
+          (when (and (eq tactic 'parent-first) parent)
+            (setq prev nil next nil))
           ;; If TACTIC is `restricted', the implementation is simple.
           ;; In principle we don't go to parent's beg/end for
           ;; `restricted' tactic, but if the parent is a "leaf thing"