mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
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.
This commit is contained in:
parent
a2b77c79dc
commit
8a6bdf88b4
2 changed files with 63 additions and 6 deletions
50
admin/notes/tree-sitter/treesit_record_change
Normal file
50
admin/notes/tree-sitter/treesit_record_change
Normal file
|
|
@ -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.
|
||||||
19
src/insdel.c
19
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))
|
eassert (NILP (BVAR (current_buffer, enable_multibyte_characters))
|
||||||
? nchars == nbytes : nchars <= nbytes);
|
? nchars == nbytes : nchars <= nbytes);
|
||||||
|
|
||||||
|
#ifdef HAVE_TREE_SITTER
|
||||||
|
ptrdiff_t ins_bytepos = GPT_BYTE;
|
||||||
|
#endif
|
||||||
|
|
||||||
GAP_SIZE -= nbytes;
|
GAP_SIZE -= nbytes;
|
||||||
if (! text_at_gap_tail)
|
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. */
|
/* Put an anchor to ensure multi-byte form ends at gap. */
|
||||||
if (GAP_SIZE > 0) *(GPT_ADDR) = 0;
|
if (GAP_SIZE > 0) *(GPT_ADDR) = 0;
|
||||||
eassert (GPT <= GPT_BYTE);
|
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
|
/* 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);
|
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)
|
if (ins_charpos < PT)
|
||||||
adjust_point (nchars, nbytes);
|
adjust_point (nchars, nbytes);
|
||||||
|
|
||||||
|
|
@ -1191,6 +1195,9 @@ insert_from_buffer (struct buffer *buf,
|
||||||
#endif
|
#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
|
static void
|
||||||
insert_from_buffer_1 (struct buffer *buf,
|
insert_from_buffer_1 (struct buffer *buf,
|
||||||
ptrdiff_t from, ptrdiff_t nchars, bool inherit)
|
ptrdiff_t from, ptrdiff_t nchars, bool inherit)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue