summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/parsing.texi38
-rw-r--r--lisp/progmodes/c-ts-mode.el37
-rw-r--r--lisp/treesit.el45
3 files changed, 103 insertions, 17 deletions
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index e213363298d..918e197676e 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 d3291722331..28e99732fe2 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 2b30da4be7a..355c6b6b99a 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