aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuan Fu2023-02-27 00:14:32 -0800
committerYuan Fu2023-02-27 00:14:32 -0800
commitaee10ca1cbee1d653f89f028c34066bf3ebb32ab (patch)
tree2f95d63c61b4acb2dbd35965c866da045cf80caf
parentedf5b97686908114f254b5077c71e8202149545f (diff)
downloademacs-aee10ca1cbee1d653f89f028c34066bf3ebb32ab.tar.gz
emacs-aee10ca1cbee1d653f89f028c34066bf3ebb32ab.zip
Adjust tree-sitter defun navigation (bug#61617)
Before this change, when you use a tree-sitter navigation function to move to the next beginning of a thing, it jumps over the immediate next thing and lands you at the beginning of the next-next thing. Eg, when point is at the "|", and we evaluate (treesit--navigate-thing pos 1 'beg), we go from | (thing) (thing) to (thing) |(thing) But some might expect point to go to |(thing) (thing) instead, which makes sense. Also, that's how Emacs expect defun navigation functions to work. The discrepancy in expectation causes bug#61617. In this change I made tree-sitter navigation functions to work as what Emacs expects. And what I described for moving to the next beginning of thing is similarly applicable to moving to the end of previous end of thing. * lisp/treesit.el (treesit-beginning-of-defun) (treesit-end-of-defun): Handle the case where defun-skipper moves point back to where we started, by adding a retry. (treesit--navigate-thing): Add a single condition checking for progress to the condition form responsible for checking whether to skip the next defun. Namely (eq pos (funcall advance next)))). * test/src/treesit-tests.el: (treesit--ert-defun-navigation-nested-master) (treesit--ert-defun-navigation-top-level-master): Change tests to reflect the new expectation.
-rw-r--r--lisp/treesit.el73
-rw-r--r--test/src/treesit-tests.el32
2 files changed, 68 insertions, 37 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 6b4db2a990c..052f641abfd 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1828,10 +1828,23 @@ This is a tree-sitter equivalent of `beginning-of-defun'.
1828Behavior of this function depends on `treesit-defun-type-regexp' 1828Behavior of this function depends on `treesit-defun-type-regexp'
1829and `treesit-defun-skipper'." 1829and `treesit-defun-skipper'."
1830 (interactive "^p") 1830 (interactive "^p")
1831 (when (treesit-beginning-of-thing treesit-defun-type-regexp arg) 1831 (let ((orig-point (point))
1832 (when treesit-defun-skipper 1832 (success nil))
1833 (funcall treesit-defun-skipper)) 1833 (catch 'done
1834 t)) 1834 (dotimes (_ 2)
1835
1836 (when (treesit-beginning-of-thing treesit-defun-type-regexp arg)
1837 (when treesit-defun-skipper
1838 (funcall treesit-defun-skipper)
1839 (setq success t)))
1840
1841 ;; If we end up at the same point, it means we went to the
1842 ;; next beg-of-defun, but defun skipper moved point back to
1843 ;; where we started, in this case we just move one step
1844 ;; further.
1845 (if (or (eq arg 0) (not (eq orig-point (point))))
1846 (throw 'done success)
1847 (setq arg (if (> arg 0) (1+ arg) (1- arg))))))))
1835 1848
1836(defun treesit-end-of-defun (&optional arg _) 1849(defun treesit-end-of-defun (&optional arg _)
1837 "Move forward to next end of defun. 1850 "Move forward to next end of defun.
@@ -1843,9 +1856,21 @@ This is a tree-sitter equivalent of `end-of-defun'. Behavior of
1843this function depends on `treesit-defun-type-regexp' and 1856this function depends on `treesit-defun-type-regexp' and
1844`treesit-defun-skipper'." 1857`treesit-defun-skipper'."
1845 (interactive "^p\nd") 1858 (interactive "^p\nd")
1846 (when (treesit-end-of-thing treesit-defun-type-regexp arg) 1859 (let ((orig-point (point)))
1847 (when treesit-defun-skipper 1860 (catch 'done
1848 (funcall treesit-defun-skipper)))) 1861 (dotimes (_ 2) ; Not making progress is better than infloop.
1862
1863 (when (treesit-end-of-thing treesit-defun-type-regexp arg)
1864 (when treesit-defun-skipper
1865 (funcall treesit-defun-skipper)))
1866
1867 ;; If we end up at the same point, it means we went to the
1868 ;; prev end-of-defun, but defun skipper moved point back to
1869 ;; where we started, in this case we just move one step
1870 ;; further.
1871 (if (or (eq arg 0) (not (eq orig-point (point))))
1872 (throw 'done nil)
1873 (setq arg (if (> arg 0) (1+ arg) (1- arg))))))))
1849 1874
1850(defun treesit-default-defun-skipper () 1875(defun treesit-default-defun-skipper ()
1851 "Skips spaces after navigating a defun. 1876 "Skips spaces after navigating a defun.
@@ -1967,9 +1992,9 @@ REGEXP and PRED are the same as in `treesit-thing-at-point'."
1967;; 1992;;
1968;; prev-end (tricky): 1993;; prev-end (tricky):
1969;; 1. prev-sibling exists 1994;; 1. prev-sibling exists
1970;; -> If you think about it, we are already at prev-sibling's end! 1995;; -> If we are already at prev-sibling's end, we need to go one
1971;; So we need to go one step further, either to 1996;; step further, either to prev-prev-sibling's end, or parent's
1972;; prev-prev-sibling's end, or parent's prev-sibling's end, etc. 1997;; prev-sibling's end, etc.
1973;; 2. prev-sibling is nil but parent exists 1998;; 2. prev-sibling is nil but parent exists
1974;; -> Obviously we don't want to go to parent's end, instead, we 1999;; -> Obviously we don't want to go to parent's end, instead, we
1975;; want to go to parent's prev-sibling's end. Again, we recurse 2000;; want to go to parent's prev-sibling's end. Again, we recurse
@@ -2019,18 +2044,24 @@ function is called recursively."
2019 ;; ...forward. 2044 ;; ...forward.
2020 (if (and (eq side 'beg) 2045 (if (and (eq side 'beg)
2021 ;; Should we skip the defun (recurse)? 2046 ;; Should we skip the defun (recurse)?
2022 (cond (next (not recursing)) ; [1] (see below) 2047 (cond (next (and (not recursing) ; [1] (see below)
2023 (parent t) ; [2] 2048 (eq pos (funcall advance next))))
2024 (t nil))) 2049 (parent t))) ; [2]
2025 ;; Special case: go to next beg-of-defun. Set POS 2050 ;; Special case: go to next beg-of-defun, but point
2026 ;; to the end of next-sib/parent defun, and run one 2051 ;; is already on beg-of-defun. Set POS to the end
2027 ;; more step. If there is a next-sib defun, we only 2052 ;; of next-sib/parent defun, and run one more step.
2028 ;; need to recurse once, so we don't need to recurse 2053 ;; If there is a next-sib defun, we only need to
2029 ;; if we are already recursing [1]. If there is no 2054 ;; recurse once, so we don't need to recurse if we
2055 ;; are already recursing [1]. If there is no
2030 ;; next-sib but a parent, keep stepping out 2056 ;; next-sib but a parent, keep stepping out
2031 ;; (recursing) until we got out of the parents until 2057 ;; (recursing) until we got out of the parents until
2032 ;; (1) there is a next sibling defun, or (2) no more 2058 ;; (1) there is a next sibling defun, or (2) no more
2033 ;; parents [2]. 2059 ;; parents [2].
2060 ;;
2061 ;; If point on beg-of-defun but we are already
2062 ;; recurring, that doesn't count as special case,
2063 ;; because we have already made progress (by moving
2064 ;; the end of next before recurring.)
2034 (setq pos (or (treesit--navigate-thing 2065 (setq pos (or (treesit--navigate-thing
2035 (treesit-node-end (or next parent)) 2066 (treesit-node-end (or next parent))
2036 1 'beg regexp pred t) 2067 1 'beg regexp pred t)
@@ -2039,9 +2070,9 @@ function is called recursively."
2039 (setq pos (funcall advance (or next parent)))) 2070 (setq pos (funcall advance (or next parent))))
2040 ;; ...backward. 2071 ;; ...backward.
2041 (if (and (eq side 'end) 2072 (if (and (eq side 'end)
2042 (cond (prev (not recursing)) 2073 (cond (prev (and (not recursing)
2043 (parent t) 2074 (eq pos (funcall advance prev))))
2044 (t nil))) 2075 (parent t)))
2045 ;; Special case: go to prev end-of-defun. 2076 ;; Special case: go to prev end-of-defun.
2046 (setq pos (or (treesit--navigate-thing 2077 (setq pos (or (treesit--navigate-thing
2047 (treesit-node-start (or prev parent)) 2078 (treesit-node-start (or prev parent))
diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el
index 5aa12e8aa0e..468cd221ef9 100644
--- a/test/src/treesit-tests.el
+++ b/test/src/treesit-tests.el
@@ -977,22 +977,22 @@ and \"]\"."
977 977
978(defvar treesit--ert-defun-navigation-nested-master 978(defvar treesit--ert-defun-navigation-nested-master
979 ;; START PREV-BEG NEXT-END PREV-END NEXT-BEG 979 ;; START PREV-BEG NEXT-END PREV-END NEXT-BEG
980 '((0 103 105 102 106) ; Between Beg of parent & 1st sibling. 980 '((0 103 105 102 104) ; Between Beg of parent & 1st sibling.
981 (1 103 105 102 106) ; Beg of 1st sibling. 981 (1 103 105 102 106) ; Beg of 1st sibling.
982 (2 104 105 102 106) ; Inside 1st sibling. 982 (2 104 105 102 106) ; Inside 1st sibling.
983 (3 104 107 102 109) ; End of 1st sibling. 983 (3 104 107 102 106) ; End of 1st sibling.
984 (4 104 107 102 109) ; Between 1st sibling & 2nd sibling. 984 (4 104 107 105 106) ; Between 1st sibling & 2nd sibling.
985 (5 104 107 102 109) ; Beg of 2nd sibling. 985 (5 104 107 105 109) ; Beg of 2nd sibling.
986 (6 106 107 105 109) ; Inside 2nd sibling. 986 (6 106 107 105 109) ; Inside 2nd sibling.
987 (7 106 108 105 109) ; End of 2nd sibling. 987 (7 106 108 105 109) ; End of 2nd sibling.
988 (8 106 108 105 109) ; Between 2nd sibling & end of parent. 988 (8 106 108 107 109) ; Between 2nd sibling & end of parent.
989 (9 103 110 102 nil) ; End of parent. 989 (9 103 110 102 109) ; End of parent.
990 990
991 (100 nil 102 nil 103) ; Before 1st parent. 991 (100 nil 102 nil 101) ; Before 1st parent.
992 (101 nil 102 nil 103) ; Beg of 1st parent. 992 (101 nil 102 nil 103) ; Beg of 1st parent.
993 (102 101 108 nil 109) ; Between 1st & 2nd parent. 993 (102 101 108 102 103) ; Between 1st & 2nd parent.
994 (103 101 108 nil 109) ; Beg of 2nd parent. 994 (103 101 108 102 109) ; Beg of 2nd parent.
995 (110 109 nil 108 nil) ; After 3rd parent. 995 (110 109 nil 110 nil) ; After 3rd parent.
996 ) 996 )
997 "Master of nested navigation test. 997 "Master of nested navigation test.
998 998
@@ -1000,7 +1000,7 @@ This basically says, e.g., \"start with point on marker 0, go to
1000the prev-beg, now point should be at marker 103\", etc.") 1000the prev-beg, now point should be at marker 103\", etc.")
1001 1001
1002(defvar treesit--ert-defun-navigation-top-level-master 1002(defvar treesit--ert-defun-navigation-top-level-master
1003 ;; START PREV-BEG NEXT-END NEXT-BEG PREV-END 1003 ;; START PREV-BEG NEXT-END PREV-END NEXT-BEG
1004 '((0 103 108 102 109) ; Between Beg of parent & 1st sibling. 1004 '((0 103 108 102 109) ; Between Beg of parent & 1st sibling.
1005 (1 103 108 102 109) ; Beg of 1st sibling. 1005 (1 103 108 102 109) ; Beg of 1st sibling.
1006 (2 103 108 102 109) ; Inside 1st sibling. 1006 (2 103 108 102 109) ; Inside 1st sibling.
@@ -1010,14 +1010,14 @@ the prev-beg, now point should be at marker 103\", etc.")
1010 (6 103 108 102 109) ; Inside 2nd sibling. 1010 (6 103 108 102 109) ; Inside 2nd sibling.
1011 (7 103 108 102 109) ; End of 2nd sibling. 1011 (7 103 108 102 109) ; End of 2nd sibling.
1012 (8 103 108 102 109) ; Between 2nd sibling & end of parent. 1012 (8 103 108 102 109) ; Between 2nd sibling & end of parent.
1013 (9 103 110 102 nil) ; End of parent. 1013 (9 103 110 102 109) ; End of parent.
1014 1014
1015 ;; Top-level defuns should be identical to the nested test. 1015 ;; Top-level defuns should be identical to the nested test.
1016 (100 nil 102 nil 103) ; Before 1st parent. 1016 (100 nil 102 nil 101) ; Before 1st parent.
1017 (101 nil 102 nil 103) ; Beg of 1st parent. 1017 (101 nil 102 nil 103) ; Beg of 1st parent.
1018 (102 101 108 nil 109) ; Between 1st & 2nd parent. 1018 (102 101 108 102 103) ; Between 1st & 2nd parent.
1019 (103 101 108 nil 109) ; Beg of 2nd parent. 1019 (103 101 108 102 109) ; Beg of 2nd parent.
1020 (110 109 nil 108 nil) ; After 3rd parent. 1020 (110 109 nil 110 nil) ; After 3rd parent.
1021 ) 1021 )
1022 "Master of top-level navigation test.") 1022 "Master of top-level navigation test.")
1023 1023