summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuan Fu <casouri@gmail.com>2023-02-02 17:22:22 -0800
committerYuan Fu <casouri@gmail.com>2023-02-02 18:31:19 -0800
commit8a6bdf88b4b665916cf74dee3a30e9136a9b6df8 (patch)
tree8deeefbb73149fdf3e5efd4a80321be98f62127e
parenta2b77c79dcca64b5e0ae58862206e7cc29640944 (diff)
downloademacs-8a6bdf88b4b665916cf74dee3a30e9136a9b6df8.tar.gz
Call treesit_record_change in insert_from_gap_1
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.
-rw-r--r--admin/notes/tree-sitter/treesit_record_change50
-rw-r--r--src/insdel.c19
2 files changed, 63 insertions, 6 deletions
diff --git a/admin/notes/tree-sitter/treesit_record_change b/admin/notes/tree-sitter/treesit_record_change
new file mode 100644
index 00000000000..bb0f9edc353
--- /dev/null
+++ b/admin/notes/tree-sitter/treesit_record_change
@@ -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
diff --git a/src/insdel.c b/src/insdel.c
index 0e1e98664b3..e459d0cfa17 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -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)