]> git.eshelyaron.com Git - emacs.git/commitdiff
Call treesit_record_change in insert_from_gap_1
authorYuan Fu <casouri@gmail.com>
Fri, 3 Feb 2023 01:22:22 +0000 (17:22 -0800)
committerYuan Fu <casouri@gmail.com>
Fri, 3 Feb 2023 02:31:19 +0000 (18:31 -0800)
Before this change, insert_from_gap calls treesit_record_change but
insert_from_gap_1 doesn't.  However, insert_from_gap_1 is a public
function and is called in many other places outside of insdel.c.  This
could lead to tree-sitter's parse tree becoming out-of-sync with the
buffer content.

This change might fix bug#60650.

* src/insdel.c (insert_from_gap_1): Call treesit_record_change.
(insert_from_gap): Remove call to treesit_record_change.

* admin/notes/tree-sitter/treesit_record_change: New file.

admin/notes/tree-sitter/treesit_record_change [new file with mode: 0644]
src/insdel.c

diff --git a/admin/notes/tree-sitter/treesit_record_change b/admin/notes/tree-sitter/treesit_record_change
new file mode 100644 (file)
index 0000000..bb0f9ed
--- /dev/null
@@ -0,0 +1,50 @@
+NOTES ON TREESIT_RECORD_CHANGE
+
+It is vital that Emacs informs tree-sitter of every change made to the
+buffer, lest tree-sitter's parse tree would be corrupted/out of sync.
+
+All buffer changes in Emacs are made through functions in insdel.c
+(and casefiddle.c), I augmented functions in those files with calls to
+treesit_record_change.  Below is a manifest of all the relavent
+functions in insdel.c as of Emacs 29:
+
+Function                          Calls
+----------------------------------------------------------------------
+copy_text                         (*1)
+insert                            insert_1_both
+insert_and_inherit                insert_1_both
+insert_char                       insert
+insert_string                     insert
+insert_before_markers             insert_1_both
+insert_before_markers_and_inherit insert_1_both
+insert_1_both                     treesit_record_change
+insert_from_string                insert_from_string_1
+insert_from_string_before_markers insert_from_string_1
+insert_from_string_1              treesit_record_change
+insert_from_gap_1                 treesit_record_change
+insert_from_gap                   insert_from_gap_1
+insert_from_buffer                treesit_record_change
+insert_from_buffer_1              (used by insert_from_buffer) (*2)
+replace_range                     treesit_record_change
+replace_range_2                   (caller needs to call treesit_r_c)
+del_range                         del_range_1
+del_range_1                       del_range_2
+del_range_byte                    del_range_2
+del_range_both                    del_range_2
+del_range_2                       treesit_record_change
+
+(*1) This functions is used only to copy from string to string when
+used outside of insdel.c, and when used inside insdel.c, the caller
+calls treesit_record_change.
+
+(*2) This function is a static function, and insert_from_buffer is its
+only caller.  So it should be fine to call treesit_record_change in
+insert_from_buffer but not insert_from_buffer_1.  I also left a
+reminder comment.
+
+
+As for casefiddle.c, do_casify_unibyte_region and
+do_casify_multibyte_region modifies buffer, but they are static
+functions and are called by casify_region, which calls
+treesit_record_change.  Other higher-level functions calls
+casify_region to do the work.
\ No newline at end of file
index 0e1e98664b30da73bc14ac13b3489412419c4189..e459d0cfa1774b0b234c09b3c3e2dfde7bdc63f0 100644 (file)
@@ -1101,6 +1101,10 @@ insert_from_gap_1 (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
   eassert (NILP (BVAR (current_buffer, enable_multibyte_characters))
            ? nchars == nbytes : nchars <= nbytes);
 
+#ifdef HAVE_TREE_SITTER
+  ptrdiff_t ins_bytepos = GPT_BYTE;
+#endif
+
   GAP_SIZE -= nbytes;
   if (! text_at_gap_tail)
     {
@@ -1115,6 +1119,12 @@ insert_from_gap_1 (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
   /* Put an anchor to ensure multi-byte form ends at gap.  */
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0;
   eassert (GPT <= GPT_BYTE);
+
+#ifdef HAVE_TREE_SITTER
+  eassert (nbytes >= 0);
+  eassert (ins_bytepos >= 0);
+  treesit_record_change (ins_bytepos, ins_bytepos, ins_bytepos + nbytes);
+#endif
 }
 
 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
@@ -1150,12 +1160,6 @@ insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
                                   current_buffer, 0);
     }
 
-#ifdef HAVE_TREE_SITTER
-  eassert (nbytes >= 0);
-  eassert (ins_bytepos >= 0);
-  treesit_record_change (ins_bytepos, ins_bytepos, ins_bytepos + nbytes);
-#endif
-
   if (ins_charpos < PT)
     adjust_point (nchars, nbytes);
 
@@ -1191,6 +1195,9 @@ insert_from_buffer (struct buffer *buf,
 #endif
 }
 
+/* NOTE: If we ever make insert_from_buffer_1 public, make sure to
+   move the call to treesit_record_change into it.  */
+
 static void
 insert_from_buffer_1 (struct buffer *buf,
                      ptrdiff_t from, ptrdiff_t nchars, bool inherit)