mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-16 17:24:23 +00:00
Add 'restricted' tactic in tree-sitter navigation functions
* lisp/treesit.el (treesit-forward-sexp): Add docstring. Use 'restricted' tactic. (treesit-transpose-sexps): Fix docstring. (treesit-beginning-of-thing) (treesit-end-of-thing): Add support for TACTIC. (treesit-beginning-of-defun) (treesit-end-of-defun): Supply treesit-defun-tactic as TACTIC. (treesit--navigate-thing): Add support for TACTIC. Wrap the old form in a new (if (eq tactic 'restricted) (new-code) (old-form)), and supply the TACTIC parameter when recursing.
This commit is contained in:
parent
e54feef094
commit
2ce27563ec
1 changed files with 86 additions and 48 deletions
134
lisp/treesit.el
134
lisp/treesit.el
|
|
@ -1783,15 +1783,17 @@ however, smaller in scope than sentences. This is used by
|
|||
`treesit-forward-sexp' and friends.")
|
||||
|
||||
(defun treesit-forward-sexp (&optional arg)
|
||||
"Tree-sitter implementation for `forward-sexp-function'.
|
||||
ARG is described in the docstring of `forward-sexp-function'."
|
||||
(interactive "^p")
|
||||
(or arg (setq arg 1))
|
||||
(funcall
|
||||
(if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing)
|
||||
treesit-sexp-type-regexp (abs arg)))
|
||||
treesit-sexp-type-regexp (abs arg) 'restricted))
|
||||
|
||||
(defun treesit-transpose-sexps (&optional arg)
|
||||
"Tree-sitter `transpose-sexps' function.
|
||||
Arg is the same as in `transpose-sexps'.
|
||||
ARG is the same as in `transpose-sexps'.
|
||||
|
||||
Locate the node closest to POINT, and transpose that node with
|
||||
its sibling node ARG nodes away.
|
||||
|
|
@ -1896,33 +1898,53 @@ Basically,
|
|||
pattern
|
||||
(cons pattern nil)))
|
||||
|
||||
(defun treesit-beginning-of-thing (pattern &optional arg)
|
||||
(defun treesit-beginning-of-thing (pattern &optional arg tactic)
|
||||
"Like `beginning-of-defun', but generalized into things.
|
||||
|
||||
PATTERN is like `treesit-defun-type-regexp', ARG
|
||||
is the same as in `beginning-of-defun'.
|
||||
|
||||
TACTIC determines how does this function move between things. It
|
||||
can be `nested', `top-level', `restricted', or nil. `nested'
|
||||
means normal nested navigation: try to move to siblings first,
|
||||
and if there aren't enough siblings, move to the parent and its
|
||||
siblings. `top-level' means only consider top-level things, and
|
||||
nested things are ignored. `restricted' means movement is
|
||||
restricted inside the thing that encloses POS (i.e., parent),
|
||||
should there be one. If omitted, TACTIC is considered to be
|
||||
`nested'.
|
||||
|
||||
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)))
|
||||
(point) (- arg) 'beg regexp pred tactic)))
|
||||
(when dest
|
||||
(goto-char dest))))
|
||||
|
||||
(defun treesit-end-of-thing (pattern &optional arg)
|
||||
(defun treesit-end-of-thing (pattern &optional arg tactic)
|
||||
"Like `end-of-defun', but generalized into things.
|
||||
|
||||
PATTERN is like `treesit-defun-type-regexp', ARG is the same as
|
||||
in `end-of-defun'.
|
||||
|
||||
TACTIC determines how does this function move between things. It
|
||||
can be `nested', `top-level', `restricted', or nil. `nested'
|
||||
means normal nested navigation: try to move to siblings first,
|
||||
and if there aren't enough siblings, move to the parent and its
|
||||
siblings. `top-level' means only consider top-level things, and
|
||||
nested things are ignored. `restricted' means movement is
|
||||
restricted inside the thing that encloses POS (i.e., parent),
|
||||
should there be one. If omitted, TACTIC is considered to be
|
||||
`nested'.
|
||||
|
||||
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)))
|
||||
(point) arg 'end regexp pred tactic)))
|
||||
(when dest
|
||||
(goto-char dest))))
|
||||
|
||||
|
|
@ -1943,7 +1965,8 @@ and `treesit-defun-skipper'."
|
|||
(catch 'done
|
||||
(dotimes (_ 2)
|
||||
|
||||
(when (treesit-beginning-of-thing treesit-defun-type-regexp arg)
|
||||
(when (treesit-beginning-of-thing
|
||||
treesit-defun-type-regexp arg treesit-defun-tactic)
|
||||
(when treesit-defun-skipper
|
||||
(funcall treesit-defun-skipper)
|
||||
(setq success t)))
|
||||
|
|
@ -1971,7 +1994,8 @@ this function depends on `treesit-defun-type-regexp' and
|
|||
(catch 'done
|
||||
(dotimes (_ 2) ; Not making progress is better than infloop.
|
||||
|
||||
(when (treesit-end-of-thing treesit-defun-type-regexp arg)
|
||||
(when (treesit-end-of-thing
|
||||
treesit-defun-type-regexp arg treesit-defun-tactic)
|
||||
(when treesit-defun-skipper
|
||||
(funcall treesit-defun-skipper)))
|
||||
|
||||
|
|
@ -2144,7 +2168,7 @@ REGEXP and PRED are the same as in `treesit-thing-at-point'."
|
|||
;; -> 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
|
||||
;; in the function to do that.
|
||||
(defun treesit--navigate-thing (pos arg side regexp &optional pred recursing)
|
||||
(defun treesit--navigate-thing (pos arg side regexp &optional pred tactic recursing)
|
||||
"Navigate thing ARG steps from POS.
|
||||
|
||||
If ARG is positive, move forward that many steps, if negative,
|
||||
|
|
@ -2157,6 +2181,16 @@ across, return nil.
|
|||
|
||||
REGEXP and PRED are the same as in `treesit-thing-at-point'.
|
||||
|
||||
TACTIC determines how does this function move between things. It
|
||||
can be `nested', `top-level', `restricted', or nil. `nested'
|
||||
means normal nested navigation: try to move to siblings first,
|
||||
and if there aren't enough siblings, move to the parent and its
|
||||
siblings. `top-level' means only consider top-level things, and
|
||||
nested things are ignored. `restricted' means movement is
|
||||
restricted inside the thing that encloses POS (i.e., parent),
|
||||
should there be one. If omitted, TACTIC is considered to be
|
||||
`nested'.
|
||||
|
||||
RECURSING is an internal parameter, if non-nil, it means this
|
||||
function is called recursively."
|
||||
(pcase-let*
|
||||
|
|
@ -2178,53 +2212,57 @@ function is called recursively."
|
|||
;; When PARENT is nil, nested and top-level are the same, if
|
||||
;; there is a PARENT, make PARENT to be the top-level parent
|
||||
;; and pretend there is no nested PREV and NEXT.
|
||||
(when (and (eq treesit-defun-tactic 'top-level)
|
||||
(when (and (eq tactic 'top-level)
|
||||
parent)
|
||||
(setq parent (treesit--top-level-thing
|
||||
parent regexp pred)
|
||||
prev nil
|
||||
next nil))
|
||||
;; Move...
|
||||
(if (> arg 0)
|
||||
;; ...forward.
|
||||
(if (and (eq side 'beg)
|
||||
;; Should we skip the defun (recurse)?
|
||||
(cond (next (and (not recursing) ; [1] (see below)
|
||||
(eq pos (funcall advance next))))
|
||||
(parent t))) ; [2]
|
||||
;; Special case: go to next beg-of-defun, but point
|
||||
;; is already on beg-of-defun. Set POS to the end
|
||||
;; of next-sib/parent defun, and run one more step.
|
||||
;; If there is a next-sib defun, we only need to
|
||||
;; recurse once, so we don't need to recurse if we
|
||||
;; are already recursing [1]. If there is no
|
||||
;; next-sib but a parent, keep stepping out
|
||||
;; (recursing) until we got out of the parents until
|
||||
;; (1) there is a next sibling defun, or (2) no more
|
||||
;; parents [2].
|
||||
;;
|
||||
;; If point on beg-of-defun but we are already
|
||||
;; recurring, that doesn't count as special case,
|
||||
;; because we have already made progress (by moving
|
||||
;; the end of next before recurring.)
|
||||
;; If TACTIC is `restricted', the implementation is very simple.
|
||||
(if (eq tactic 'restricted)
|
||||
(setq pos (funcall advance (if (> arg 0) next prev)))
|
||||
;; For `nested', it's a bit more work:
|
||||
;; Move...
|
||||
(if (> arg 0)
|
||||
;; ...forward.
|
||||
(if (and (eq side 'beg)
|
||||
;; Should we skip the defun (recurse)?
|
||||
(cond (next (and (not recursing) ; [1] (see below)
|
||||
(eq pos (funcall advance next))))
|
||||
(parent t))) ; [2]
|
||||
;; Special case: go to next beg-of-defun, but point
|
||||
;; is already on beg-of-defun. Set POS to the end
|
||||
;; of next-sib/parent defun, and run one more step.
|
||||
;; If there is a next-sib defun, we only need to
|
||||
;; recurse once, so we don't need to recurse if we
|
||||
;; are already recursing [1]. If there is no
|
||||
;; next-sib but a parent, keep stepping out
|
||||
;; (recursing) until we got out of the parents until
|
||||
;; (1) there is a next sibling defun, or (2) no more
|
||||
;; parents [2].
|
||||
;;
|
||||
;; If point on beg-of-defun but we are already
|
||||
;; recurring, that doesn't count as special case,
|
||||
;; because we have already made progress (by moving
|
||||
;; the end of next before recurring.)
|
||||
(setq pos (or (treesit--navigate-thing
|
||||
(treesit-node-end (or next parent))
|
||||
1 'beg regexp pred tactic t)
|
||||
(throw 'term nil)))
|
||||
;; Normal case.
|
||||
(setq pos (funcall advance (or next parent))))
|
||||
;; ...backward.
|
||||
(if (and (eq side 'end)
|
||||
(cond (prev (and (not recursing)
|
||||
(eq pos (funcall advance prev))))
|
||||
(parent t)))
|
||||
;; Special case: go to prev end-of-defun.
|
||||
(setq pos (or (treesit--navigate-thing
|
||||
(treesit-node-end (or next parent))
|
||||
1 'beg regexp pred t)
|
||||
(treesit-node-start (or prev parent))
|
||||
-1 'end regexp pred tactic t)
|
||||
(throw 'term nil)))
|
||||
;; Normal case.
|
||||
(setq pos (funcall advance (or next parent))))
|
||||
;; ...backward.
|
||||
(if (and (eq side 'end)
|
||||
(cond (prev (and (not recursing)
|
||||
(eq pos (funcall advance prev))))
|
||||
(parent t)))
|
||||
;; Special case: go to prev end-of-defun.
|
||||
(setq pos (or (treesit--navigate-thing
|
||||
(treesit-node-start (or prev parent))
|
||||
-1 'end regexp pred t)
|
||||
(throw 'term nil)))
|
||||
;; Normal case.
|
||||
(setq pos (funcall advance (or prev parent)))))
|
||||
(setq pos (funcall advance (or prev parent))))))
|
||||
;; A successful step! Decrement counter.
|
||||
(cl-decf counter))))
|
||||
;; Counter equal to 0 means we successfully stepped ARG steps.
|
||||
|
|
|
|||
Loading…
Reference in a new issue