From 8a6bdf88b4b665916cf74dee3a30e9136a9b6df8 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Thu, 2 Feb 2023 17:22:22 -0800 Subject: [PATCH] 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. --- admin/notes/tree-sitter/treesit_record_change | 50 +++++++++++++++++++ src/insdel.c | 19 ++++--- 2 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 admin/notes/tree-sitter/treesit_record_change 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) -- 2.39.2