emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

emacs-29 cb761eb7ac 4/4: Use the new tree-sitter commands


From: Yuan Fu
Subject: emacs-29 cb761eb7ac 4/4: Use the new tree-sitter commands
Date: Thu, 15 Dec 2022 20:47:22 -0500 (EST)

branch: emacs-29
commit cb761eb7ac4197706658a68bb853c3fc8909d84e
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>

    Use the new tree-sitter commands
    
    * lisp/progmodes/c-ts-mode.el (c-ts-mode--defun-valid-p)
    (c-ts-mode--defun-skipper): New functions.
    (c-ts-base-mode): Setup defun navigation.
    * lisp/progmodes/sh-script.el (bash-ts-mode): Setup defun navigation.
    * lisp/treesit.el (treesit-beginning-of-defun)
    (treesit-end-of-defun): Change to new implementation, which is
    intended to be used as commands.
    (treesit-major-mode-setup): Setup remap for beginning/end-of-defun
    commands.
---
 lisp/progmodes/c-ts-mode.el | 35 ++++++++++++++++++----
 lisp/progmodes/sh-script.el |  2 ++
 lisp/treesit.el             | 71 ++++++++++++++++++++++-----------------------
 3 files changed, 66 insertions(+), 42 deletions(-)

diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index ff2ff63fd8..97e29ca13b 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -531,6 +531,27 @@ the subtrees."
       (if (looking-at "\\s<\\|\n")
          (forward-line 1)))))
 
+(defun c-ts-mode--defun-valid-p (node)
+  (if (string-match-p
+       (rx (or "struct_specifier"
+               "enum_specifier"
+               "union_specifier"))
+       (treesit-node-type node))
+      (null
+       (treesit-node-top-level
+        node (rx (or "function_definition"
+                     "type_definition"))))
+    t))
+
+(defun c-ts-mode--defun-skipper ()
+  "Custom defun skipper for `c-ts-mode' and friends.
+Structs in C ends with a semicolon, but the semicolon is not
+considered part of the struct node, so point would stop before
+the semicolon.  This function skips the semicolon."
+  (when (looking-at (rx (* (or " " "\t")) ";"))
+    (goto-char (match-end 0)))
+  (treesit-default-defun-skipper))
+
 (defun c-ts-mode-indent-defun ()
   "Indent the current top-level declaration syntactically.
 
@@ -559,12 +580,14 @@ the subtrees."
 
   ;; Navigation.
   (setq-local treesit-defun-type-regexp
-              (regexp-opt '("function_definition"
-                            "type_definition"
-                            "struct_specifier"
-                            "enum_specifier"
-                            "union_specifier"
-                            "class_specifier")))
+              (cons (regexp-opt '("function_definition"
+                                  "type_definition"
+                                  "struct_specifier"
+                                  "enum_specifier"
+                                  "union_specifier"
+                                  "class_specifier"))
+                    #'c-ts-mode--defun-valid-p))
+  (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
 
   ;; Nodes like struct/enum/union_specifier can appear in
   ;; function_definitions, so we need to find the top-level node.
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 76e8d5b074..85da9e89f9 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1613,6 +1613,7 @@ This mode automatically falls back to `sh-mode' if the 
buffer is
 not written in Bash or sh."
   :syntax-table sh-mode-syntax-table
   (when (treesit-ready-p 'bash)
+    (treesit-parser-create 'bash)
     (setq-local treesit-font-lock-feature-list
                 '(( comment function)
                   ( command declaration-command keyword string)
@@ -1620,6 +1621,7 @@ not written in Bash or sh."
                   ( bracket delimiter misc-punctuation operator)))
     (setq-local treesit-font-lock-settings
                 sh-mode--treesit-settings)
+    (setq-local treesit-defun-type-regexp "function_definition")
     (treesit-major-mode-setup)))
 
 (advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 58b85ddba3..353a9bc12c 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1624,40 +1624,37 @@ For the detailed semantic see 
`treesit-defun-prefer-top-level'."
       finally return node))))
 
 (defun treesit-beginning-of-defun (&optional arg)
-  "Tree-sitter `beginning-of-defun' function.
-ARG is the same as in `beginning-of-defun'."
-  (let ((arg (or arg 1))
-        (node (treesit-node-at (point))))
-    (if (> arg 0)
-        ;; Go backward.
-        (while (and (> arg 0)
-                    (setq node (treesit-search-forward-goto
-                                node treesit-defun-type-regexp t t)))
-          (setq node (treesit--defun-maybe-top-level node))
-          (setq arg (1- arg)))
-      ;; Go forward.
-      (while (and (< arg 0)
-                  (setq node (treesit-search-forward-goto
-                              node treesit-defun-type-regexp)))
-        (setq node (treesit--defun-maybe-top-level node))
-        (setq arg (1+ arg))))
-    (when node
-      (goto-char (treesit-node-start node))
-      t)))
-
-(defun treesit-end-of-defun ()
-  "Tree-sitter `end-of-defun' function."
-  ;; Why not simply get the largest node at point: when point is at
-  ;; (point-min), that gives us the root node.
-  (let* ((node (treesit-search-forward
-                (treesit-node-at (point)) treesit-defun-type-regexp t t))
-         (top (treesit--defun-maybe-top-level node)))
-    ;; Technically `end-of-defun' should only call this function when
-    ;; point is at the beginning of a defun, so TOP should always be
-    ;; non-nil, but things happen, and we want to be safe, so check
-    ;; for TOP anyway.
-    (when top
-      (goto-char (treesit-node-end top)))))
+  "Move backward to the beginning of a defun.
+
+With argument ARG, do it that many times.  Negative ARG means
+move forward to the ARGth following beginning of defun.
+
+If search is successful, return t, otherwise return nil.
+
+This is a tree-sitter equivalent of `beginning-of-defun'.
+Behavior of this function depends on `treesit-defun-type-regexp'
+and `treesit-defun-skipper'."
+  (interactive "^p")
+  (when-let ((dest (treesit--navigate-defun (point) (- arg) 'beg)))
+    (goto-char dest)
+    (when treesit-defun-skipper
+      (funcall treesit-defun-skipper))
+    t))
+
+(defun treesit-end-of-defun (&optional arg _)
+  "Move forward to next end of defun.
+
+With argument ARG, do it that many times.
+Negative argument -N means move back to Nth preceding end of defun.
+
+This is a tree-sitter equivalent of `end-of-defun'.  Behavior of
+this function depends on `treesit-defun-type-regexp' and
+`treesit-defun-skipper'."
+  (interactive "^p\nd")
+  (when-let ((dest (treesit--navigate-defun (point) arg 'end)))
+    (goto-char dest)
+    (when treesit-defun-skipper
+      (funcall treesit-defun-skipper))))
 
 (defun treesit-default-defun-skipper ()
   "Skips spaces after navigating a defun.
@@ -1953,8 +1950,10 @@ before calling this function."
     (setq-local indent-region-function #'treesit-indent-region))
   ;; Navigation.
   (when treesit-defun-type-regexp
-    (setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
-    (setq-local end-of-defun-function #'treesit-end-of-defun)))
+    (keymap-set (current-local-map) "<remap> <beginning-of-defun>"
+                #'treesit-beginning-of-defun)
+    (keymap-set (current-local-map) "<remap> <end-of-defun>"
+                #'treesit-end-of-defun)))
 
 ;;; Debugging
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]