Further generalize treesit-defun functions

Two new functions, treesit-beginning/end-of-thing.  And
treesit-thing-at-point's signature changes.

* lisp/treesit.el (treesit-block-type-regexp): New variable.
(treesit-beginning-of-thing)
(treesit-end-of-thing): Generalized from
treesit-beginning/end-of-defun.
(treesit-beginning-of-defun)
(treesit-end-of-defun): Use the new functions.
(treesit-thing-at-point): Accept PATTERN rather than REGEXP and PRED.
(treesit-defun-at-point): Adjust for the new signature of
treesit-thing-at-point.
This commit is contained in:
Yuan Fu 2022-12-24 22:08:17 -08:00
parent a819ca5a93
commit 79584a206b
No known key found for this signature in database
GPG key ID: 56E19BC57664A442

View file

@ -1582,7 +1582,7 @@ BACKWARD and ALL are the same as in `treesit-search-forward'."
(goto-char current-pos))) (goto-char current-pos)))
node)) node))
;;; Navigation ;;; Navigation, defun, things
(defvar-local treesit-defun-type-regexp nil (defvar-local treesit-defun-type-regexp nil
"A regexp that matches the node type of defun nodes. "A regexp that matches the node type of defun nodes.
@ -1596,6 +1596,9 @@ for invalid node.
This is used by `treesit-beginning-of-defun' and friends.") This is used by `treesit-beginning-of-defun' and friends.")
(defvar-local treesit-block-type-regexp nil
"Like `treesit-defun-type-regexp', but for blocks.")
(defvar-local treesit-defun-tactic 'nested (defvar-local treesit-defun-tactic 'nested
"Determines how does Emacs treat nested defuns. "Determines how does Emacs treat nested defuns.
If the value is `top-level', Emacs only moves across top-level If the value is `top-level', Emacs only moves across top-level
@ -1632,6 +1635,36 @@ Basically,
pattern pattern
(cons pattern nil))) (cons pattern nil)))
(defun treesit-beginning-of-thing (pattern &optional arg)
"Like `beginning-of-defun', but generalized into things.
PATTERN is like `treesit-defun-type-regexp', ARG
is the same as in `beginning-of-defun'.
Return non-nil if successfully moved, nil otherwise."
(pcase-let* ((arg (or arg 1))
(`(,regexp . ,pred) (treesit--thing-unpack-pattern
pattern))
(dest (treesit--navigate-thing
(point) (- arg) 'beg regexp pred)))
(when dest
(goto-char dest))))
(defun treesit-end-of-thing (pattern &optional arg)
"Like `end-of-defun', but generalized into things.
PATTERN is like `treesit-defun-type-regexp', ARG is the same as
in `end-of-defun'.
Return non-nil if successfully moved, nil otherwise."
(pcase-let* ((arg (or arg 1))
(`(,regexp . ,pred) (treesit--thing-unpack-pattern
pattern))
(dest (treesit--navigate-thing
(point) arg 'end regexp pred)))
(when dest
(goto-char dest))))
(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.
@ -1644,16 +1677,10 @@ This is a tree-sitter equivalent of `beginning-of-defun'.
Behavior of this function depends on `treesit-defun-type-regexp' Behavior of this function depends on `treesit-defun-type-regexp'
and `treesit-defun-skipper'." and `treesit-defun-skipper'."
(interactive "^p") (interactive "^p")
(pcase-let* ((arg (or arg 1)) (when (treesit-beginning-of-thing treesit-defun-type-regexp arg)
(`(,regexp . ,pred) (when treesit-defun-skipper
(treesit--thing-unpack-pattern treesit-defun-type-regexp)) (funcall treesit-defun-skipper))
(dest (treesit--navigate-thing t))
(point) (- arg) 'beg regexp pred)))
(when dest
(goto-char dest)
(when treesit-defun-skipper
(funcall treesit-defun-skipper))
t)))
(defun treesit-end-of-defun (&optional arg _) (defun treesit-end-of-defun (&optional arg _)
"Move forward to next end of defun. "Move forward to next end of defun.
@ -1665,15 +1692,9 @@ This is a tree-sitter equivalent of `end-of-defun'. Behavior of
this function depends on `treesit-defun-type-regexp' and this function depends on `treesit-defun-type-regexp' and
`treesit-defun-skipper'." `treesit-defun-skipper'."
(interactive "^p\nd") (interactive "^p\nd")
(pcase-let* ((arg (or arg 1)) (when (treesit-end-of-thing treesit-defun-type-regexp arg)
(`(,regexp . ,pred) (when treesit-defun-skipper
(treesit--thing-unpack-pattern treesit-defun-type-regexp)) (funcall treesit-defun-skipper))))
(dest (treesit--navigate-thing
(point) arg 'end regexp pred)))
(when dest
(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.
@ -1890,17 +1911,20 @@ function is called recursively."
(if (eq counter 0) pos nil))) (if (eq counter 0) pos nil)))
;; TODO: In corporate into thing-at-point. ;; TODO: In corporate into thing-at-point.
(defun treesit-thing-at-point (regexp tactic &optional pred) (defun treesit-thing-at-point (pattern tactic)
"Return the thing node at point or nil if none is found. "Return the thing node at point or nil if none is found.
\"Thing\" is defined by REGEXP: if a node's type matches REGEXP, \"Thing\" is defined by PATTERN, which can be either a string
it is a thing. The \"thing\" could be further restricted by REGEXP or a cons cell (REGEXP . PRED): if a node's type matches
PRED: if non-nil, PRED should be a function that takes a node and REGEXP, it is a thing. The \"thing\" could be further restricted
returns t if the node is a \"thing\", and nil if not. by PRED: if non-nil, PRED should be a function that takes a node
and returns t if the node is a \"thing\", and nil if not.
Return the top-level defun if TACTIC is `top-level', return the Return the top-level defun if TACTIC is `top-level', return the
immediate parent thing if TACTIC is `nested'." immediate parent thing if TACTIC is `nested'."
(pcase-let* ((`(,_ ,next ,parent) (pcase-let* ((`(,regexp . ,pred)
(treesit--thing-unpack-pattern pattern))
(`(,_ ,next ,parent)
(treesit--things-around (point) regexp pred)) (treesit--things-around (point) regexp pred))
;; If point is at the beginning of a thing, we ;; If point is at the beginning of a thing, we
;; prioritize that thing over the parent in nested ;; prioritize that thing over the parent in nested
@ -1921,10 +1945,8 @@ is `top-level', return the immediate parent defun if it is
Return nil if `treesit-defun-type-regexp' is not set." Return nil if `treesit-defun-type-regexp' is not set."
(when treesit-defun-type-regexp (when treesit-defun-type-regexp
(pcase-let ((`(,regexp . ,pred) (treesit-thing-at-point
(treesit--thing-unpack-pattern treesit-defun-type-regexp treesit-defun-tactic)))
treesit-defun-type-regexp)))
(treesit-thing-at-point regexp treesit-defun-tactic pred))))
(defun treesit-defun-name (node) (defun treesit-defun-name (node)
"Return the defun name of NODE. "Return the defun name of NODE.