Fix tree-sitter parser notifier recursion

See the comment for detail.

* src/treesit.c (treesit_ensure_parsed): Move the need_reparse short
circuit to the very beginning.  Move the call to
treesit_call_after_change_functions to the very end.
This commit is contained in:
Yuan Fu 2022-12-28 15:19:34 -08:00
parent db96b1282f
commit ec6feeaa19
No known key found for this signature in database
GPG key ID: 56E19BC57664A442

View file

@ -955,6 +955,11 @@ treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree,
static void
treesit_ensure_parsed (Lisp_Object parser)
{
/* Make sure this comes before everything else, see comment
(ref:notifier-inside-ensure-parsed) for more detail. */
if (!XTS_PARSER (parser)->need_reparse)
return;
struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer);
/* Before we parse, catch up with the narrowing situation. */
@ -963,8 +968,6 @@ treesit_ensure_parsed (Lisp_Object parser)
because it might set the flag to true. */
treesit_sync_visible_region (parser);
if (!XTS_PARSER (parser)->need_reparse)
return;
TSParser *treesit_parser = XTS_PARSER (parser)->parser;
TSTree *tree = XTS_PARSER (parser)->tree;
TSInput input = XTS_PARSER (parser)->input;
@ -984,14 +987,20 @@ treesit_ensure_parsed (Lisp_Object parser)
xsignal1 (Qtreesit_parse_error, buf);
}
XTS_PARSER (parser)->tree = new_tree;
XTS_PARSER (parser)->need_reparse = false;
/* After-change functions should run at the very end, most crucially
after need_reparse is set to false, this way if the function
calls some tree-sitter function which invokes
treesit_ensure_parsed again, it returns early and do not
recursively call the after change functions again.
(ref:notifier-inside-ensure-parsed) */
if (tree != NULL)
{
treesit_call_after_change_functions (tree, new_tree, parser);
ts_tree_delete (tree);
}
XTS_PARSER (parser)->tree = new_tree;
XTS_PARSER (parser)->need_reparse = false;
}
/* This is the read function provided to tree-sitter to read from a