]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix treesit_sync_visible_region's range fixup code (bug#73264)
authorYuan Fu <casouri@gmail.com>
Sun, 15 Sep 2024 07:24:03 +0000 (00:24 -0700)
committerEshel Yaron <me@eshelyaron.com>
Mon, 23 Sep 2024 10:45:12 +0000 (12:45 +0200)
      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
test/src/treesit-tests.el

index 3790f5046c1ecd100e4c9c73de849d487f9be4a3..519f22ef5fe81f0137185da77aeff2d1bfa80bc8 100644 (file)
@@ -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);
index d62344e81f08ee5d170f7013a1b39534aaa842cd..892671578406b1ed6e11bc0f0945f4bcc0e2bfa2 100644 (file)
@@ -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 ()