diff options
author | Yuan Fu <casouri@gmail.com> | 2023-11-09 20:50:44 -0800 |
---|---|---|
committer | Yuan Fu <casouri@gmail.com> | 2023-11-09 20:50:44 -0800 |
commit | 3ad06ed4f0e6a69ed31ffa7e6aba26b0594763be (patch) | |
tree | 0c0415c9112bd58f172d9e3406600bd7d3de41e6 /lisp/treesit.el | |
parent | 0db75b80e1ce54f3597f7d19468157fd5ec2bd71 (diff) | |
download | emacs-3ad06ed4f0e6a69ed31ffa7e6aba26b0594763be.tar.gz |
Add treesit thing-at-point functions
* lisp/treesit.el (treesit--thing-sibling):
(treesit--thing-prev):
(treesit--thing-next):
(treesit--thing-at): New functions.
Diffstat (limited to 'lisp/treesit.el')
-rw-r--r-- | lisp/treesit.el | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el index 826e719172d..ec3739bd73d 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2427,6 +2427,77 @@ which see; it can also be a predicate." (treesit-parent-until cursor iter-pred))) result)) +(defun treesit--thing-sibling (pos thing prev) + "Return the next or previous THING at POS. + +If PREV is non-nil, return the previous THING. It's guaranteed +that returned previous sibling's end <= POS, and returned next +sibling's beginning >= POS. + +Return nil if no THING can be found. THING should be a thing +defined in `treesit-thing-settings', or a predicate as described +in `treesit-thing-settings'." + (let* ((cursor (treesit-node-at pos)) + (pos-pred (if prev + (lambda (n) (<= (treesit-node-end n) pos)) + (lambda (n) (>= (treesit-node-start n) pos)))) + (iter-pred (lambda (node) + (and (treesit-node-match-p node thing t) + (funcall pos-pred node)))) + (sibling nil)) + (when cursor + ;; Find the node just before/after POS to start searching. + (save-excursion + (while (and cursor (not (funcall pos-pred cursor))) + (setq cursor (treesit-search-forward-goto + cursor "" prev prev t)))) + ;; Keep searching until we run out of candidates or found a + ;; return value. + (while (and cursor + (funcall pos-pred cursor) + (null sibling)) + (setq sibling (treesit-node-top-level cursor iter-pred t)) + (setq cursor (treesit-search-forward cursor thing prev prev))) + sibling))) + +(defun treesit--thing-prev (pos thing) + "Return the previous THING at POS. + +The returned node, if non-nil, must be before POS, i.e., its end +<= POS. + +THING should be a thing defined in `treesit-thing-settings', or a +predicate as described in `treesit-thing-settings'." + (treesit--thing-sibling pos thing t)) + +(defun treesit--thing-next (pos thing) + "Return the next THING at POS. + +The returned node, if non-nil, must be after POS, i.e., its +start >= POS. + +THING should be a thing defined in `treesit-thing-settings', or a +predicate as described in `treesit-thing-settings'." + (treesit--thing-sibling pos thing nil)) + +(defun treesit--thing-at (pos thing &optional strict) + "Return the smallest THING enclosing POS. + +The returned node, if non-nil, must enclose POS, i.e., its start +<= POS, its end > POS. If STRICT is non-nil, the returned node's +start must < POS rather than <= POS. + +THING should be a thing defined in `treesit-thing-settings', or +it can be a predicate described in `treesit-thing-settings'." + (let* ((cursor (treesit-node-at pos)) + (iter-pred (lambda (node) + (and (treesit-node-match-p node thing t) + (if strict + (< (treesit-node-start node) pos) + (<= (treesit-node-start node) pos)) + (< pos (treesit-node-end node)))))) + (treesit-parent-until cursor iter-pred t))) + ;; The basic idea for nested defun navigation is that we first try to ;; move across sibling defuns in the same level, if no more siblings ;; exist, we move to parents's beg/end, rinse and repeat. We never |