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
3 changed files with 103 additions and 17 deletions
|
@ -1727,6 +1727,9 @@ indentation.
|
||||||
If @code{treesit-defun-type-regexp} is non-@code{nil}, it sets up
|
If @code{treesit-defun-type-regexp} is non-@code{nil}, it sets up
|
||||||
navigation functions for @code{beginning-of-defun} and
|
navigation functions for @code{beginning-of-defun} and
|
||||||
@code{end-of-defun}.
|
@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 itemize
|
||||||
@end defun
|
@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,
|
For supporting mixing of multiple languages in a major mode,
|
||||||
@pxref{Multiple Languages}.
|
@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
|
@node Tree-sitter C API
|
||||||
@section Tree-sitter C API Correspondence
|
@section Tree-sitter C API Correspondence
|
||||||
|
|
||||||
|
|
|
@ -481,6 +481,25 @@ For NODE, OVERRIDE, START, and END, see
|
||||||
|
|
||||||
;;; Imenu
|
;;; 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)
|
(defun c-ts-mode--imenu-1 (node)
|
||||||
"Helper for `c-ts-mode--imenu'.
|
"Helper for `c-ts-mode--imenu'.
|
||||||
Find string representation for NODE and set marker, then recurse
|
Find string representation for NODE and set marker, then recurse
|
||||||
|
@ -488,22 +507,7 @@ the subtrees."
|
||||||
(let* ((ts-node (car node))
|
(let* ((ts-node (car node))
|
||||||
(subtrees (mapcan #'c-ts-mode--imenu-1 (cdr node)))
|
(subtrees (mapcan #'c-ts-mode--imenu-1 (cdr node)))
|
||||||
(name (when ts-node
|
(name (when ts-node
|
||||||
(treesit-node-text
|
(treesit-defun-name ts-node)))
|
||||||
(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"))))))
|
|
||||||
(marker (when ts-node
|
(marker (when ts-node
|
||||||
(set-marker (make-marker)
|
(set-marker (make-marker)
|
||||||
(treesit-node-start ts-node)))))
|
(treesit-node-start ts-node)))))
|
||||||
|
@ -682,6 +686,7 @@ ARG is passed to `fill-paragraph'."
|
||||||
"class_specifier"))
|
"class_specifier"))
|
||||||
#'c-ts-mode--defun-valid-p))
|
#'c-ts-mode--defun-valid-p))
|
||||||
(setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
|
(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
|
;; Nodes like struct/enum/union_specifier can appear in
|
||||||
;; function_definitions, so we need to find the top-level node.
|
;; 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.")
|
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)
|
(defun treesit-beginning-of-defun (&optional arg)
|
||||||
"Move backward to the beginning of a defun.
|
"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)
|
(if (eq treesit-defun-tactic 'top-level)
|
||||||
(treesit--top-level-defun node regexp pred)
|
(treesit--top-level-defun node regexp pred)
|
||||||
node)))
|
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
|
;;; Activating tree-sitter
|
||||||
|
|
||||||
|
@ -1979,7 +2018,11 @@ before calling this function."
|
||||||
;; the variables. In future we should update `end-of-defun' to
|
;; the variables. In future we should update `end-of-defun' to
|
||||||
;; work with nested defuns.
|
;; work with nested defuns.
|
||||||
(setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
|
(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
|
;;; Debugging
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue