GNU bug report logs -
#80136
30.2.50; How to customize treesit-font-lock-level for a specific mode only?
Previous Next
To reply to this bug, email your comments to 80136 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
casouri <at> gmail.com, bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Mon, 05 Jan 2026 17:41:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Augusto Stoffel <arstoffel <at> gmail.com>:
New bug report received and forwarded. Copy sent to
casouri <at> gmail.com, bug-gnu-emacs <at> gnu.org.
(Mon, 05 Jan 2026 17:41:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
I would expect that calling either one of the following, via M-: or in a
mode hook would change the fontified features, but it doesn't.
(let ((treesit-font-lock-level 0))
(treesit-font-lock-recompute-features '(comment string)))
(let ((treesit-font-lock-level 1))
(treesit-font-lock-recompute-features))
Replacing the let-binding with a setq-local doesn't work, either.
However, after customizing treesit-font-lock-level to 0 I am able to use
"recompute features"; of course that affects all buffers, which I would
like to avoid.
PS: I would like very much to be able to do achieve the first version
above (fontification only for comments and strings) globally, but I
assume that's not possible?
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Mon, 05 Jan 2026 19:44:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 80136 <at> debbugs.gnu.org (full text, mbox):
> Cc: Yuan Fu <casouri <at> gmail.com>
> From: Augusto Stoffel <arstoffel <at> gmail.com>
> Date: Mon, 05 Jan 2026 18:39:53 +0100
>
> I would expect that calling either one of the following, via M-: or in a
> mode hook would change the fontified features, but it doesn't.
>
> (let ((treesit-font-lock-level 0))
> (treesit-font-lock-recompute-features '(comment string)))
>
> (let ((treesit-font-lock-level 1))
> (treesit-font-lock-recompute-features))
>
> Replacing the let-binding with a setq-local doesn't work, either.
That's not a bug, but rather a minor omission in the doc string;
now fixed on master.
> However, after customizing treesit-font-lock-level to 0 I am able to use
> "recompute features"; of course that affects all buffers, which I would
> like to avoid.
I don't believe this variable was meant to be buffer-local.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 07:07:01 GMT)
Full text and
rfc822 format available.
Message #11 received at 80136 <at> debbugs.gnu.org (full text, mbox):
> On Jan 5, 2026, at 11:42 AM, Eli Zaretskii <eliz <at> gnu.org> wrote:
>
>> Cc: Yuan Fu <casouri <at> gmail.com>
>> From: Augusto Stoffel <arstoffel <at> gmail.com>
>> Date: Mon, 05 Jan 2026 18:39:53 +0100
>>
>> I would expect that calling either one of the following, via M-: or in a
>> mode hook would change the fontified features, but it doesn't.
>>
>> (let ((treesit-font-lock-level 0))
>> (treesit-font-lock-recompute-features '(comment string)))
>>
>> (let ((treesit-font-lock-level 1))
>> (treesit-font-lock-recompute-features))
>>
>> Replacing the let-binding with a setq-local doesn't work, either.
>
> That's not a bug, but rather a minor omission in the doc string;
> now fixed on master.
>
>> However, after customizing treesit-font-lock-level to 0 I am able to use
>> "recompute features"; of course that affects all buffers, which I would
>> like to avoid.
>
> I don't believe this variable was meant to be buffer-local.
You can use treesit-font-lock-level like that, the problem is how Augusto used treesit-font-lock-recompute-features.
For the issue of
(let ((treesit-font-lock-level 0))
(treesit-font-lock-recompute-features '(comment string)))
It’s mostly due to misleading doc string of treesit-font-lock-recompute-features: this function essentially has two modes. When both ADD-LIST and REMOVE-LIST are nil, the function resets the features by treesit-font-lock-level; when either ADD-LIST or REMOVE-LIST is non-nil, the function adds/removes features on top of currently enabled features in the buffer (not features prescribed by treesit-font-lock-level).
Therefore, to achieve what Augusto wants, we need to use
(let ((treesit-font-lock-level 0))
;; Set features to level 0 (disable all features).
(treesit-font-lock-recompute-features)
;; Add comment and string.
(treesit-font-lock-recompute-features '(comment string)))
(And call jit-lock-refontify if you’re eval’ing the code using M-:)
As for Augusto’s second question about configuring this globally, you can add the above snippet to prog-mode-hook, which runs for every programming mode, tree-sitter-based or not. treesit-font-lock-recompute-features is a no-op when no tree-sitter configuration exists in the buffer, so it can be safely called in any buffer.
Eli, obviously your doc fix is right too, but the main problem is treesit-font-lock-recompute-features’s doc string, which I fixed with another commit.
Yuan
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 07:08:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 80136 <at> debbugs.gnu.org (full text, mbox):
> On Jan 5, 2026, at 11:05 PM, Yuan Fu <casouri <at> gmail.com> wrote:
>
>
>
>> On Jan 5, 2026, at 11:42 AM, Eli Zaretskii <eliz <at> gnu.org> wrote:
>>
>>> Cc: Yuan Fu <casouri <at> gmail.com>
>>> From: Augusto Stoffel <arstoffel <at> gmail.com>
>>> Date: Mon, 05 Jan 2026 18:39:53 +0100
>>>
>>> I would expect that calling either one of the following, via M-: or in a
>>> mode hook would change the fontified features, but it doesn't.
>>>
>>> (let ((treesit-font-lock-level 0))
>>> (treesit-font-lock-recompute-features '(comment string)))
>>>
>>> (let ((treesit-font-lock-level 1))
>>> (treesit-font-lock-recompute-features))
>>>
>>> Replacing the let-binding with a setq-local doesn't work, either.
>>
>> That's not a bug, but rather a minor omission in the doc string;
>> now fixed on master.
>>
>>> However, after customizing treesit-font-lock-level to 0 I am able to use
>>> "recompute features"; of course that affects all buffers, which I would
>>> like to avoid.
>>
>> I don't believe this variable was meant to be buffer-local.
>
> You can use treesit-font-lock-level like that, the problem is how Augusto used treesit-font-lock-recompute-features.
>
> For the issue of
>
> (let ((treesit-font-lock-level 0))
> (treesit-font-lock-recompute-features '(comment string)))
>
> It’s mostly due to misleading doc string of treesit-font-lock-recompute-features: this function essentially has two modes. When both ADD-LIST and REMOVE-LIST are nil, the function resets the features by treesit-font-lock-level; when either ADD-LIST or REMOVE-LIST is non-nil, the function adds/removes features on top of currently enabled features in the buffer (not features prescribed by treesit-font-lock-level).
>
> Therefore, to achieve what Augusto wants, we need to use
>
> (let ((treesit-font-lock-level 0))
> ;; Set features to level 0 (disable all features).
> (treesit-font-lock-recompute-features)
> ;; Add comment and string.
> (treesit-font-lock-recompute-features '(comment string)))
>
> (And call jit-lock-refontify if you’re eval’ing the code using M-:)
>
> As for Augusto’s second question about configuring this globally, you can add the above snippet to prog-mode-hook, which runs for every programming mode, tree-sitter-based or not. treesit-font-lock-recompute-features is a no-op when no tree-sitter configuration exists in the buffer, so it can be safely called in any buffer.
>
> Eli, obviously your doc fix is right too, but the main problem is treesit-font-lock-recompute-features’s doc string, which I fixed with another commit.
>
> Yuan
Oh, and you can totally set different treesit-font-lock-level for different modes, see the docstring of treesit-font-lock-level.
Yuan
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 08:26:01 GMT)
Full text and
rfc822 format available.
Message #17 received at 80136 <at> debbugs.gnu.org (full text, mbox):
On Mon, 5 Jan 2026 at 21:42, Eli Zaretskii <eliz <at> gnu.org> wrote:
> That's not a bug, but rather a minor omission in the doc string;
> now fixed on master.
IMO that change just added noise to the docstring, since being a
defcustom it already has an automatically generated remark to that
effect. Also, as Yuan clarified, the problem was not about the let /
setq-local.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 08:33:01 GMT)
Full text and
rfc822 format available.
Message #20 received at 80136 <at> debbugs.gnu.org (full text, mbox):
On Mon, 5 Jan 2026 at 23:05, Yuan Fu <casouri <at> gmail.com> wrote:
> You can use treesit-font-lock-level like that, the problem is how Augusto used treesit-font-lock-recompute-features.
>
> For the issue of
>
> (let ((treesit-font-lock-level 0))
> (treesit-font-lock-recompute-features '(comment string)))
>
> It’s mostly due to misleading doc string of treesit-font-lock-recompute-features: this function essentially has two modes. When both ADD-LIST and REMOVE-LIST are nil, the function resets the features by treesit-font-lock-level; when either ADD-LIST or REMOVE-LIST is non-nil, the function adds/removes features on top of currently enabled features in the buffer (not features prescribed by treesit-font-lock-level).
>
> Therefore, to achieve what Augusto wants, we need to use
>
> (let ((treesit-font-lock-level 0))
> ;; Set features to level 0 (disable all features).
> (treesit-font-lock-recompute-features)
> ;; Add comment and string.
> (treesit-font-lock-recompute-features '(comment string)))
>
> (And call jit-lock-refontify if you’re eval’ing the code using M-:)
Okay, that clarifies it, thanks!
(It might have been better to define two functions rather than one
function with two modes, and perhaps it's actually not too late to
change that, with a suitable warning message when using a deprecated
calling convention. Personally I think I would have defined
`treesit-font-lock-recompute-features' to take one optional argument,
the level, falling back to `treesit-font-lock-level').
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 08:41:02 GMT)
Full text and
rfc822 format available.
Message #23 received at 80136 <at> debbugs.gnu.org (full text, mbox):
On Mon, 5 Jan 2026 at 23:06, Yuan Fu <casouri <at> gmail.com> wrote:
> Oh, and you can totally set different treesit-font-lock-level for
> different modes, see the docstring of treesit-font-lock-level.
>
> Yuan
Ah, I see, this is new (or only documented) in Emacs 31, so I had not
noticed until now.
But I must say, I find the level setting not to be very useful, at least
as someone who wants to turn of most things but keep a few essential
ones. I kinda see the logic behind levels 3 and 4, but honestly I don't
see the point of level 1. To me the logical level 1 one should enable
you to distinguish code from non-code runs of text, and that's why I
generally only want to fontify comments and strings.
Any, since `treesit-font-lock-level' can be a fancy list, maybe it could
be upgraded to a list of fancy things so you can specify a level but
also exceptions you want to add/remove?
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 13:37:02 GMT)
Full text and
rfc822 format available.
Message #26 received at 80136 <at> debbugs.gnu.org (full text, mbox):
> From: Augusto Stoffel <arstoffel <at> gmail.com>
> Cc: Augusto Stoffel <arstoffel <at> gmail.com>, 80136 <at> debbugs.gnu.org,
> casouri <at> gmail.com
> Date: Tue, 06 Jan 2026 09:25:11 +0100
>
> On Mon, 5 Jan 2026 at 21:42, Eli Zaretskii <eliz <at> gnu.org> wrote:
>
> > That's not a bug, but rather a minor omission in the doc string;
> > now fixed on master.
>
> IMO that change just added noise to the docstring, since being a
> defcustom it already has an automatically generated remark to that
> effect.
It does? I didn't see it, and the current master shows the text I
added only once. What am I missing?
And no, this is not added to every defcustom, or at least I'm not
aware of that. It is only true for defcustom's that have a :set
function; most defcustom's don't.
> Also, as Yuan clarified, the problem was not about the let /
> setq-local.
That's not the problem I tried to fix. I tried to fix this:
> I would expect that calling either one of the following, via M-: or in a
> mode hook would change the fontified features, but it doesn't.
>
> (let ((treesit-font-lock-level 0))
> (treesit-font-lock-recompute-features '(comment string)))
>
> (let ((treesit-font-lock-level 1))
> (treesit-font-lock-recompute-features))
>
> Replacing the let-binding with a setq-local doesn't work, either.
AFAIU, these are not supposed to work with this user option.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Tue, 06 Jan 2026 15:04:02 GMT)
Full text and
rfc822 format available.
Message #29 received at 80136 <at> debbugs.gnu.org (full text, mbox):
On Tue, 6 Jan 2026 at 15:36, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> From: Augusto Stoffel <arstoffel <at> gmail.com>
>> Cc: Augusto Stoffel <arstoffel <at> gmail.com>, 80136 <at> debbugs.gnu.org,
>> casouri <at> gmail.com
>> Date: Tue, 06 Jan 2026 09:25:11 +0100
>>
>> On Mon, 5 Jan 2026 at 21:42, Eli Zaretskii <eliz <at> gnu.org> wrote:
>>
>> > That's not a bug, but rather a minor omission in the doc string;
>> > now fixed on master.
>>
>> IMO that change just added noise to the docstring, since being a
>> defcustom it already has an automatically generated remark to that
>> effect.
>
> It does? I didn't see it, and the current master shows the text I
> added only once. What am I missing?
>
> And no, this is not added to every defcustom, or at least I'm not
> aware of that. It is only true for defcustom's that have a :set
> function; most defcustom's don't.
I though it were, and this variable has a :set. But now I don't see it
anymore.
Anyway, now there are two warnings to the same effect in the docstring,
the one you added and this one, which was already there (and is more
accurate IMO):
Changing the decoration level requires calling
‘treesit-font-lock-recompute-features’ to have an effect, unless
done via ‘customize-variable’.
>> Also, as Yuan clarified, the problem was not about the let /
>> setq-local.
>
> That's not the problem I tried to fix. I tried to fix this:
>
>> I would expect that calling either one of the following, via M-: or in a
>> mode hook would change the fontified features, but it doesn't.
>>
>> (let ((treesit-font-lock-level 0))
>> (treesit-font-lock-recompute-features '(comment string)))
>>
>> (let ((treesit-font-lock-level 1))
>> (treesit-font-lock-recompute-features))
>>
>> Replacing the let-binding with a setq-local doesn't work, either.
>
> AFAIU, these are not supposed to work with this user option.
As Yuan explained above, the issue with the code snippets above has
nothing to do with the let-binding. The following works:
(let ((treesit-font-lock-level 0))
(treesit-font-lock-recompute-features)
(treesit-font-lock-recompute-features '(comment string))
(jit-lock-refontify))
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Thu, 08 Jan 2026 04:24:02 GMT)
Full text and
rfc822 format available.
Message #32 received at 80136 <at> debbugs.gnu.org (full text, mbox):
> On Jan 6, 2026, at 12:40 AM, Augusto Stoffel <arstoffel <at> gmail.com> wrote:
>
> On Mon, 5 Jan 2026 at 23:06, Yuan Fu <casouri <at> gmail.com> wrote:
>
>> Oh, and you can totally set different treesit-font-lock-level for
>> different modes, see the docstring of treesit-font-lock-level.
>>
>> Yuan
>
> Ah, I see, this is new (or only documented) in Emacs 31, so I had not
> noticed until now.
>
> But I must say, I find the level setting not to be very useful, at least
> as someone who wants to turn of most things but keep a few essential
> ones. I kinda see the logic behind levels 3 and 4, but honestly I don't
> see the point of level 1. To me the logical level 1 one should enable
> you to distinguish code from non-code runs of text, and that's why I
> generally only want to fontify comments and strings.
Yeah. The thing is, the next person will come and say they only want comments highlighted for the minimum level. These things are subjective and usually there aren’t very strong reasons to change it.
>
> Any, since `treesit-font-lock-level' can be a fancy list, maybe it could
> be upgraded to a list of fancy things so you can specify a level but
> also exceptions you want to add/remove?
At that point we’d have two canonical ways to do the same thing (adding/removing features). That creates confusion: why are their two ways to do it? Which one should I use? And what happens if both are used? Etc, etc. I’d like to keep them separated and clear: If you want to set a level, use treesit-font-lock-level. If you want to additionally modify features, use treesit-f-l-recompute-features in a major mode hook.
Yuan
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Thu, 08 Jan 2026 04:27:02 GMT)
Full text and
rfc822 format available.
Message #35 received at 80136 <at> debbugs.gnu.org (full text, mbox):
> On Jan 6, 2026, at 12:32 AM, Augusto Stoffel <arstoffel <at> gmail.com> wrote:
>
> On Mon, 5 Jan 2026 at 23:05, Yuan Fu <casouri <at> gmail.com> wrote:
>
>> You can use treesit-font-lock-level like that, the problem is how Augusto used treesit-font-lock-recompute-features.
>>
>> For the issue of
>>
>> (let ((treesit-font-lock-level 0))
>> (treesit-font-lock-recompute-features '(comment string)))
>>
>> It’s mostly due to misleading doc string of treesit-font-lock-recompute-features: this function essentially has two modes. When both ADD-LIST and REMOVE-LIST are nil, the function resets the features by treesit-font-lock-level; when either ADD-LIST or REMOVE-LIST is non-nil, the function adds/removes features on top of currently enabled features in the buffer (not features prescribed by treesit-font-lock-level).
>>
>> Therefore, to achieve what Augusto wants, we need to use
>>
>> (let ((treesit-font-lock-level 0))
>> ;; Set features to level 0 (disable all features).
>> (treesit-font-lock-recompute-features)
>> ;; Add comment and string.
>> (treesit-font-lock-recompute-features '(comment string)))
>>
>> (And call jit-lock-refontify if you’re eval’ing the code using M-:)
>
> Okay, that clarifies it, thanks!
>
> (It might have been better to define two functions rather than one
> function with two modes, and perhaps it's actually not too late to
> change that, with a suitable warning message when using a deprecated
> calling convention. Personally I think I would have defined
> `treesit-font-lock-recompute-features' to take one optional argument,
> the level, falling back to `treesit-font-lock-level’).
Admittedly, they could’ve been two functions. But the cat’s already out of the bag now. And changing this function would be a huge pain. I think the doc string update should alleviate the confusion a lot, if not completely.
Yuan
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#80136; Package
emacs.
(Thu, 08 Jan 2026 07:46:01 GMT)
Full text and
rfc822 format available.
Message #38 received at 80136 <at> debbugs.gnu.org (full text, mbox):
On Wed, 7 Jan 2026 at 20:23, Yuan Fu <casouri <at> gmail.com> wrote:
>> On Jan 6, 2026, at 12:40 AM, Augusto Stoffel <arstoffel <at> gmail.com> wrote:
>>
>> On Mon, 5 Jan 2026 at 23:06, Yuan Fu <casouri <at> gmail.com> wrote:
>>
>>> Oh, and you can totally set different treesit-font-lock-level for
>>> different modes, see the docstring of treesit-font-lock-level.
>>>
>>> Yuan
>>
>> Ah, I see, this is new (or only documented) in Emacs 31, so I had not
>> noticed until now.
>>
>> But I must say, I find the level setting not to be very useful, at least
>> as someone who wants to turn of most things but keep a few essential
>> ones. I kinda see the logic behind levels 3 and 4, but honestly I don't
>> see the point of level 1. To me the logical level 1 one should enable
>> you to distinguish code from non-code runs of text, and that's why I
>> generally only want to fontify comments and strings.
>
> Yeah. The thing is, the next person will come and say they only want
> comments highlighted for the minimum level. These things are
> subjective and usually there aren’t very strong reasons to change it.
Sure, but did anyone do that? (Note I'm not asking for peculiar things
I want, it's about what makes sense generally.)
>> Any, since `treesit-font-lock-level' can be a fancy list, maybe it could
>> be upgraded to a list of fancy things so you can specify a level but
>> also exceptions you want to add/remove?
>
> At that point we’d have two canonical ways to do the same thing
> (adding/removing features). That creates confusion: why are their two
> ways to do it? Which one should I use? And what happens if both are
> used? Etc, etc. I’d like to keep them separated and clear: If you want
> to set a level, use treesit-font-lock-level. If you want to
> additionally modify features, use treesit-f-l-recompute-features in a
> major mode hook.
Well, _there are_ two ways to add and remove features, by levels and by
feature names. The design with levels wasn't strictly necessary: one
could just work with individual features. But you chose to add it for a
reason.
Also the variable treesit-font-lock-level wasn't strictly necessary, the
user could just always customize everything by calling functions in a
mode hook. Also here the variable was introduced for a good reason: the
hook method is only suitable for Elisp hackers (in particular, ones good
at reading the docstring 🙂). So much so that in Emacs 31 it was
decided that variable can also be an alist of major modes.
> Yuan
This bug report was last modified 3 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.