[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
emacs-29 cb761eb7ac 4/4: Use the new tree-sitter commands
From: |
Yuan Fu |
Subject: |
emacs-29 cb761eb7ac 4/4: Use the new tree-sitter commands |
Date: |
Thu, 15 Dec 2022 20:47:22 -0500 (EST) |
branch: emacs-29
commit cb761eb7ac4197706658a68bb853c3fc8909d84e
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>
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.
---
lisp/progmodes/c-ts-mode.el | 35 ++++++++++++++++++----
lisp/progmodes/sh-script.el | 2 ++
lisp/treesit.el | 71 ++++++++++++++++++++++-----------------------
3 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index ff2ff63fd8..97e29ca13b 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -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.
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 76e8d5b074..85da9e89f9 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -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
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 58b85ddba3..353a9bc12c 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -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)))
-
-(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)))))
+ "Move backward to the beginning of a defun.
+
+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