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:
Yuan Fu 2022-12-15 17:44:07 -08:00
parent 037407ad95
commit cb761eb7ac
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
3 changed files with 65 additions and 41 deletions

View file

@ -531,6 +531,27 @@ the subtrees."
(if (looking-at "\\s<\\|\n")
(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 ()
"Indent the current top-level declaration syntactically.
@ -559,12 +580,14 @@ the subtrees."
;; Navigation.
(setq-local treesit-defun-type-regexp
(regexp-opt '("function_definition"
"type_definition"
"struct_specifier"
"enum_specifier"
"union_specifier"
"class_specifier")))
(cons (regexp-opt '("function_definition"
"type_definition"
"struct_specifier"
"enum_specifier"
"union_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
;; function_definitions, so we need to find the top-level node.

View file

@ -1613,6 +1613,7 @@ This mode automatically falls back to `sh-mode' if the buffer is
not written in Bash or sh."
:syntax-table sh-mode-syntax-table
(when (treesit-ready-p 'bash)
(treesit-parser-create 'bash)
(setq-local treesit-font-lock-feature-list
'(( comment function)
( command declaration-command keyword string)
@ -1620,6 +1621,7 @@ not written in Bash or sh."
( bracket delimiter misc-punctuation operator)))
(setq-local treesit-font-lock-settings
sh-mode--treesit-settings)
(setq-local treesit-defun-type-regexp "function_definition")
(treesit-major-mode-setup)))
(advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode

View file

@ -1624,40 +1624,37 @@ For the detailed semantic see `treesit-defun-prefer-top-level'."
finally return node))))
(defun treesit-beginning-of-defun (&optional arg)
"Tree-sitter `beginning-of-defun' function.
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)))
"Move backward to the beginning of a defun.
(defun treesit-end-of-defun ()
"Tree-sitter `end-of-defun' function."
;; Why not simply get the largest node at point: when point is at
;; (point-min), that gives us the root node.
(let* ((node (treesit-search-forward
(treesit-node-at (point)) treesit-defun-type-regexp t t))
(top (treesit--defun-maybe-top-level node)))
;; Technically `end-of-defun' should only call this function when
;; point is at the beginning of a defun, so TOP should always be
;; non-nil, but things happen, and we want to be safe, so check
;; for TOP anyway.
(when top
(goto-char (treesit-node-end top)))))
With argument ARG, do it that many times. Negative ARG means
move forward to the ARGth following beginning of defun.
If search is successful, return t, otherwise return nil.
This is a tree-sitter equivalent of `beginning-of-defun'.
Behavior of this function depends on `treesit-defun-type-regexp'
and `treesit-defun-skipper'."
(interactive "^p")
(when-let ((dest (treesit--navigate-defun (point) (- arg) 'beg)))
(goto-char dest)
(when treesit-defun-skipper
(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 ()
"Skips spaces after navigating a defun.
@ -1953,8 +1950,10 @@ before calling this function."
(setq-local indent-region-function #'treesit-indent-region))
;; Navigation.
(when treesit-defun-type-regexp
(setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
(setq-local end-of-defun-function #'treesit-end-of-defun)))
(keymap-set (current-local-map) "<remap> <beginning-of-defun>"
#'treesit-beginning-of-defun)
(keymap-set (current-local-map) "<remap> <end-of-defun>"
#'treesit-end-of-defun)))
;;; Debugging