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.
This commit is contained in:
parent
037407ad95
commit
cb761eb7ac
3 changed files with 65 additions and 41 deletions
|
@ -531,6 +531,27 @@ the subtrees."
|
||||||
(if (looking-at "\\s<\\|\n")
|
(if (looking-at "\\s<\\|\n")
|
||||||
(forward-line 1)))))
|
(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 ()
|
(defun c-ts-mode-indent-defun ()
|
||||||
"Indent the current top-level declaration syntactically.
|
"Indent the current top-level declaration syntactically.
|
||||||
|
|
||||||
|
@ -559,12 +580,14 @@ the subtrees."
|
||||||
|
|
||||||
;; Navigation.
|
;; Navigation.
|
||||||
(setq-local treesit-defun-type-regexp
|
(setq-local treesit-defun-type-regexp
|
||||||
(regexp-opt '("function_definition"
|
(cons (regexp-opt '("function_definition"
|
||||||
"type_definition"
|
"type_definition"
|
||||||
"struct_specifier"
|
"struct_specifier"
|
||||||
"enum_specifier"
|
"enum_specifier"
|
||||||
"union_specifier"
|
"union_specifier"
|
||||||
"class_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
|
;; 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.
|
||||||
|
|
|
@ -1613,6 +1613,7 @@ This mode automatically falls back to `sh-mode' if the buffer is
|
||||||
not written in Bash or sh."
|
not written in Bash or sh."
|
||||||
:syntax-table sh-mode-syntax-table
|
:syntax-table sh-mode-syntax-table
|
||||||
(when (treesit-ready-p 'bash)
|
(when (treesit-ready-p 'bash)
|
||||||
|
(treesit-parser-create 'bash)
|
||||||
(setq-local treesit-font-lock-feature-list
|
(setq-local treesit-font-lock-feature-list
|
||||||
'(( comment function)
|
'(( comment function)
|
||||||
( command declaration-command keyword string)
|
( command declaration-command keyword string)
|
||||||
|
@ -1620,6 +1621,7 @@ not written in Bash or sh."
|
||||||
( bracket delimiter misc-punctuation operator)))
|
( bracket delimiter misc-punctuation operator)))
|
||||||
(setq-local treesit-font-lock-settings
|
(setq-local treesit-font-lock-settings
|
||||||
sh-mode--treesit-settings)
|
sh-mode--treesit-settings)
|
||||||
|
(setq-local treesit-defun-type-regexp "function_definition")
|
||||||
(treesit-major-mode-setup)))
|
(treesit-major-mode-setup)))
|
||||||
|
|
||||||
(advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode
|
(advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode
|
||||||
|
|
|
@ -1624,40 +1624,37 @@ For the detailed semantic see `treesit-defun-prefer-top-level'."
|
||||||
finally return node))))
|
finally return node))))
|
||||||
|
|
||||||
(defun treesit-beginning-of-defun (&optional arg)
|
(defun treesit-beginning-of-defun (&optional arg)
|
||||||
"Tree-sitter `beginning-of-defun' function.
|
"Move backward to the beginning of a defun.
|
||||||
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 ()
|
With argument ARG, do it that many times. Negative ARG means
|
||||||
"Tree-sitter `end-of-defun' function."
|
move forward to the ARGth following beginning of defun.
|
||||||
;; Why not simply get the largest node at point: when point is at
|
|
||||||
;; (point-min), that gives us the root node.
|
If search is successful, return t, otherwise return nil.
|
||||||
(let* ((node (treesit-search-forward
|
|
||||||
(treesit-node-at (point)) treesit-defun-type-regexp t t))
|
This is a tree-sitter equivalent of `beginning-of-defun'.
|
||||||
(top (treesit--defun-maybe-top-level node)))
|
Behavior of this function depends on `treesit-defun-type-regexp'
|
||||||
;; Technically `end-of-defun' should only call this function when
|
and `treesit-defun-skipper'."
|
||||||
;; point is at the beginning of a defun, so TOP should always be
|
(interactive "^p")
|
||||||
;; non-nil, but things happen, and we want to be safe, so check
|
(when-let ((dest (treesit--navigate-defun (point) (- arg) 'beg)))
|
||||||
;; for TOP anyway.
|
(goto-char dest)
|
||||||
(when top
|
(when treesit-defun-skipper
|
||||||
(goto-char (treesit-node-end top)))))
|
(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 ()
|
(defun treesit-default-defun-skipper ()
|
||||||
"Skips spaces after navigating a defun.
|
"Skips spaces after navigating a defun.
|
||||||
|
@ -1953,8 +1950,10 @@ before calling this function."
|
||||||
(setq-local indent-region-function #'treesit-indent-region))
|
(setq-local indent-region-function #'treesit-indent-region))
|
||||||
;; Navigation.
|
;; Navigation.
|
||||||
(when treesit-defun-type-regexp
|
(when treesit-defun-type-regexp
|
||||||
(setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
|
(keymap-set (current-local-map) "<remap> <beginning-of-defun>"
|
||||||
(setq-local end-of-defun-function #'treesit-end-of-defun)))
|
#'treesit-beginning-of-defun)
|
||||||
|
(keymap-set (current-local-map) "<remap> <end-of-defun>"
|
||||||
|
#'treesit-end-of-defun)))
|
||||||
|
|
||||||
;;; Debugging
|
;;; Debugging
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue