Generalize treesit-defun functions to "things"
Change the "defun" in some functions (e.g. treesit--defuns-around) to "thing". Add a function treesit-thing-at-point. * lisp/treesit.el (treesit--thing-unpack-pattern): New subroutine. (treesit-beginning-of-defun) (treesit-end-of-defun): Use new function treesit--navigate-thing. (treesit--defuns-around): Generalize into treesit--thing-around. (treesit--top-level-defun): Generalize into treesit--top-level-thing. (treesit--navigate-defun): Generalize into treesit--navigate-thing. (treesit-thing-at-point): Generalized from treesit-defun-at-point. (treesit-defun-at-point): Use treesit-thing-at-point to do tht work.
This commit is contained in:
parent
e8b34109ee
commit
a819ca5a93
1 changed files with 77 additions and 51 deletions
128
lisp/treesit.el
128
lisp/treesit.el
|
@ -1621,6 +1621,17 @@ nil.")
|
||||||
"The delimiter used to connect several defun names.
|
"The delimiter used to connect several defun names.
|
||||||
This is used in `treesit-add-log-current-defun'.")
|
This is used in `treesit-add-log-current-defun'.")
|
||||||
|
|
||||||
|
(defsubst treesit--thing-unpack-pattern (pattern)
|
||||||
|
"Unpack PATTERN in the shape of `treesit-defun-type-regexp'.
|
||||||
|
|
||||||
|
Basically,
|
||||||
|
|
||||||
|
(unpack REGEXP) = (REGEXP . nil)
|
||||||
|
(unpack (REGEXP . PRED)) = (REGEXP . PRED)"
|
||||||
|
(if (consp pattern)
|
||||||
|
pattern
|
||||||
|
(cons pattern nil)))
|
||||||
|
|
||||||
(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.
|
||||||
|
|
||||||
|
@ -1633,12 +1644,16 @@ 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")
|
||||||
(when-let* ((arg (or arg 1))
|
(pcase-let* ((arg (or arg 1))
|
||||||
(dest (treesit--navigate-defun (point) (- arg) 'beg)))
|
(`(,regexp . ,pred)
|
||||||
(goto-char dest)
|
(treesit--thing-unpack-pattern treesit-defun-type-regexp))
|
||||||
(when treesit-defun-skipper
|
(dest (treesit--navigate-thing
|
||||||
(funcall treesit-defun-skipper))
|
(point) (- arg) 'beg regexp pred)))
|
||||||
t))
|
(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.
|
||||||
|
@ -1650,11 +1665,15 @@ 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")
|
||||||
(when-let* ((arg (or arg 1))
|
(pcase-let* ((arg (or arg 1))
|
||||||
(dest (treesit--navigate-defun (point) arg 'end)))
|
(`(,regexp . ,pred)
|
||||||
(goto-char dest)
|
(treesit--thing-unpack-pattern treesit-defun-type-regexp))
|
||||||
(when treesit-defun-skipper
|
(dest (treesit--navigate-thing
|
||||||
(funcall treesit-defun-skipper))))
|
(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.
|
||||||
|
@ -1680,17 +1699,15 @@ the current line if the beginning of the defun is indented."
|
||||||
;; parent:
|
;; parent:
|
||||||
;; 1. node covers pos
|
;; 1. node covers pos
|
||||||
;; 2. smallest such node
|
;; 2. smallest such node
|
||||||
(defun treesit--defuns-around (pos regexp &optional pred)
|
(defun treesit--things-around (pos regexp &optional pred)
|
||||||
"Return the previous, next, and parent defun around POS.
|
"Return the previous, next, and parent thing around POS.
|
||||||
|
|
||||||
Return a list of (PREV NEXT PARENT), where PREV and NEXT are
|
Return a list of (PREV NEXT PARENT), where PREV and NEXT are
|
||||||
previous and next sibling defuns around POS, and PARENT is the
|
previous and next sibling things around POS, and PARENT is the
|
||||||
parent defun surrounding POS. All of three could be nil if no
|
parent thing surrounding POS. All of three could be nil if no
|
||||||
sound defun exists.
|
sound things exists.
|
||||||
|
|
||||||
REGEXP and PRED are the same as in `treesit-defun-type-regexp'.
|
REGEXP and PRED are the same as in `treesit-thing-at-point'."
|
||||||
|
|
||||||
Assumes `treesit-defun-type-regexp' is set."
|
|
||||||
(let* ((node (treesit-node-at pos))
|
(let* ((node (treesit-node-at pos))
|
||||||
;; NODE-BEFORE/AFTER = NODE when POS is completely in NODE,
|
;; NODE-BEFORE/AFTER = NODE when POS is completely in NODE,
|
||||||
;; but if not, that means point could be in between two
|
;; but if not, that means point could be in between two
|
||||||
|
@ -1750,9 +1767,9 @@ Assumes `treesit-defun-type-regexp' is set."
|
||||||
return cursor))
|
return cursor))
|
||||||
result))
|
result))
|
||||||
|
|
||||||
(defun treesit--top-level-defun (node regexp &optional pred)
|
(defun treesit--top-level-thing (node regexp &optional pred)
|
||||||
"Return the top-level parent defun of NODE.
|
"Return the top-level parent thing of NODE.
|
||||||
REGEXP and PRED are the same as in `treesit-defun-type-regexp'."
|
REGEXP and PRED are the same as in `treesit-thing-at-point'."
|
||||||
(let* ((pred (or pred (lambda (_) t))))
|
(let* ((pred (or pred (lambda (_) t))))
|
||||||
;; `treesit-search-forward-goto' will make sure the matched node
|
;; `treesit-search-forward-goto' will make sure the matched node
|
||||||
;; is before POS.
|
;; is before POS.
|
||||||
|
@ -1792,25 +1809,23 @@ REGEXP and PRED are the same as in `treesit-defun-type-regexp'."
|
||||||
;; -> Obviously we don't want to go to parent's end, instead, we
|
;; -> Obviously we don't want to go to parent's end, instead, we
|
||||||
;; want to go to parent's prev-sibling's end. Again, we recurse
|
;; want to go to parent's prev-sibling's end. Again, we recurse
|
||||||
;; in the function to do that.
|
;; in the function to do that.
|
||||||
(defun treesit--navigate-defun (pos arg side &optional recursing)
|
(defun treesit--navigate-thing (pos arg side regexp &optional pred recursing)
|
||||||
"Navigate defun ARG steps from POS.
|
"Navigate thing ARG steps from POS.
|
||||||
|
|
||||||
If ARG is positive, move forward that many steps, if negative,
|
If ARG is positive, move forward that many steps, if negative,
|
||||||
move backward. If SIDE is `beg', stop at the beginning of a
|
move backward. If SIDE is `beg', stop at the beginning of a
|
||||||
defun, if SIDE is `end', stop at the end.
|
thing, if SIDE is `end', stop at the end.
|
||||||
|
|
||||||
This function doesn't actually move point, it just returns the
|
This function doesn't actually move point, it just returns the
|
||||||
position it would move to. If there aren't enough defuns to move
|
position it would move to. If there aren't enough things to move
|
||||||
across, return nil.
|
across, return nil.
|
||||||
|
|
||||||
|
REGEXP and PRED are the same as in `treesit-thing-at-point'.
|
||||||
|
|
||||||
RECURSING is an internal parameter, if non-nil, it means this
|
RECURSING is an internal parameter, if non-nil, it means this
|
||||||
function is called recursively."
|
function is called recursively."
|
||||||
(pcase-let*
|
(pcase-let*
|
||||||
((counter (abs arg))
|
((counter (abs arg))
|
||||||
(`(,regexp . ,pred)
|
|
||||||
(if (consp treesit-defun-type-regexp)
|
|
||||||
treesit-defun-type-regexp
|
|
||||||
(cons treesit-defun-type-regexp nil)))
|
|
||||||
;; Move POS to the beg/end of NODE. If NODE is nil, terminate.
|
;; Move POS to the beg/end of NODE. If NODE is nil, terminate.
|
||||||
;; Return the position we moved to.
|
;; Return the position we moved to.
|
||||||
(advance (lambda (node)
|
(advance (lambda (node)
|
||||||
|
@ -1824,13 +1839,13 @@ function is called recursively."
|
||||||
(while (> counter 0)
|
(while (> counter 0)
|
||||||
(pcase-let
|
(pcase-let
|
||||||
((`(,prev ,next ,parent)
|
((`(,prev ,next ,parent)
|
||||||
(treesit--defuns-around pos regexp pred)))
|
(treesit--things-around pos regexp pred)))
|
||||||
;; When PARENT is nil, nested and top-level are the same, if
|
;; When PARENT is nil, nested and top-level are the same, if
|
||||||
;; there is a PARENT, make PARENT to be the top-level parent
|
;; there is a PARENT, make PARENT to be the top-level parent
|
||||||
;; and pretend there is no nested PREV and NEXT.
|
;; and pretend there is no nested PREV and NEXT.
|
||||||
(when (and (eq treesit-defun-tactic 'top-level)
|
(when (and (eq treesit-defun-tactic 'top-level)
|
||||||
parent)
|
parent)
|
||||||
(setq parent (treesit--top-level-defun
|
(setq parent (treesit--top-level-thing
|
||||||
parent regexp pred)
|
parent regexp pred)
|
||||||
prev nil
|
prev nil
|
||||||
next nil))
|
next nil))
|
||||||
|
@ -1851,9 +1866,9 @@ function is called recursively."
|
||||||
;; (recursing) until we got out of the parents until
|
;; (recursing) until we got out of the parents until
|
||||||
;; (1) there is a next sibling defun, or (2) no more
|
;; (1) there is a next sibling defun, or (2) no more
|
||||||
;; parents [2].
|
;; parents [2].
|
||||||
(setq pos (or (treesit--navigate-defun
|
(setq pos (or (treesit--navigate-thing
|
||||||
(treesit-node-end (or next parent))
|
(treesit-node-end (or next parent))
|
||||||
1 'beg t)
|
1 'beg regexp pred t)
|
||||||
(throw 'term nil)))
|
(throw 'term nil)))
|
||||||
;; Normal case.
|
;; Normal case.
|
||||||
(setq pos (funcall advance (or next parent))))
|
(setq pos (funcall advance (or next parent))))
|
||||||
|
@ -1863,9 +1878,9 @@ function is called recursively."
|
||||||
(parent t)
|
(parent t)
|
||||||
(t nil)))
|
(t nil)))
|
||||||
;; Special case: go to prev end-of-defun.
|
;; Special case: go to prev end-of-defun.
|
||||||
(setq pos (or (treesit--navigate-defun
|
(setq pos (or (treesit--navigate-thing
|
||||||
(treesit-node-start (or prev parent))
|
(treesit-node-start (or prev parent))
|
||||||
-1 'end t)
|
-1 'end regexp pred t)
|
||||||
(throw 'term nil)))
|
(throw 'term nil)))
|
||||||
;; Normal case.
|
;; Normal case.
|
||||||
(setq pos (funcall advance (or prev parent)))))
|
(setq pos (funcall advance (or prev parent)))))
|
||||||
|
@ -1875,6 +1890,28 @@ 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)
|
||||||
|
"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.
|
||||||
|
|
||||||
|
Return the top-level defun if TACTIC is `top-level', return the
|
||||||
|
immediate parent thing if TACTIC is `nested'."
|
||||||
|
(pcase-let* ((`(,_ ,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
|
||||||
|
;; mode.
|
||||||
|
(node (or (and (eq (treesit-node-start next) (point))
|
||||||
|
next)
|
||||||
|
parent)))
|
||||||
|
(if (eq tactic 'top-level)
|
||||||
|
(treesit--top-level-thing node regexp pred)
|
||||||
|
node)))
|
||||||
|
|
||||||
(defun treesit-defun-at-point ()
|
(defun treesit-defun-at-point ()
|
||||||
"Return the defun node at point or nil if none is found.
|
"Return the defun node at point or nil if none is found.
|
||||||
|
|
||||||
|
@ -1884,21 +1921,10 @@ 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)
|
(pcase-let ((`(,regexp . ,pred)
|
||||||
(if (consp treesit-defun-type-regexp)
|
(treesit--thing-unpack-pattern
|
||||||
treesit-defun-type-regexp
|
treesit-defun-type-regexp)))
|
||||||
(cons treesit-defun-type-regexp nil)))
|
(treesit-thing-at-point regexp treesit-defun-tactic pred))))
|
||||||
(`(,_ ,next ,parent)
|
|
||||||
(treesit--defuns-around (point) regexp pred))
|
|
||||||
;; If point is at the beginning of a defun, we
|
|
||||||
;; prioritize that defun over the parent in nested
|
|
||||||
;; mode.
|
|
||||||
(node (or (and (eq (treesit-node-start next) (point))
|
|
||||||
next)
|
|
||||||
parent)))
|
|
||||||
(if (eq treesit-defun-tactic 'top-level)
|
|
||||||
(treesit--top-level-defun node regexp pred)
|
|
||||||
node))))
|
|
||||||
|
|
||||||
(defun treesit-defun-name (node)
|
(defun treesit-defun-name (node)
|
||||||
"Return the defun name of NODE.
|
"Return the defun name of NODE.
|
||||||
|
|
Loading…
Add table
Reference in a new issue