Subject: Re: bug#78402: treesit after-change-functions

From: Yuan Fu <[email-masked]>
Date: Thu, 15 May 2025 00:10:57 -0700

> On May 12, 2025, at 11:27 PM, Juri Linkov <[email-masked]> wrote:
> 
> This new request is the continuation from bug#77256 and
> https://lists.gnu.org/archive/html/emacs-devel/2025-05/msg00300.html
> about updating treesit ranges for after-change-functions,
> particularly for outline--fix-buttons-after-change that uses ranges.
> 
> Hopefully Yuan could verify how implementable is this:
> 
>> BTW the fix should be fairly simple, AFAICT: the `treesit.c` code is
>> told about the buffer change before `after-change-functions` runs, so it
>> can record "ranges need to be updated" somewhere, and then lazily update
>> the ranges next time some code uses treesit functions that depend on the
>> ranges (e.g. outline's after-change function).  If the fully automatic
>> lazy update is too eager, we can delay it to an explicit call to
>> `treesit-ensure-ranges-are-uptodate` which outline's after-change
>> function would have to call manually (same as all other current calls
>> to `treesit-update-ranges`)

First of all, the affected range could be larger than the changed range (think inserting “/*” into a C buffer, everything behind the /* is affected). And you don’t really need to remember the changed range, we already does that in the form of updating the existing tree-sitter parse-tree with buffer edit information. When we finally re-parse the buffer, the parser knows the affected range. And we already rely on that information to selectively update ranges. Specifically, we get the affected regions of the primary parser (which should be the superset of all the affected ranges of all the embedded parsers), and update embedded parser ranges in those regions.

It seems that we only need to invoke treesit--pre-redisplay whenever the root node is accessed (you have to get the root node to accessing any node in the parse tree). treesit--pre-redisplay, if haven’t called since last buffer-chars-modified-tick, will force a re-parse on the primary parser, get the affected region, and update ranges for embedded parsers on the region.

Let me ponder on this a bit more to make sure it’s actually a good idea.

Btw, what’s the issue we’re trying to fix here? If some lisp want to have up-to-date ranges, it can just call treesit--pre-redisplay or treesit-update-ranges. Why do we get the node-outdated error?

Yuan