emacs-diffs
[Top][All Lists]
Advanced

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

emacs-29 f8e219ebfa 3/5: Add treesit-defun-name and friends


From: Yuan Fu
Subject: emacs-29 f8e219ebfa 3/5: Add treesit-defun-name and friends
Date: Sat, 24 Dec 2022 21:43:13 -0500 (EST)

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

    Add treesit-defun-name and friends
    
    1. We now have treesit-defun-name, powered by
    treesit-defun-name-function.
    2. We now have treesit-add-log-current-defun, which powers
    add-log-current-defun.
    3. c-ts-mode updates its code to take advantage of these new features.
    4. Manual updates.
    
    * doc/lispref/parsing.texi (Tree-sitter major modes): Add manual for
    new functions.
    * lisp/progmodes/c-ts-mode.el (c-ts-mode--defun-name): New function.
    (c-ts-mode--imenu-1): Extract out into c-ts-mode--defun-name.
    (c-ts-base-mode): Setup treesit-defun-name-function.
    * lisp/treesit.el (treesit-defun-name-function)
    (treesit-add-log-defun-delimiter): New variables.
    (treesit-defun-at-point)
    (treesit-defun-name): New functions.
    (treesit-major-mode-setup): Setup add-log-current-defun-function.
---
 doc/lispref/parsing.texi    | 38 ++++++++++++++++++++++++++++++++++++++
 lisp/progmodes/c-ts-mode.el | 37 +++++++++++++++++++++----------------
 lisp/treesit.el             | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 103 insertions(+), 17 deletions(-)

diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index e213363298..918e197676 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -1727,6 +1727,9 @@ indentation.
 If @code{treesit-defun-type-regexp} is non-@code{nil}, it sets up
 navigation functions for @code{beginning-of-defun} and
 @code{end-of-defun}.
+@item
+If @code{treesit-defun-name-function} is non-@code{nil}, it sets up
+add-log functions used by @code{add-log-current-defun}.
 @end itemize
 @end defun
 
@@ -1737,6 +1740,41 @@ For more information of these built-in tree-sitter 
features,
 For supporting mixing of multiple languages in a major mode,
 @pxref{Multiple Languages}.
 
+Besides @code{beginning-of-defun} and @code{end-of-defun}, Emacs
+provides some additional functions for working with defuns:
+@code{treesit-defun-at-point} returns the defun node at point, and
+@code{treesit-defun-name} returns the name of a defun node.
+
+@defun treesit-defun-at-point
+This function returns the defun node at point, or @code{nil} if none
+is found.  It respects @code{treesit-defun-tactic}: it returns the
+top-level defun if the value is @code{top-level}, and returns the
+immediate enclosing defun if the value is @code{nested}.
+
+This function requires @code{treesit-defun-type-regexp} to work.  If
+it is @code{nil}, this function simply returns @code{nil}.
+@end defun
+
+@defun treesit-defun-name node
+This function returns the defun name of @var{node}.  It returns
+@code{nil} if there is no defun name for @var{node}, or if @var{node}
+is not a defun node, or if @var{node} is @code{nil}.
+
+The defun name is names like function name, class name, struct name,
+etc.
+
+If @code{treesit-defun-name-function} is @code{nil}, this function
+always returns @code{nil}.
+@end defun
+
+@defvar treesit-defun-name-function
+If non-@code{nil}, this variable should store a function that is
+called with a node and returns the defun name of it.  The function
+should have the same semantic as @code{treesit-defun-name}: if the
+node is not a defun node, or the node is a defun node but doesn't have
+a name, or the node is @code{nil}, return @code{nil}.
+@end defvar
+
 @node Tree-sitter C API
 @section Tree-sitter C API Correspondence
 
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index d329172233..28e99732fe 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -481,6 +481,25 @@ For NODE, OVERRIDE, START, and END, see
 
 ;;; Imenu
 
+(defun c-ts-mode--defun-name (node)
+  "Return the name of the defun NODE.
+Return nil if NODE is not a defun node, return an empty string if
+NODE doesn't have a name."
+  (treesit-node-text
+   (pcase (treesit-node-type node)
+     ("function_definition"
+      (treesit-node-child-by-field-name
+       (treesit-node-child-by-field-name node "declarator")
+       "declarator"))
+     ("declaration"
+      (let ((child (treesit-node-child node -1 t)))
+        (pcase (treesit-node-type child)
+          ("identifier" child)
+          (_ (treesit-node-child-by-field-name child "declarator")))))
+     ("struct_specifier"
+      (treesit-node-child-by-field-name node "name")))
+   t))
+
 (defun c-ts-mode--imenu-1 (node)
   "Helper for `c-ts-mode--imenu'.
 Find string representation for NODE and set marker, then recurse
@@ -488,22 +507,7 @@ the subtrees."
   (let* ((ts-node (car node))
          (subtrees (mapcan #'c-ts-mode--imenu-1 (cdr node)))
          (name (when ts-node
-                 (treesit-node-text
-                  (pcase (treesit-node-type ts-node)
-                    ("function_definition"
-                     (treesit-node-child-by-field-name
-                      (treesit-node-child-by-field-name
-                       ts-node "declarator")
-                      "declarator"))
-                    ("declaration"
-                     (let ((child (treesit-node-child ts-node -1 t)))
-                       (pcase (treesit-node-type child)
-                         ("identifier" child)
-                         (_ (treesit-node-child-by-field-name
-                             child "declarator")))))
-                    ("struct_specifier"
-                     (treesit-node-child-by-field-name
-                      ts-node "name"))))))
+                 (treesit-defun-name ts-node)))
          (marker (when ts-node
                    (set-marker (make-marker)
                                (treesit-node-start ts-node)))))
@@ -682,6 +686,7 @@ ARG is passed to `fill-paragraph'."
                                   "class_specifier"))
                     #'c-ts-mode--defun-valid-p))
   (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
+  (setq-local treesit-defun-name-function #'c-ts-mode--defun-name)
 
   ;; Nodes like struct/enum/union_specifier can appear in
   ;; function_definitions, so we need to find the top-level node.
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 2b30da4be7..355c6b6b99 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1612,6 +1612,17 @@ newline after a defun, or the beginning of a defun.
 
 If the value is nil, no skipping is performed.")
 
+(defvar-local treesit-defun-name-function nil
+  "A function called with a node and returns the name of it.
+If the node is a defun node, return the defun name.  E.g., the
+function name of a function.  If the node is not a defun node, or
+the defun node doesn't have a name, or the node is nil, return
+nil.")
+
+(defvar-local treesit-add-log-defun-delimiter "."
+  "The delimiter used to connect several defun names.
+This is used in `treesit-add-log-current-defun'.")
+
 (defun treesit-beginning-of-defun (&optional arg)
   "Move backward to the beginning of a defun.
 
@@ -1885,6 +1896,34 @@ is `top-level', return the immediate parent defun if it 
is
     (if (eq treesit-defun-tactic 'top-level)
         (treesit--top-level-defun node regexp pred)
       node)))
+(defun treesit-defun-name (node)
+  "Return the defun name of NODE.
+
+Return nil if there is no name, or if NODE is not a defun node,
+or if NODE is nil.
+
+If `treesit-defun-name-function' is nil, always return nil."
+  (when treesit-defun-name-function
+    (funcall treesit-defun-name-function node)))
+
+(defun treesit-add-log-current-defun ()
+  "Return the name of the defun at point.
+
+Used for `add-log-current-defun-function'.
+
+The delimiter between nested defun names is controlled by
+`treesit-add-log-defun-delimiter'."
+  (let ((node (treesit-defun-at-point))
+        (name nil))
+    (while node
+      (when-let ((new-name (treesit-defun-name node)))
+        (if name
+            (setq name (concat new-name
+                               treesit-add-log-defun-delimiter
+                               name))
+          (setq name new-name)))
+      (setq node (treesit-node-parent node)))
+    name))
 
 ;;; Activating tree-sitter
 
@@ -1979,7 +2018,11 @@ before calling this function."
     ;; the variables.  In future we should update `end-of-defun' to
     ;; work with nested defuns.
     (setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
-    (setq-local end-of-defun-function #'treesit-end-of-defun)))
+    (setq-local end-of-defun-function #'treesit-end-of-defun))
+  ;; Defun name.
+  (when treesit-defun-name-function
+    (setq-local add-log-current-defun-function
+                #'treesit-add-log-current-defun)))
 
 ;;; Debugging
 



reply via email to

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