mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
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.
This commit is contained in:
parent
35c2ca2ca6
commit
f8e219ebfa
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user