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

From: Juri Linkov <[email-masked]>
Date: Sat, 22 Feb 2025 21:53:02 +0200

>>>> 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.

> 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.

>>>  (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.