]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new variable 'down-list-function' for 'treesit-down-list'
authorJuri Linkov <juri@linkov.net>
Sun, 29 Dec 2024 17:51:18 +0000 (19:51 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sat, 4 Jan 2025 20:24:44 +0000 (21:24 +0100)
* lisp/emacs-lisp/lisp.el (down-list-default-function): New function.
(down-list-function): New variable (bug#73404).
(down-list): Move meat to 'down-list-default-function',
and call 'down-list-function' when non-nil.  Don't raise an error
in strings or comments when 'down-list-function' is non-nil.

* lisp/treesit.el (treesit--scan-error): New internal function.
(treesit-forward-sexp, treesit-forward-list): Use 'treesit--scan-error'.
(treesit-down-list): New function.
(treesit-major-mode-setup): Set 'down-list-function' to
'treesit-down-list'.

(cherry picked from commit 3c50edb2b500c6ac18696e99c3f8df597dea54d4)

etc/NEWS
lisp/emacs-lisp/lisp.el
lisp/treesit.el

index d1a0b2ebe503246bdcfc10d9fc77d2c101db03d3..68f3892fdb63fb4d3a7ad856b7f475ff82cd8d66 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -847,6 +847,11 @@ Tree-sitter conditionally sets 'forward-list-function' for major modes
 that have defined 'sexp-list' in 'treesit-thing-settings' to enable
 the 'forward-list' motion command.
 
+*** New function 'treesit-down-list'.
+Tree-sitter conditionally sets 'down-list-function' for major modes
+that have defined 'sexp-list' in 'treesit-thing-settings' to enable
+the 'down-list' motion command.
+
 +++
 *** New function 'treesit-language-display-name'.
 This new function returns the display name of a language given the
index dac9dbcd83dc99d328ec9a8df39a638f372049ef..f61464054163c634c921a6456f29aaf62f186078 100644 (file)
@@ -187,6 +187,17 @@ report errors as appropriate for this kind of usage."
   (or arg (setq arg 1))
   (forward-list (- arg) interactive))
 
+(defun down-list-default-function (&optional arg)
+  "Default function for `down-list-function'."
+  (let ((inc (if (> arg 0) 1 -1)))
+    (while (/= arg 0)
+      (goto-char (or (scan-lists (point) inc -1) (buffer-end arg)))
+      (setq arg (- arg inc)))))
+
+(defvar down-list-function nil
+  "If non-nil, `down-list' delegates to this function.
+Should take the same arguments and behave similarly to `down-list'.")
+
 (defun down-list (&optional arg interactive)
   "Move forward down one level of parentheses.
 This command will also work on other parentheses-like expressions
@@ -194,20 +205,21 @@ defined by the current language mode.
 With ARG, do this that many times.
 A negative argument means move backward but still go down a level.
 This command assumes point is not in a string or comment.
+Calls `down-list-function' to do the work, if that is non-nil.
 If INTERACTIVE is non-nil, as it is interactively,
 report errors as appropriate for this kind of usage."
   (interactive "^p\nd")
-  (when (ppss-comment-or-string-start (syntax-ppss))
+  (when (and (null down-list-function)
+             (ppss-comment-or-string-start (syntax-ppss)))
     (user-error "This command doesn't work in strings or comments"))
   (if interactive
       (condition-case _
           (down-list arg nil)
         (scan-error (user-error "At bottom level")))
     (or arg (setq arg 1))
-    (let ((inc (if (> arg 0) 1 -1)))
-      (while (/= arg 0)
-        (goto-char (or (scan-lists (point) inc -1) (buffer-end arg)))
-        (setq arg (- arg inc))))))
+    (if down-list-function
+        (funcall down-list-function arg)
+      (down-list-default-function arg))))
 
 (defun backward-up-list (&optional arg escape-strings no-syntax-crossing)
   "Move backward out of one level of parentheses.
index 21375475d9a9b406c3e9a35707935c8de32a637b..975f9e5c89014d839b26c0cfd299bb4dab36fb40 100644 (file)
@@ -2412,6 +2412,13 @@ delimits medium sized statements in the source code.  It is,
 however, smaller in scope than sentences.  This is used by
 `treesit-forward-sexp' and friends.")
 
+(defun treesit--scan-error (pred arg)
+  (when-let* ((parent (treesit-thing-at (point) pred t))
+              (boundary (treesit-node-child parent (if (> arg 0) -1 0))))
+    (signal 'scan-error (list (format-message "No more %S to move across" pred)
+                              (treesit-node-start boundary)
+                              (treesit-node-end boundary)))))
+
 (defun treesit-forward-sexp (&optional arg)
   "Tree-sitter implementation for `forward-sexp-function'.
 
@@ -2452,13 +2459,7 @@ across atoms (such as symbols or words) inside the list."
         ;; the obstacle, like `forward-sexp' does.  If we couldn't
         ;; find a parent, we simply return nil without moving point,
         ;; then functions like `up-list' will signal "at top level".
-        (when-let* ((parent (treesit-thing-at (point) pred t))
-                    (boundary (if (> arg 0)
-                                  (treesit-node-child parent -1)
-                                (treesit-node-child parent 0))))
-          (signal 'scan-error (list "No more sexp to move across"
-                                    (treesit-node-start boundary)
-                                    (treesit-node-end boundary)))))))
+        (treesit--scan-error pred arg))))
 
 (defun treesit-forward-sexp-list (&optional arg)
   "Alternative tree-sitter implementation for `forward-sexp-function'.
@@ -2533,13 +2534,34 @@ ARG is described in the docstring of `forward-list'."
     (or (if (> arg 0)
             (treesit-end-of-thing pred (abs arg) 'restricted)
           (treesit-beginning-of-thing pred (abs arg) 'restricted))
-        (when-let* ((parent (treesit-thing-at (point) pred t))
-                    (boundary (if (> arg 0)
-                                  (treesit-node-child parent -1)
-                                (treesit-node-child parent 0))))
-          (signal 'scan-error (list "No more group to move across"
-                                    (treesit-node-start boundary)
-                                    (treesit-node-end boundary)))))))
+        (treesit--scan-error pred arg))))
+
+(defun treesit-down-list (&optional arg)
+  "Move forward down one level of parentheses.
+What constitutes a level of parentheses is determined by
+`sexp-list' in `treesit-thing-settings' that usually defines
+parentheses-like expressions.
+
+This command is the tree-sitter variant of `down-list'
+redefined by the variable `down-list-function'.
+
+ARG is described in the docstring of `down-list'."
+  (interactive "^p")
+  (let* ((pred 'sexp-list)
+         (arg (or arg 1))
+         (inc (if (> arg 0) 1 -1)))
+    (while (/= arg 0)
+      (let* ((node (if (> arg 0)
+                       (treesit-thing-next (point) pred)
+                     (treesit-thing-prev (point) pred)))
+             (child (when node
+                      (treesit-node-child node (if (> arg 0) 0 -1))))
+             (pos (when child
+                    (if (> arg 0)
+                        (treesit-node-end child)
+                      (treesit-node-start child)))))
+        (if pos (goto-char pos) (treesit--scan-error pred arg)))
+      (setq arg (- arg inc)))))
 
 (defun treesit-transpose-sexps (&optional arg)
   "Tree-sitter `transpose-sexps' function.
@@ -3466,7 +3488,8 @@ before calling this function."
 
   (when (treesit-thing-defined-p 'sexp-list nil)
     (setq-local forward-sexp-function #'treesit-forward-sexp-list)
-    (setq-local forward-list-function #'treesit-forward-list))
+    (setq-local forward-list-function #'treesit-forward-list)
+    (setq-local down-list-function #'treesit-down-list))
 
   (when (treesit-thing-defined-p 'sentence nil)
     (setq-local forward-sentence-function #'treesit-forward-sentence))