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

From: Juri Linkov <[email-masked]>
Date: Sun, 02 Mar 2025 19:27:42 +0200

>> Maybe a better name would be 'treesit-outline--closest-range-boundary'?
>> 
>> It's needed to prevent skipping the range boundaries that
>> treesit-navigate-thing does by default, e.g. instead of
>> 
>> from (the starting point of the navigation)
>> range_1_beg
>> range_1_end
>> to (the ending point of the navigation)

But currently handling a local parser is not possible in the above function.
For example, I tried:

  (mapcar #'treesit-parser-included-ranges
          (append (treesit-parser-list)
                  (treesit-local-parsers-at (point))))

But it's position-dependent and can't find the next local-parser
when the position of point is before the start of the local-parser.

>> Like you noticed, we need to check ranges, not parsers anyway,
>> so treesit-local-parsers-at can't help here.
>
> Combine with your reply above, it seems we need some information attached
> to the ranges (with either overlay or text property), rather than to the
> parser. Is that right?

Maybe.  One of two needs I have discovered so far is the ability
to find the next/previous range boundary.

> When updating ranges, we can mark the ranges covered
> by each embed parser, and perhaps link the text prop or overlay to the
> “parent node”.

The ability to find the parent node of the range is another need.

>>>>> I bring this up because this tree structure would’ve
>>>>> solved your problem here as well, once we have it.

A tree of ranges (including ranges of local parsers)
would solve the problem indeed.

> I’ve mostly worked out arbitrary nesting of embedded parsers.
> I tested with markdown -> javascript -> jsdoc, and it seems to work
> fine.  What I’m not sure about right now is the navigation part.

I tested on mhtml-ts-mode -> javascript -> jsdoc and
(mapcar 'treesit-parser-embed-level (treesit-local-parsers-at (point)))
correctly returns (2).  Whereas
(mapcar 'treesit-parser-parent-node (treesit-local-parsers-at (point)))
returns (nil).

BTW, while deleting a jsdoc block I get such backtrace:

Debugger entered--Lisp error: (treesit-parser-deleted #<treesit-parser for jsdoc>)
  treesit-node-on(1 202 #<treesit-parser for jsdoc>)
  treesit--explorer-refresh()
  apply(treesit--explorer-refresh nil)
  timer-event-handler([t ...

and while editing a jsdoc block (inserting a newline before it):

Debugger entered--Lisp error: (treesit-no-parser jsdoc)
  treesit-buffer-root-node(jsdoc)
  treesit-node-on(60 60)
  treesit--indent-1()
  treesit-indent()
  indent-according-to-mode()
  electric-indent-post-self-insert-function()
  newline(nil 1)
  funcall-interactively(newline nil 1)
  command-execute(newline)