From 149d6a851701accac71555822cea8ee5e3e3b54e Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sun, 15 Sep 2024 00:24:03 -0700 Subject: [PATCH] Fix treesit_sync_visible_region's range fixup code (bug#73264) new_ranges_head | v ( )->( )->( )->( )->( ) ^ ^ | | | lisp_ranges (loop head) | prev_cons -> set cdr to nil to cut of the rest result: ( )->( ) * src/treesit.c (treesit_sync_visible_region): Cut off this cons and the rest, not set the current range's end to nil. * test/src/treesit-tests.el: (treesit-range-fixup-after-edit): Add tests for all cases. (cherry picked from commit 460b9d705ab482003fabe75b0fd1df223abe467c) --- src/treesit.c | 14 ++++++++-- test/src/treesit-tests.el | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/treesit.c b/src/treesit.c index 3790f5046c1..519f22ef5fe 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1110,6 +1110,7 @@ treesit_sync_visible_region (Lisp_Object parser) if (NILP (lisp_ranges)) return; Lisp_Object new_ranges_head = lisp_ranges; + Lisp_Object prev_cons = Qnil; FOR_EACH_TAIL_SAFE (lisp_ranges) { @@ -1122,9 +1123,12 @@ treesit_sync_visible_region (Lisp_Object parser) new_ranges_head = XCDR (new_ranges_head); else if (beg >= visible_end) { - /* Even the beg is after visible_end, dicard this range and all + /* Even the beg is after visible_end, discard this range and all the ranges after it. */ - XSETCDR (range, Qnil); + if (NILP (prev_cons)) + new_ranges_head = Qnil; + else + XSETCDR (prev_cons, Qnil); break; } else @@ -1137,12 +1141,18 @@ treesit_sync_visible_region (Lisp_Object parser) if (end > visible_end) XSETCDR (range, make_fixnum (visible_end)); } + prev_cons = lisp_ranges; } XTS_PARSER (parser)->last_set_ranges = new_ranges_head; if (NILP (new_ranges_head)) { + /* We are in a weird situation here: none of the previous ranges + overlaps with the new visible region. We don't have any good + options, so just throw the towel: just remove ranges and hope + lisp world will soon update with reasonable ranges or just + delete this parser. */ bool success; success = ts_parser_set_included_ranges (XTS_PARSER (parser)->parser, NULL, 0); diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el index d62344e81f0..89267157840 100644 --- a/test/src/treesit-tests.el +++ b/test/src/treesit-tests.el @@ -686,6 +686,63 @@ visible_end.)" (should (equal '((16 . 28)) (treesit-query-range 'javascript query nil nil '(1 . -1))))))) +(ert-deftest treesit-range-fixup-after-edit () + "Tests if Emacs can fix OOB ranges after deleting text or narrowing." + (skip-unless (treesit-language-available-p 'json)) + (with-temp-buffer + (let ((parser (treesit-parser-create 'json))) + (insert "11111111111111111111") + (treesit-parser-set-included-ranges parser '((1 . 20))) + (treesit-parser-root-node parser) + (should (equal (treesit-parser-included-ranges parser) + '((1 . 20)))) + + (narrow-to-region 5 15) + (should (equal (treesit-parser-included-ranges parser) + '((5 . 15)))) + + (widen) + ;; Trickier ranges + ;; 11111111111111111111 + ;; [ ] [ ] + ;; { narrow } + (treesit-parser-set-included-ranges parser '((1 . 7) (10 . 15))) + (should (equal (treesit-parser-included-ranges parser) + '((1 . 7) (10 . 15)))) + (narrow-to-region 5 13) + (should (equal (treesit-parser-included-ranges parser) + '((5 . 7) (10 . 13)))) + + ;; Narrow in front. + (widen) + (treesit-parser-set-included-ranges parser '((4 . 17))) + ;; 11111111111111111111 + ;; [ ] + ;; { } narrow + (narrow-to-region 1 8) + (should (equal (treesit-parser-included-ranges parser) + '((4 . 8)))) + + ;; Narrow in back. + (widen) + (treesit-parser-set-included-ranges parser '((4 . 17))) + ;; 11111111111111111111 + ;; [ ] + ;; { } narrow + (narrow-to-region 15 20) + (should (equal (treesit-parser-included-ranges parser) + '((15 . 17)))) + + ;; No overlap + (widen) + (treesit-parser-set-included-ranges parser '((15 . 20))) + ;; 11111111111111111111 + ;; [ ] + ;; { } narrow + (narrow-to-region 1 10) + (should (equal (treesit-parser-included-ranges parser) + nil))))) + ;;; Multiple language (ert-deftest treesit-multi-lang () -- 2.39.5