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)))
node))
;;; Navigation
;;; Navigation, defun, things
(defvar-local treesit-defun-type-regexp nil
"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.")
(defvar-local treesit-block-type-regexp nil
"Like `treesit-defun-type-regexp', but for blocks.")
(defvar-local treesit-defun-tactic 'nested
"Determines how does Emacs treat nested defuns.
If the value is `top-level', Emacs only moves across top-level
@ -1632,6 +1635,36 @@ Basically,
pattern
(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)
"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'
and `treesit-defun-skipper'."
(interactive "^p")
(pcase-let* ((arg (or arg 1))
(`(,regexp . ,pred)
(treesit--thing-unpack-pattern treesit-defun-type-regexp))
(dest (treesit--navigate-thing
(point) (- arg) 'beg regexp pred)))
(when dest
(goto-char dest)
(when treesit-defun-skipper
(funcall treesit-defun-skipper))
t)))
(when (treesit-beginning-of-thing treesit-defun-type-regexp arg)
(when treesit-defun-skipper
(funcall treesit-defun-skipper))
t))
(defun treesit-end-of-defun (&optional arg _)
"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
`treesit-defun-skipper'."
(interactive "^p\nd")
(pcase-let* ((arg (or arg 1))
(`(,regexp . ,pred)
(treesit--thing-unpack-pattern treesit-defun-type-regexp))
(dest (treesit--navigate-thing
(point) arg 'end regexp pred)))
(when dest
(goto-char dest)
(when treesit-defun-skipper
(funcall treesit-defun-skipper)))))
(when (treesit-end-of-thing treesit-defun-type-regexp arg)
(when treesit-defun-skipper
(funcall treesit-defun-skipper))))
(defun treesit-default-defun-skipper ()
"Skips spaces after navigating a defun.
@ -1890,17 +1911,20 @@ function is called recursively."
(if (eq counter 0) pos nil)))
;; 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.
\"Thing\" is defined by REGEXP: if a node's type matches REGEXP,
it is a thing. The \"thing\" could be further restricted 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.
\"Thing\" is defined by PATTERN, which can be either a string
REGEXP or a cons cell (REGEXP . PRED): if a node's type matches
REGEXP, it is a thing. The \"thing\" could be further restricted
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
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))
;; If point is at the beginning of a thing, we
;; 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."
(when treesit-defun-type-regexp
(pcase-let ((`(,regexp . ,pred)
(treesit--thing-unpack-pattern
treesit-defun-type-regexp)))
(treesit-thing-at-point regexp treesit-defun-tactic pred))))
(treesit-thing-at-point
treesit-defun-type-regexp treesit-defun-tactic)))
(defun treesit-defun-name (node)
"Return the defun name of NODE.