Subject: bug#76398: treesit-aggregated-outline-predicate

From: Yuan Fu <[email-masked]>
Date: Sun, 23 Feb 2025 22:47:47 -0800

> On Feb 22, 2025, at 11:53 AM, Juri Linkov <[email-masked]> wrote:
> 
>>>>> So this patch helps 'treesit-outline-search' to get out of the local parser
>>>>> to the primary parser to continue search for the next outline predicate.
>>>>> 
>>>>> 'treesit-outline-level' should do the same, but currently I can't find
>>>>> a suitable function to break out of embedded confinement
>>>>> and get the host node that contains the guest ranges.
>>>>> I mean that e.g. (treesit-parser-root-node (treesit-node-parser node))
>>>>> can get the root node of the local parser, but how to get its parent node
>>>>> in the primary parser?  It's understandable that treesit-node-parent
>>>>> doesn't go out of its parser.  But maybe there is another function?
>>>>> If such function doesn't exist, this is fine, then could find that
>>>>> node manually by calculating from treesit-parser-included-ranges.
>>>> 
>>>> Maybe we need two new primitives:
>>>> 
>>>> (treesit-next-parser-boundary POS)
>>>> (treesit-prev-parser-boundary POS)
>>> 
>>> Now pushed as 'treesit-closest-parser-boundary'.
>> 
>> Hold on, let’s not get ahead of ourselves. First of all, the name is not
>> very descriptive IMO it actually finds range boundary, not parser boundary;
>> and the docstring mentions local parser while the function itself doesn’t
>> really involve local parsers—it just checks parser ranges. It can be used
>> for getting out of local parsers, yes, but that’s a use-case, not what it
>> does. So if we want to add this function to the public API set for
>> tree-sitter, it needs a better docstring. (And at the moment I have doubt
>> on its general usefulness.)
> 
> I assumed that this function will not remain in the final
> implementation of this feature.  I added it temporarily
> to get the embedded outlines into a working state.

Great. Then let’s use double dash and maybe even add some comments to explain that, WDYT?

> 
>> More over, is this even necessary?  Why do we need to go over all the
>> ranges for all the parsers to get out of a local parser?  I thought we
>> can just get the local parser and get it’s range?
> 
> I tried to use treesit-local-parsers-at, but it always returns nil.

That’s probably because the major mode you’re testing with doesn’t use local parser for the embedded language. I’ll add a function to get the “parent node”, that should solve your problem here.

> 
>>>> (treesit-upper-parser-node POS)
>>> 
>>> Addition of 'treesit-upper-parser-node' is underway that should
>>> be used in 'treesit-up-list' as well.
>> 
>> And if we need to get the “parent node” of a local parser, we can do it in
>> much nicer ways. We can record the parent node when creating the local
>> parser, by either adding a field to the parser object, or record it in
>> a local database, or even just save it in the text property alongside the
>> local parser. Let’s take some time and think of the best way to solve
>> this.
> 
> Now I improved treesit-outline-level as well without adding
> new functions.  Everything works now, so we can do more
> refactoring without introducing regressions.
> 
>> Whatever you have in mind, I suspect that it wouldn’t work if there
>> are more than one layer of nesting of parsers, ie, what if you want to get
>> out of a embedded (local) parser’s embedded parser?
> 
> The current implementation in treesit-outline-level works with any depth
> of nested parsers.  But the current solution is quite fragile.  So we need
> to find a better way such as recording the parent parser node somewhere.
> 
>> On the same note, we actually need some proper tree structure for the
>> primary parser - local parser relationship, because there can be more than
>> one layer. What we currently have doesn’t handle this well (font-lock and
>> indentation). It’s a real use case, someone requested for this for the Perl
>> (or Haskell?) mode, and imagine a rust buffer embeds a markdown comment
>> which embeds rust code examples. I bring this up because this tree
>> structure would’ve solved your problem here as well, once we have it.
> 
> Agreed, this needs a better design.

Cool, working on it.

Yuan