GNU bug report logs -
#77256
Treesit language-at-point
Previous Next
Reported by: Juri Linkov <juri <at> linkov.net>
Date: Tue, 25 Mar 2025 18:44:02 UTC
Severity: normal
Fixed in version 31.0.50
Done: Juri Linkov <juri <at> linkov.net>
Bug is archived. No further changes may be made.
Full log
Message #55 received at 77256 <at> debbugs.gnu.org (full text, mbox):
> On Apr 5, 2025, at 11:51 PM, Juri Linkov <juri <at> linkov.net> wrote:
>
>>>> Unfortunately, I discovered that it causes treesit-node-outdated errors.
>>>>
>>>> This is because overlays are updated by 'pre-redisplay-functions'
>>>> later than outline-minor-mode uses them by 'after-change-functions',
>>>> since 'after-change-functions' runs before 'pre-redisplay-functions'.
>>>
>>> This fixes the problem:
>>>
>>> (defun outline--fix-buttons-after-change (beg end _len)
>>> + (when (fboundp 'treesit-update-ranges)
>>> + (treesit-update-ranges beg end))
>>> ;; Handle whole lines
>>> (save-excursion (goto-char beg) (setq beg (pos-bol)))
>>> (save-excursion (goto-char end) (setq end (pos-eol)))
>>
>> Using treesit-update-ranges is the right approach. But is there no
>> better place to put it? I assume there should be a function that
>> involves tree-sitter, in front of which you can put this call.
>
> 'treesit-outline-search' has no information about the positions of
> the beginning and end of the range of changed text. Only
> 'after-change-functions' has access to this information.
>
> So what we could do is this, and I've tested that this approach works:
>
> #+begin_src diff
> diff --git a/lisp/treesit.el b/lisp/treesit.el
> index 07861603244..c77b28c4647 100644
> --- a/lisp/treesit.el
> +++ b/lisp/treesit.el
> @@ -4044,6 +4112,10 @@ treesit-outline-level
>
> level))
>
> +(defun treesit--after-change (beg end _len)
> + "Force updating the ranges after each text change."
> + (treesit-update-ranges beg end))
> +
> ;;; Hideshow mode
>
> (defun treesit-hs-block-end ()
> @@ -4338,7 +4410,16 @@ treesit-major-mode-setup
> (setq treesit-outline-predicate
> #'treesit-outline-predicate--from-imenu))
> (setq-local outline-search-function #'treesit-outline-search
> - outline-level #'treesit-outline-level))
> + outline-level #'treesit-outline-level)
> + (add-hook 'outline-minor-mode-hook
> + (lambda ()
> + (if (bound-and-true-p outline-minor-mode)
> + (add-hook 'after-change-functions
> + #'treesit--after-change
> + 0 t)
> + (remove-hook 'after-change-functions
> + #'treesit--after-change t)))
> + nil t))
>
> ;; Remove existing local parsers.
> (dolist (ov (overlays-in (point-min) (point-max)))
> #+end_src
This seems a bit convoluted to me. What do you think about adding some hook or generic function to outline-minor-mode?
>>> But can we do better? I see that 'treesit-major-mode-setup'
>>> adds the notifier
>>>
>>> (treesit-parser-add-notifier
>>> treesit-primary-parser #'treesit--font-lock-mark-ranges-to-fontify)
>>>
>>> to 'after_change_functions'. But why the treesit
>>> 'after_change_functions' notifier is called after the
>>> 'after-change-functions' hook? Can we change their order?
>>
>> Because we parse lazily. And I should’ve called them after-parse functions
>> in the docstring (good thing I named them notifiers, not
>> after-change-functions)—they get called after the parser re-parses, but the
>> parser doesn’t have to re-parse immediately after a buffer change. It only
>> re-parses when some Lisp asks for a node from the parse tree.
>>
>> In practice, that usually happens in pre-redisplay-function where we set
>> ranges for embedded parsers, which causes the primary parser to re-parse
>> and return a root node for querying. As a (intended) side-effect, the
>> notifiers get called and mark relevant regions to be re-fontified.
>
> Would it be possible on the first attempt of Lisp code to access a node
> to detect such a situation that there are some outdated nodes and
> to update their ranges automatically?
Probably not, since you need to have correct ranges to know which parser to use to get nodes in the first place.
Yuan
This bug report was last modified 91 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.