unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Disable tree-sitter font-locking for smaller ranges
@ 2022-10-16 10:32 Theodor Thornhill
  2022-10-17  5:04 ` Yuan Fu
  0 siblings, 1 reply; 14+ messages in thread
From: Theodor Thornhill @ 2022-10-16 10:32 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1700 bytes --]


Hi Yuan!

I've been trying to tweak the font-locking for tree-sitter in
js/ts-mode, and I'm still struggling with the template strings.  Is
there a way to _disable_ font-locking for smaller ranges?

Let's say you have this string:
```
`Some string with ${5+5} many template substitutions ${foo().bar().baz()}`;
```

This string will match something like:
```
(template_string (template_substitution) :*)
```

If you use this as a query:
```
(template_string) @font-lock-string-face
```

Everything inside the string is in string-face.

If you add
```
(template_substitution
 "${" @font-lock-constant-face
 (_)
 "}" @font-lock-constant-face)
```

You get font-locking in the ranges inside the squigglies, as expected.
However, if there isn't defined any rules for say, "(), . []" etc, the
template_string capture will bleed into the substitution, because its
range suggests it should.  It would be nice to say something like:

```
(defvar fonts ()
  (treesit-font-lock-rules
     :language 'tsx
     :override t
     :feature 'basic
     '((template_string (_):* @disabled) @font-lock-string-face 
       (template_substitution ["${" "}"] @font-lock-constant-face)))
```

to ensure that whatever is inside the wildcard match will _not_ be
considered for the string face, but whatever is still inside the bigger
range will.  Is this currently possible?  If not, is
it possible to add?  I guess I could make a function that would remove
the range, but that seems fiddly and error prone.

I've tried fiddling with the :feature flag in 'treesit-font-lock-rules',
but I never found a combination that did what I wanted.

Adding a small image of a stupid snipped just to make the point more visual

Theo



[-- Attachment #2: 2022-10-16_12-26.png --]
[-- Type: image/png, Size: 12890 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-16 10:32 Disable tree-sitter font-locking for smaller ranges Theodor Thornhill
@ 2022-10-17  5:04 ` Yuan Fu
  2022-10-17  5:49   ` Theodor Thornhill
  0 siblings, 1 reply; 14+ messages in thread
From: Yuan Fu @ 2022-10-17  5:04 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: emacs-devel



> On Oct 16, 2022, at 3:32 AM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> 
> Hi Yuan!
> 
> I've been trying to tweak the font-locking for tree-sitter in
> js/ts-mode, and I'm still struggling with the template strings.  Is
> there a way to _disable_ font-locking for smaller ranges?
> 
> Let's say you have this string:
> ```
> `Some string with ${5+5} many template substitutions ${foo().bar().baz()}`;
> ```
> 
> This string will match something like:
> ```
> (template_string (template_substitution) :*)
> ```
> 
> If you use this as a query:
> ```
> (template_string) @font-lock-string-face
> ```
> 
> Everything inside the string is in string-face.
> 
> If you add
> ```
> (template_substitution
> "${" @font-lock-constant-face
> (_)
> "}" @font-lock-constant-face)
> ```
> 
> You get font-locking in the ranges inside the squigglies, as expected.
> However, if there isn't defined any rules for say, "(), . []" etc, the
> template_string capture will bleed into the substitution, because its
> range suggests it should.  It would be nice to say something like:
> 
> ```
> (defvar fonts ()
>  (treesit-font-lock-rules
>     :language 'tsx
>     :override t
>     :feature 'basic
>     '((template_string (_):* @disabled) @font-lock-string-face 
>       (template_substitution ["${" "}"] @font-lock-constant-face)))
> ```
> 
> to ensure that whatever is inside the wildcard match will _not_ be
> considered for the string face, but whatever is still inside the bigger
> range will.  Is this currently possible?  If not, is
> it possible to add?  I guess I could make a function that would remove
> the range, but that seems fiddly and error prone.
> 
> I've tried fiddling with the :feature flag in 'treesit-font-lock-rules',
> but I never found a combination that did what I wanted.
> 
> Adding a small image of a stupid snipped just to make the point more visual

The image you attached looks perfectly fine to me. Do you not want to font-lock what’s inside a substitution? I’m not exactly sure what result you want to archive.

If you don’t want font-lock in substitutions, you can put 

>  '((template_string) @font-lock-string-face 
>       (template_substitution ["${" "}"] @font-lock-constant-face))


After all other queries, and mark these two with :override t. That should do it.

Also, when I was browsing tsx’s grammar file, I didn’t find definition of template_substitution at all. That means at least some part of js and tsx’s grammar are not interchangeable.

Yuan


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  5:04 ` Yuan Fu
@ 2022-10-17  5:49   ` Theodor Thornhill
  2022-10-17  6:01     ` Yuan Fu
  0 siblings, 1 reply; 14+ messages in thread
From: Theodor Thornhill @ 2022-10-17  5:49 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel



On 17 October 2022 07:04:58 CEST, Yuan Fu <casouri@gmail.com> wrote:
>
>
>> On Oct 16, 2022, at 3:32 AM, Theodor Thornhill <theo@thornhill.no> wrote:
>> 
>> 
>> Hi Yuan!
>> 
>> I've been trying to tweak the font-locking for tree-sitter in
>> js/ts-mode, and I'm still struggling with the template strings.  Is
>> there a way to _disable_ font-locking for smaller ranges?
>> 
>> Let's say you have this string:
>> ```
>> `Some string with ${5+5} many template substitutions ${foo().bar().baz()}`;
>> ```
>> 
>> This string will match something like:
>> ```
>> (template_string (template_substitution) :*)
>> ```
>> 
>> If you use this as a query:
>> ```
>> (template_string) @font-lock-string-face
>> ```
>> 
>> Everything inside the string is in string-face.
>> 
>> If you add
>> ```
>> (template_substitution
>> "${" @font-lock-constant-face
>> (_)
>> "}" @font-lock-constant-face)
>> ```
>> 
>> You get font-locking in the ranges inside the squigglies, as expected.
>> However, if there isn't defined any rules for say, "(), . []" etc, the
>> template_string capture will bleed into the substitution, because its
>> range suggests it should.  It would be nice to say something like:
>> 
>> ```
>> (defvar fonts ()
>>  (treesit-font-lock-rules
>>     :language 'tsx
>>     :override t
>>     :feature 'basic
>>     '((template_string (_):* @disabled) @font-lock-string-face 
>>       (template_substitution ["${" "}"] @font-lock-constant-face)))
>> ```
>> 
>> to ensure that whatever is inside the wildcard match will _not_ be
>> considered for the string face, but whatever is still inside the bigger
>> range will.  Is this currently possible?  If not, is
>> it possible to add?  I guess I could make a function that would remove
>> the range, but that seems fiddly and error prone.
>> 
>> I've tried fiddling with the :feature flag in 'treesit-font-lock-rules',
>> but I never found a combination that did what I wanted.
>> 
>> Adding a small image of a stupid snipped just to make the point more visual
>
>The image you attached looks perfectly fine to me. Do you not want to font-lock what’s inside a substitution? I’m not exactly sure what result you want to archive.
>

All the parens, braces, equal, semicolons should be white, as they would in the source file outside of the template string. But the string outside of the ${...} should be string colored. 


>If you don’t want font-lock in substitutions, you can put 
>
>>  '((template_string) @font-lock-string-face 
>>       (template_substitution ["${" "}"] @font-lock-constant-face))
>
>
>After all other queries, and mark these two with :override t. That should do it.
>

Ill try that! 

>Also, when I was browsing tsx’s grammar file, I didn’t find definition of template_substitution at all. That means at least some part of js and tsx’s grammar are not interchangeable.
>
>Yuan

They do some inheritance shenanigans in their files. Most of the grammar is from tree-sitter-Javascript. 

Theo



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  5:49   ` Theodor Thornhill
@ 2022-10-17  6:01     ` Yuan Fu
  2022-10-17  6:33       ` Theodor Thornhill
  0 siblings, 1 reply; 14+ messages in thread
From: Yuan Fu @ 2022-10-17  6:01 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: emacs-devel



> On Oct 16, 2022, at 10:49 PM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> 
> 
> On 17 October 2022 07:04:58 CEST, Yuan Fu <casouri@gmail.com> wrote:
>> 
>> 
>>> On Oct 16, 2022, at 3:32 AM, Theodor Thornhill <theo@thornhill.no> wrote:
>>> 
>>> 
>>> Hi Yuan!
>>> 
>>> I've been trying to tweak the font-locking for tree-sitter in
>>> js/ts-mode, and I'm still struggling with the template strings.  Is
>>> there a way to _disable_ font-locking for smaller ranges?
>>> 
>>> Let's say you have this string:
>>> ```
>>> `Some string with ${5+5} many template substitutions ${foo().bar().baz()}`;
>>> ```
>>> 
>>> This string will match something like:
>>> ```
>>> (template_string (template_substitution) :*)
>>> ```
>>> 
>>> If you use this as a query:
>>> ```
>>> (template_string) @font-lock-string-face
>>> ```
>>> 
>>> Everything inside the string is in string-face.
>>> 
>>> If you add
>>> ```
>>> (template_substitution
>>> "${" @font-lock-constant-face
>>> (_)
>>> "}" @font-lock-constant-face)
>>> ```
>>> 
>>> You get font-locking in the ranges inside the squigglies, as expected.
>>> However, if there isn't defined any rules for say, "(), . []" etc, the
>>> template_string capture will bleed into the substitution, because its
>>> range suggests it should.  It would be nice to say something like:
>>> 
>>> ```
>>> (defvar fonts ()
>>> (treesit-font-lock-rules
>>>    :language 'tsx
>>>    :override t
>>>    :feature 'basic
>>>    '((template_string (_):* @disabled) @font-lock-string-face 
>>>      (template_substitution ["${" "}"] @font-lock-constant-face)))
>>> ```
>>> 
>>> to ensure that whatever is inside the wildcard match will _not_ be
>>> considered for the string face, but whatever is still inside the bigger
>>> range will.  Is this currently possible?  If not, is
>>> it possible to add?  I guess I could make a function that would remove
>>> the range, but that seems fiddly and error prone.
>>> 
>>> I've tried fiddling with the :feature flag in 'treesit-font-lock-rules',
>>> but I never found a combination that did what I wanted.
>>> 
>>> Adding a small image of a stupid snipped just to make the point more visual
>> 
>> The image you attached looks perfectly fine to me. Do you not want to font-lock what’s inside a substitution? I’m not exactly sure what result you want to archive.
>> 
> 
> All the parens, braces, equal, semicolons should be white, as they would in the source file outside of the template string. But the string outside of the ${...} should be string colored. 
> 
Ah, I finally get it. How about:

(template_string) @font-lock-string-face
(template_substitution) @default ; color everything in substitution white
(template_substitution ["${" "}"] @font-lock-constant-face)
;; rest font-lock

Yuan


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  6:01     ` Yuan Fu
@ 2022-10-17  6:33       ` Theodor Thornhill
  2022-10-17  9:00         ` Yuan Fu
  0 siblings, 1 reply; 14+ messages in thread
From: Theodor Thornhill @ 2022-10-17  6:33 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

Yuan Fu <casouri@gmail.com> writes:
>>> 
>>> The image you attached looks perfectly fine to me. Do you not want
>>> to font-lock what’s inside a substitution? I’m not exactly sure what
>>> result you want to archive.
>>> 
>> 
>> All the parens, braces, equal, semicolons should be white, as they
>> would in the source file outside of the template string. But the
>> string outside of the ${...} should be string colored.
>> 
> Ah, I finally get it. How about:
>
> (template_string) @font-lock-string-face
> (template_substitution) @default ; color everything in substitution white
> (template_substitution ["${" "}"] @font-lock-constant-face)
> ;; rest font-lock
>

Yes! That's it! Thanks :)

See attached patch:

Theo



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-correct-ordering-in-template_substitution.patch --]
[-- Type: text/x-diff, Size: 2961 bytes --]

From dbe998506f9052455d3499638930418832f5c243 Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Mon, 17 Oct 2022 08:29:39 +0200
Subject: [PATCH] Add correct ordering in template_substitution

We want to override the template substitution contents with no
coloring, because we need the font-lock-string-face not to bleed into
the substitutions.  The correct ordering of these forms are important.

* lisp/progmodes/js.el (js--treesit-settings): Move template string
related queries to top, and use the correct ordering.

* lisp/progmodes/ts-mode.el (ts-mode--settings): Move template string
related queries to top, and use the correct ordering.
---
 lisp/progmodes/js.el      | 12 ++++++++----
 lisp/progmodes/ts-mode.el | 10 +++++++---
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 18499a466a..0cf106f482 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3461,8 +3461,14 @@ js--treesit-settings
    :language 'javascript
    :feature 'basic
    :override t
-   `(;; Everything overrides template string.
+   `(
+     ;; The order of these are important.  We want to keep coloring in
+     ;; the string, but not in the substitution, thus delegating the
+     ;; contents of that substitution to the usual rules
      (template_string) @font-lock-string-face
+     (template_substitution) @default   ; Color everything white
+     (template_substitution
+      ["${" "}"] @font-lock-builtin-face)
 
      ((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
@@ -3559,9 +3565,7 @@ js--treesit-settings
 
      (string) @font-lock-string-face
      (comment) @font-lock-comment-face
-     [,@js--treesit-keywords] @font-lock-keyword-face
-
-     (template_substitution ["${" "}"] @font-lock-constant-face))))
+     [,@js--treesit-keywords] @font-lock-keyword-face)))
 
 
 (defun js-treesit-current-defun ()
diff --git a/lisp/progmodes/ts-mode.el b/lisp/progmodes/ts-mode.el
index 10d4b7bd18..5a8f7da30a 100644
--- a/lisp/progmodes/ts-mode.el
+++ b/lisp/progmodes/ts-mode.el
@@ -110,7 +110,14 @@ ts-mode--settings
    :override t
    :feature 'basic
    '(
+     ;; The order of these are important.  We want to keep coloring in
+     ;; the string, but not in the substitution, thus delegating the
+     ;; contents of that substitution to the usual rules
      (template_string) @font-lock-string-face
+     (template_substitution) @default   ; Color everything white
+     (template_substitution
+      ["${" "}"] @font-lock-builtin-face)
+
 
      ((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
@@ -225,9 +232,6 @@ ts-mode--settings
      (string) @font-lock-string-face
      (template_string) @font-lock-string-face
 
-     (template_substitution
-      ["${" "}"] @font-lock-constant-face)
-
      ["!"
       "abstract"
       "as"
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  6:33       ` Theodor Thornhill
@ 2022-10-17  9:00         ` Yuan Fu
  2022-10-17  9:41           ` Theodor Thornhill
  2022-10-18  1:23           ` Trey Peacock
  0 siblings, 2 replies; 14+ messages in thread
From: Yuan Fu @ 2022-10-17  9:00 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: emacs-devel



> On Oct 16, 2022, at 11:33 PM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> Yuan Fu <casouri@gmail.com> writes:
>>>> 
>>>> The image you attached looks perfectly fine to me. Do you not want
>>>> to font-lock what’s inside a substitution? I’m not exactly sure what
>>>> result you want to archive.
>>>> 
>>> 
>>> All the parens, braces, equal, semicolons should be white, as they
>>> would in the source file outside of the template string. But the
>>> string outside of the ${...} should be string colored.
>>> 
>> Ah, I finally get it. How about:
>> 
>> (template_string) @font-lock-string-face
>> (template_substitution) @default ; color everything in substitution white
>> (template_substitution ["${" "}"] @font-lock-constant-face)
>> ;; rest font-lock
>> 
> 
> Yes! That's it! Thanks :)
> 
> See attached patch:

Actually, thinking more of it, it working relies on the exact order of which these rules are applied:
1. Outer template_string
2. Outer template_substitution
3. Inner template_string
4. Inner template_substitution

Relying on such un-guaranteed fact is a bit uncomfortable, so I just wrote a function that did what you suggested initially: to fontify parts of template_string that’s not a template_substitution. WDYT? (I just pushed the change.)

BTW, if you have time and energy, could you look into separating the queries into roughly three levels: minimum, moderate, and full fontification, and mark each with the new :feature flag? Or even better, separate them into different features (as suggested in the docstring of treesit-font-lock-feature-list).

Yuan






^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  9:00         ` Yuan Fu
@ 2022-10-17  9:41           ` Theodor Thornhill
  2022-10-17 11:02             ` Theodor Thornhill via Emacs development discussions.
  2022-10-18  5:06             ` Yuan Fu
  2022-10-18  1:23           ` Trey Peacock
  1 sibling, 2 replies; 14+ messages in thread
From: Theodor Thornhill @ 2022-10-17  9:41 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel

Yuan Fu <casouri@gmail.com> writes:

>
> Actually, thinking more of it, it working relies on the exact order of which these rules are applied:
> 1. Outer template_string
> 2. Outer template_substitution
> 3. Inner template_string
> 4. Inner template_substitution

That's correct.

>
> Relying on such un-guaranteed fact is a bit uncomfortable, so I just
> wrote a function that did what you suggested initially: to fontify
> parts of template_string that’s not a template_substitution. WDYT? (I
> just pushed the change.)
>

I agree! The change looks good to me. Is there any change in performance
doing this? I'm not yet 100% on the inner workings, but if this would
slow things down that wouldn't be so nice.

> BTW, if you have time and energy, could you look into separating the
> queries into roughly three levels: minimum, moderate, and full
> fontification, and mark each with the new :feature flag? Or even
> better, separate them into different features (as suggested in the
> docstring of treesit-font-lock-feature-list).
>

I will do that promptly and attach patches for ts-mode and js-mode to
this thread.

Theo



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  9:41           ` Theodor Thornhill
@ 2022-10-17 11:02             ` Theodor Thornhill via Emacs development discussions.
  2022-10-18  0:20               ` Yuan Fu
  2022-10-18  5:06             ` Yuan Fu
  1 sibling, 1 reply; 14+ messages in thread
From: Theodor Thornhill via Emacs development discussions. @ 2022-10-17 11:02 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 458 bytes --]

>> BTW, if you have time and energy, could you look into separating the
>> queries into roughly three levels: minimum, moderate, and full
>> fontification, and mark each with the new :feature flag? Or even
>> better, separate them into different features (as suggested in the
>> docstring of treesit-font-lock-feature-list).
>>
>
> I will do that promptly and attach patches for ts-mode and js-mode to
> this thread.
>
> Theo


See attached patch :-)

Theo


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-more-granular-features-in-font-locking.patch --]
[-- Type: text/x-diff, Size: 14803 bytes --]

From 1f4f6c6ede3198af4f8c252dd0a56a3ad1bdbd2f Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Mon, 17 Oct 2022 12:49:19 +0200
Subject: [PATCH] Add more granular features in font-locking

There is now support for three font-locking levels, 'minimum',
'medium' and 'full'.  The richest experience is to be expected from
the 'full', and all levels are enabled by default.

* lisp/progmodes/js.el (js--treesit-font-lock-settings): New defvar
renamed from 'js--treesit-settings'.

(js--font-lock-minimum-settings, js--font-lock-medium-settings,
js--font-lock-full-settings): New defvars.

(js--treesit-font-lock-settings): New defvar renamed from
'js--json-treesit-settings'.

* lisp/progmodes/ts-mode.el (ts-mode--font-lock-settings): New defvar
renamed from 'ts-mode--settings'.

(ts-mode--font-lock-minimum-settings,
ts-mode--font-lock-medium-settings, ts-mode--font-lock-full-settings):
New defvars.
---
 lisp/progmodes/js.el      | 104 ++++++++++++--------
 lisp/progmodes/ts-mode.el | 195 +++++++++++++++++++-------------------
 2 files changed, 164 insertions(+), 135 deletions(-)

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 667416852e..62f83fe831 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3454,19 +3454,40 @@ js--treesit-keywords
     "debugger" "default" "delete" "do" "else" "export" "extends" "finally"
     "for" "from" "function" "get" "if" "import" "in" "instanceof" "let" "new"
     "of" "return" "set" "static" "switch" "switch" "target" "throw" "try"
-    "typeof" "var" "void" "while" "with" "yield"))
+    "typeof" "var" "void" "while" "with" "yield")
+  "JavaScript keywords for tree-sitter font-locking.")
 
-(defvar js--treesit-settings
-  (treesit-font-lock-rules
+(defvar js--font-lock-minimum-settings
+  (list
    :language 'javascript
-   :feature 'basic
    :override t
-   `(((identifier) @font-lock-constant-face
+   :feature 'minimal
+   `(
+     ((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
 
-     (new_expression
-      constructor: (identifier) @font-lock-type-face)
+     [(this) (super)] @font-lock-keyword-face
 
+     [(true) (false) (null)] @font-lock-constant-face
+     (regex pattern: (regex_pattern)) @font-lock-string-face
+     (number) @font-lock-constant-face
+
+     (string) @font-lock-string-face
+     (comment) @font-lock-comment-face
+     [,@js--treesit-keywords] @font-lock-keyword-face
+
+     (template_string) @js--fontify-template-string
+     (template_substitution ["${" "}"] @font-lock-constant-face)))
+  "Font lock settings for minimal TypeScript highlights.
+This level will font-lock only keywords, strings, comments and
+some identifiers.")
+
+(defvar js--font-lock-medium-settings
+  (list
+   :language 'javascript
+   :override t
+   :feature 'medium
+   `(
      (function
       name: (identifier) @font-lock-function-name-face)
 
@@ -3479,6 +3500,26 @@ js--treesit-settings
      (method_definition
       name: (property_identifier) @font-lock-function-name-face)
 
+     (variable_declarator
+      name: (identifier) @font-lock-variable-name-face)
+
+     (new_expression
+      constructor: (identifier) @font-lock-type-face)
+
+     (for_in_statement
+      left: (identifier) @font-lock-variable-name-face)
+
+     (arrow_function
+      parameter: (identifier) @font-lock-variable-name-face)))
+  "Font lock settings for medium TypeScript highlights.
+This levels adds some flair to the more advanced patterns.")
+
+(defvar js--font-lock-full-settings
+  (list
+   :language 'javascript
+   :override t
+   :feature 'full
+   `(
      (variable_declarator
       name: (identifier) @font-lock-function-name-face
       value: [(function) (arrow_function)])
@@ -3502,20 +3543,11 @@ js--treesit-settings
                   property:
                   (property_identifier) @font-lock-function-name-face)])
 
-     (variable_declarator
-      name: (identifier) @font-lock-variable-name-face)
-
      (assignment_expression
       left: [(identifier) @font-lock-variable-name-face
              (member_expression
               property: (property_identifier) @font-lock-variable-name-face)])
 
-     (for_in_statement
-      left: (identifier) @font-lock-variable-name-face)
-
-     (arrow_function
-      parameter: (identifier) @font-lock-variable-name-face)
-
      (pair key: (property_identifier) @font-lock-variable-name-face)
 
      (pair value: (identifier) @font-lock-variable-name-face)
@@ -3546,20 +3578,17 @@ js--treesit-settings
 
      (jsx_attribute
       (property_identifier)
-      @font-lock-constant-face)
-
-     [(this) (super)] @font-lock-keyword-face
-
-     [(true) (false) (null)] @font-lock-constant-face
-     (regex pattern: (regex_pattern)) @font-lock-string-face
-     (number) @font-lock-constant-face
-
-     (string) @font-lock-string-face
-     (comment) @font-lock-comment-face
-     [,@js--treesit-keywords] @font-lock-keyword-face
-
-     (template_string) @js--fontify-template-string
-     (template_substitution ["${" "}"] @font-lock-constant-face))))
+      @font-lock-constant-face)))
+  "Font lock settings for full TypeScript highlights.
+This level yields the richest experience, with support for
+pattern matching and TSX.")
+
+(defvar js--treesit-font-lock-settings
+  (apply #'treesit-font-lock-rules
+         (append js--font-lock-minimum-settings
+                 js--font-lock-medium-settings
+                 js--font-lock-full-settings))
+  "Tree-sitter font-lock settings.")
 
 (defun js--fontify-template-string (beg end node)
   "Fontify template string but not substitution inside it.
@@ -3655,8 +3684,8 @@ js--treesit-enable
   (setq-local end-of-defun-function #'js--treesit-end-of-defun)
 
   (setq-local font-lock-keywords-only t)
-  (setq-local treesit-font-lock-settings js--treesit-settings)
-  (setq-local treesit-font-lock-feature-list '((basic)))
+  (setq-local treesit-font-lock-settings js--treesit-font-lock-settings)
+  (setq-local treesit-font-lock-feature-list '((minimal medium full)))
 
   (add-hook 'which-func-functions #'js-treesit-current-defun nil t)
 
@@ -3761,10 +3790,10 @@ js-json-use-tree-sitter
   :type 'boolean
   :safe 'booleanp)
 
-(defvar js--json-treesit-settings
+(defvar js-json--treesit-font-lock-settings
   (treesit-font-lock-rules
    :language 'json
-   :feature 'basic
+   :feature 'minimal
    :override t
    `(
      (pair
@@ -3778,8 +3807,8 @@ js--json-treesit-settings
 
      (escape_sequence) @font-lock-constant-face
 
-     (comment) @font-lock-comment-face
-     )))
+     (comment) @font-lock-comment-face))
+  "Font-lock settings for JSON.")
 
 
 (defvar js--json-treesit-indent-rules
@@ -3809,8 +3838,9 @@ js--json-treesit-enable
   (setq-local end-of-defun-function #'ignore)
 
   (setq-local font-lock-defaults '(nil t))
-  (setq-local treesit-font-lock-settings js--json-treesit-settings)
+  (setq-local treesit-font-lock-settings js-json--treesit-font-lock-settings)
 
+  (setq treesit-font-lock-feature-list '((minimal)))
   (treesit-font-lock-enable))
 
 
diff --git a/lisp/progmodes/ts-mode.el b/lisp/progmodes/ts-mode.el
index 6e4aeebde8..656f655aed 100644
--- a/lisp/progmodes/ts-mode.el
+++ b/lisp/progmodes/ts-mode.el
@@ -104,17 +104,55 @@ ts-mode--indent-rules
      (no-node parent-bol 0)))
   "Tree-sitter indent rules.")
 
-(defvar ts-mode--settings
-  (treesit-font-lock-rules
+(defvar ts-mode--keywords
+  '("!" "abstract" "as" "async" "await" "break"
+    "case" "catch" "class" "const" "continue" "debugger"
+    "declare" "default" "delete" "do" "else" "enum"
+    "export" "extends" "finally" "for" "from" "function"
+    "get" "if" "implements" "import" "in" "instanceof" "interface"
+    "keyof" "let" "namespace" "new" "of" "private" "protected"
+    "public" "readonly" "return" "set" "static" "switch"
+    "target" "throw" "try" "type" "typeof" "var" "void"
+    "while" "with" "yield")
+  "TypeScript keywords for tree-sitter font-locking.")
+
+(defvar ts-mode--font-lock-minimum-settings
+  (list
    :language 'tsx
    :override t
-   :feature 'basic
-   '(((identifier) @font-lock-constant-face
+   :feature 'minimal
+   `(
+     ((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
 
+     [,@ts-mode--keywords] @font-lock-keyword-face
+     [(this) (super)] @font-lock-keyword-face
+
+     [(true) (false) (null)] @font-lock-constant-face
+     (regex pattern: (regex_pattern)) @font-lock-string-face
+     (number) @font-lock-constant-face
+
+     (string) @font-lock-string-face
+
+     (template_string) @ts-mode--fontify-template-string
+     (template_substitution ["${" "}"] @font-lock-builtin-face)
+
+     (comment) @font-lock-comment-face))
+  "Font lock settings for minimal TypeScript highlights.
+This level will font-lock only keywords, strings, comments and
+some identifiers.")
+
+(defvar ts-mode--font-lock-medium-settings
+  (list
+   :language 'tsx
+   :override t
+   :feature 'medium
+   '(
      (nested_type_identifier
       module: (identifier) @font-lock-type-face)
+
      (type_identifier) @font-lock-type-face
+
      (predefined_type) @font-lock-type-face
 
      (new_expression
@@ -129,6 +167,34 @@ ts-mode--settings
      (method_definition
       name: (property_identifier) @font-lock-function-name-face)
 
+     (variable_declarator
+      name: (identifier) @font-lock-variable-name-face)
+
+     (enum_declaration (identifier) @font-lock-type-face)
+
+     (enum_body (property_identifier) @font-lock-type-face)
+
+     (enum_assignment name: (property_identifier) @font-lock-type-face)
+
+     (assignment_expression
+      left: [(identifier) @font-lock-variable-name-face
+             (member_expression
+              property: (property_identifier) @font-lock-variable-name-face)])
+
+     (for_in_statement
+      left: (identifier) @font-lock-variable-name-face)
+
+     (arrow_function
+      parameter: (identifier) @font-lock-variable-name-face)))
+  "Font lock settings for medium TypeScript highlights.
+This levels adds some flair to the more advanced patterns.")
+
+(defvar ts-mode--font-lock-full-settings
+  (list
+   :language 'tsx
+   :override t
+   :feature 'full
+   '(
      (variable_declarator
       name: (identifier) @font-lock-function-name-face
       value: [(function) (arrow_function)])
@@ -151,33 +217,12 @@ ts-mode--settings
        (member_expression
         property: (property_identifier) @font-lock-function-name-face)])
 
-     (variable_declarator
-      name: (identifier) @font-lock-variable-name-face)
-
-     (enum_declaration (identifier) @font-lock-type-face)
-
-     (enum_body (property_identifier) @font-lock-type-face)
-
-     (enum_assignment name: (property_identifier) @font-lock-type-face)
-
-     (assignment_expression
-      left: [(identifier) @font-lock-variable-name-face
-             (member_expression
-              property: (property_identifier) @font-lock-variable-name-face)])
-
-     (for_in_statement
-      left: (identifier) @font-lock-variable-name-face)
-
-     (arrow_function
-      parameter: (identifier) @font-lock-variable-name-face)
-
      (arrow_function
       parameters:
       [(_ (identifier) @font-lock-variable-name-face)
        (_ (_ (identifier) @font-lock-variable-name-face))
        (_ (_ (_ (identifier) @font-lock-variable-name-face)))])
 
-
      (pair key: (property_identifier) @font-lock-variable-name-face)
 
      (pair value: (identifier) @font-lock-variable-name-face)
@@ -211,80 +256,33 @@ ts-mode--settings
       [(nested_identifier (identifier)) (identifier)]
       @font-lock-function-name-face)
 
-     (jsx_attribute (property_identifier) @font-lock-constant-face)
-
-     [(this) (super)] @font-lock-keyword-face
-
-     [(true) (false) (null)] @font-lock-constant-face
-     (regex pattern: (regex_pattern)) @font-lock-string-face
-     (number) @font-lock-constant-face
-
-     (string) @font-lock-string-face
+     (jsx_attribute (property_identifier) @font-lock-constant-face)))
+  "Font lock settings for full TypeScript highlights.
+This level yields the richest experience, with support for
+pattern matching and TSX.")
 
-     (template_string) @js--fontify-template-string
-     (template_substitution
-      ["${" "}"] @font-lock-constant-face)
-
-     ["!"
-      "abstract"
-      "as"
-      "async"
-      "await"
-      "break"
-      "case"
-      "catch"
-      "class"
-      "const"
-      "continue"
-      "debugger"
-      "declare"
-      "default"
-      "delete"
-      "do"
-      "else"
-      "enum"
-      "export"
-      "extends"
-      "finally"
-      "for"
-      "from"
-      "function"
-      "get"
-      "if"
-      "implements"
-      "import"
-      "in"
-      "instanceof"
-      "interface"
-      "keyof"
-      "let"
-      "namespace"
-      "new"
-      "of"
-      "private"
-      "protected"
-      "public"
-      "readonly"
-      "return"
-      "set"
-      "static"
-      "switch"
-      "target"
-      "throw"
-      "try"
-      "type"
-      "typeof"
-      "var"
-      "void"
-      "while"
-      "with"
-      "yield"
-      ] @font-lock-keyword-face
-
-     (comment) @font-lock-comment-face
-     ))
+(defvar ts-mode--font-lock-settings
+  (apply #'treesit-font-lock-rules
+         (append ts-mode--font-lock-minimum-settings
+                 ts-mode--font-lock-medium-settings
+                 ts-mode--font-lock-full-settings))
   "Tree-sitter font-lock settings.")
 
+(defun ts-mode--fontify-template-string (beg end node)
+  "Fontify template string but not substitution inside it.
+BEG, END, NODE refers to the template_string node."
+  (ignore end)
+  ;; Stolen from `js--fontify-template-string'
+  (let ((child (treesit-node-child node 0)))
+    (while child
+      (if (equal (treesit-node-type child) "template_substitution")
+          (put-text-property beg (treesit-node-start child)
+                             'face 'font-lock-string-face)
+        (put-text-property beg (treesit-node-end child)
+                           'face 'font-lock-string-face))
+      (setq beg (treesit-node-end child)
+            child (treesit-node-next-sibling child)))))
+
 (defvar ts-mode--defun-type-regexp
   (rx (or "class_declaration"
           "method_definition"
@@ -354,9 +352,10 @@ ts-mode
     (unless font-lock-defaults
       (setq font-lock-defaults '(nil t)))
 
-    (setq-local treesit-font-lock-settings ts-mode--settings)
+    (setq-local treesit-font-lock-settings ts-mode--font-lock-settings)
+
+    (setq treesit-font-lock-feature-list '((minimal medium full)))
 
-    (setq treesit-font-lock-feature-list '((basic)))
     (treesit-font-lock-enable))
    (t
     (message "Tree sitter for TypeScript isn't available, defaulting to js-mode")
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17 11:02             ` Theodor Thornhill via Emacs development discussions.
@ 2022-10-18  0:20               ` Yuan Fu
  2022-10-18  5:04                 ` Theodor Thornhill
  0 siblings, 1 reply; 14+ messages in thread
From: Yuan Fu @ 2022-10-18  0:20 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: emacs-devel



> On Oct 17, 2022, at 4:02 AM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
>>> BTW, if you have time and energy, could you look into separating the
>>> queries into roughly three levels: minimum, moderate, and full
>>> fontification, and mark each with the new :feature flag? Or even
>>> better, separate them into different features (as suggested in the
>>> docstring of treesit-font-lock-feature-list).
>>> 
>> 
>> I will do that promptly and attach patches for ts-mode and js-mode to
>> this thread.
>> 
>> Theo
> 
> 
> See attached patch :-)

Thanks! I think you have a bit of misunderstanding of the :feature flag. You should only need to change

(defvar xxx-font-lock-settings
  (treesit-font-lock-rules
   :language 'xxx
   '(1111111111111
     2222222222222
     3333333333333)))

to

(defvar xxx-font-lock-settings
  (treesit-font-lock-rules
   :language 'xxx
   :feature 'minimum
   '(1111111111111)
   :language 'xxx
   :feature 'moderate
   '(2222222222222)
   :language 'xxx
   :feature 'full
   '(3333333333333)))

Ie, no need to create separate variables. And you should set treesit-font-lock-feature-list to

(setq treesit-font-lock-feature-list
      '((minimum) (moderate) (full)))

Yuan


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  9:00         ` Yuan Fu
  2022-10-17  9:41           ` Theodor Thornhill
@ 2022-10-18  1:23           ` Trey Peacock
  1 sibling, 0 replies; 14+ messages in thread
From: Trey Peacock @ 2022-10-18  1:23 UTC (permalink / raw)
  To: Yuan Fu, Theodor Thornhill; +Cc: emacs-devel

"Yuan Fu" <casouri@gmail.com> writes:

> Actually, thinking more of it, it working relies on the exact order of which these rules are applied:
> 1. Outer template_string
> 2. Outer template_substitution
> 3. Inner template_string
> 4. Inner template_substitution
>

If it's useful, I believe the reason why the queries you were using
didn't work was because you were using the alternation which only allows
for selecting a single option. This should work, regardless of the
order:

(template_substitution
 "${" @font-lock-constant-face
 "}" @font-lock-constant-face) @default
(escape_sequence) @font-lock-constant-face
(template_string) @font-lock-string-face

However, I am unsure how to address potentially nested template
substitutions. Perhaps a function could assist in that.

Trey




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-18  0:20               ` Yuan Fu
@ 2022-10-18  5:04                 ` Theodor Thornhill
  2022-10-18 20:07                   ` Theodor Thornhill
  0 siblings, 1 reply; 14+ messages in thread
From: Theodor Thornhill @ 2022-10-18  5:04 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel



On 18 October 2022 02:20:02 CEST, Yuan Fu <casouri@gmail.com> wrote:
>
>
>> On Oct 17, 2022, at 4:02 AM, Theodor Thornhill <theo@thornhill.no> wrote:
>> 
>>>> BTW, if you have time and energy, could you look into separating the
>>>> queries into roughly three levels: minimum, moderate, and full
>>>> fontification, and mark each with the new :feature flag? Or even
>>>> better, separate them into different features (as suggested in the
>>>> docstring of treesit-font-lock-feature-list).
>>>> 
>>> 
>>> I will do that promptly and attach patches for ts-mode and js-mode to
>>> this thread.
>>> 
>>> Theo
>> 
>> 
>> See attached patch :-)
>
>Thanks! I think you have a bit of misunderstanding of the :feature flag. You should only need to change
>
>(defvar xxx-font-lock-settings
>  (treesit-font-lock-rules
>   :language 'xxx
>   '(1111111111111
>     2222222222222
>     3333333333333)))
>
>to
>
>(defvar xxx-font-lock-settings
>  (treesit-font-lock-rules
>   :language 'xxx
>   :feature 'minimum
>   '(1111111111111)
>   :language 'xxx
>   :feature 'moderate
>   '(2222222222222)
>   :language 'xxx
>   :feature 'full
>   '(3333333333333)))
>
>Ie, no need to create separate variables. And you should set treesit-font-lock-feature-list to
>
>(setq treesit-font-lock-feature-list
>      '((minimum) (moderate) (full)))
>
>Yuan

Oh, right, thanks!

The separate variables was more for readability, but I can change that back :)

Theo



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-17  9:41           ` Theodor Thornhill
  2022-10-17 11:02             ` Theodor Thornhill via Emacs development discussions.
@ 2022-10-18  5:06             ` Yuan Fu
  1 sibling, 0 replies; 14+ messages in thread
From: Yuan Fu @ 2022-10-18  5:06 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: emacs-devel



> On Oct 17, 2022, at 2:41 AM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> Yuan Fu <casouri@gmail.com> writes:
> 
>> 
>> Actually, thinking more of it, it working relies on the exact order of which these rules are applied:
>> 1. Outer template_string
>> 2. Outer template_substitution
>> 3. Inner template_string
>> 4. Inner template_substitution
> 
> That's correct.
> 
>> 
>> Relying on such un-guaranteed fact is a bit uncomfortable, so I just
>> wrote a function that did what you suggested initially: to fontify
>> parts of template_string that’s not a template_substitution. WDYT? (I
>> just pushed the change.)
>> 
> 
> I agree! The change looks good to me. Is there any change in performance
> doing this? I'm not yet 100% on the inner workings, but if this would
> slow things down that wouldn't be so nice.

I didn’t do benchmarks, but I’ll be surprised if there are any difference.

Yuan


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-18  5:04                 ` Theodor Thornhill
@ 2022-10-18 20:07                   ` Theodor Thornhill
  2022-10-18 20:44                     ` Yuan Fu
  0 siblings, 1 reply; 14+ messages in thread
From: Theodor Thornhill @ 2022-10-18 20:07 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 157 bytes --]

Theodor Thornhill <theo@thornhill.no> writes:
> The separate variables was more for readability, but I can change that back :)


Something like this?

Theo


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-more-granular-features-in-font-locking.patch --]
[-- Type: text/x-diff, Size: 13083 bytes --]

From 0b44ad45133dbdff85120e056c7ff95eef07e492 Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Mon, 17 Oct 2022 12:49:19 +0200
Subject: [PATCH] Add more granular features in font-locking

There is now support for three font-locking levels, 'minimal',
'moderate' and 'full'.  The richest experience is to be expected from
the 'full', and all levels are enabled by default.

* lisp/progmodes/js.el (js--treesit-font-lock-settings): New defvar
renamed from 'js--treesit-settings'.

(js--treesit-font-lock-settings): New defvar renamed from
'js--json-treesit-settings'.

* lisp/progmodes/ts-mode.el (ts-mode--font-lock-settings): New defvar
renamed from 'ts-mode--settings'.
---
 lisp/progmodes/js.el      |  82 ++++++++++--------
 lisp/progmodes/ts-mode.el | 175 +++++++++++++++++---------------------
 2 files changed, 123 insertions(+), 134 deletions(-)

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 667416852e..32e1e5027d 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3454,19 +3454,34 @@ js--treesit-keywords
     "debugger" "default" "delete" "do" "else" "export" "extends" "finally"
     "for" "from" "function" "get" "if" "import" "in" "instanceof" "let" "new"
     "of" "return" "set" "static" "switch" "switch" "target" "throw" "try"
-    "typeof" "var" "void" "while" "with" "yield"))
+    "typeof" "var" "void" "while" "with" "yield")
+  "JavaScript keywords for tree-sitter font-locking.")
 
-(defvar js--treesit-settings
+(defvar js--treesit-font-lock-settings
   (treesit-font-lock-rules
    :language 'javascript
-   :feature 'basic
    :override t
-   `(((identifier) @font-lock-constant-face
+   :feature 'minimal
+   `(
+     ((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
 
-     (new_expression
-      constructor: (identifier) @font-lock-type-face)
+     [(this) (super)] @font-lock-keyword-face
 
+     [(true) (false) (null)] @font-lock-constant-face
+     (regex pattern: (regex_pattern)) @font-lock-string-face
+     (number) @font-lock-constant-face
+
+     (string) @font-lock-string-face
+     (comment) @font-lock-comment-face
+     [,@js--treesit-keywords] @font-lock-keyword-face
+
+     (template_string) @js--fontify-template-string
+     (template_substitution ["${" "}"] @font-lock-constant-face))
+   :language 'javascript
+   :override t
+   :feature 'moderate
+   `(
      (function
       name: (identifier) @font-lock-function-name-face)
 
@@ -3479,6 +3494,21 @@ js--treesit-settings
      (method_definition
       name: (property_identifier) @font-lock-function-name-face)
 
+     (variable_declarator
+      name: (identifier) @font-lock-variable-name-face)
+
+     (new_expression
+      constructor: (identifier) @font-lock-type-face)
+
+     (for_in_statement
+      left: (identifier) @font-lock-variable-name-face)
+
+     (arrow_function
+      parameter: (identifier) @font-lock-variable-name-face))
+   :language 'javascript
+   :override t
+   :feature 'full
+   `(
      (variable_declarator
       name: (identifier) @font-lock-function-name-face
       value: [(function) (arrow_function)])
@@ -3502,20 +3532,11 @@ js--treesit-settings
                   property:
                   (property_identifier) @font-lock-function-name-face)])
 
-     (variable_declarator
-      name: (identifier) @font-lock-variable-name-face)
-
      (assignment_expression
       left: [(identifier) @font-lock-variable-name-face
              (member_expression
               property: (property_identifier) @font-lock-variable-name-face)])
 
-     (for_in_statement
-      left: (identifier) @font-lock-variable-name-face)
-
-     (arrow_function
-      parameter: (identifier) @font-lock-variable-name-face)
-
      (pair key: (property_identifier) @font-lock-variable-name-face)
 
      (pair value: (identifier) @font-lock-variable-name-face)
@@ -3546,20 +3567,8 @@ js--treesit-settings
 
      (jsx_attribute
       (property_identifier)
-      @font-lock-constant-face)
-
-     [(this) (super)] @font-lock-keyword-face
-
-     [(true) (false) (null)] @font-lock-constant-face
-     (regex pattern: (regex_pattern)) @font-lock-string-face
-     (number) @font-lock-constant-face
-
-     (string) @font-lock-string-face
-     (comment) @font-lock-comment-face
-     [,@js--treesit-keywords] @font-lock-keyword-face
-
-     (template_string) @js--fontify-template-string
-     (template_substitution ["${" "}"] @font-lock-constant-face))))
+      @font-lock-constant-face)))
+  "Tree-sitter font-lock settings.")
 
 (defun js--fontify-template-string (beg end node)
   "Fontify template string but not substitution inside it.
@@ -3655,8 +3664,8 @@ js--treesit-enable
   (setq-local end-of-defun-function #'js--treesit-end-of-defun)
 
   (setq-local font-lock-keywords-only t)
-  (setq-local treesit-font-lock-settings js--treesit-settings)
-  (setq-local treesit-font-lock-feature-list '((basic)))
+  (setq-local treesit-font-lock-settings js--treesit-font-lock-settings)
+  (setq-local treesit-font-lock-feature-list '((minimal) (moderate) (full)))
 
   (add-hook 'which-func-functions #'js-treesit-current-defun nil t)
 
@@ -3761,10 +3770,10 @@ js-json-use-tree-sitter
   :type 'boolean
   :safe 'booleanp)
 
-(defvar js--json-treesit-settings
+(defvar js-json--treesit-font-lock-settings
   (treesit-font-lock-rules
    :language 'json
-   :feature 'basic
+   :feature 'minimal
    :override t
    `(
      (pair
@@ -3778,8 +3787,8 @@ js--json-treesit-settings
 
      (escape_sequence) @font-lock-constant-face
 
-     (comment) @font-lock-comment-face
-     )))
+     (comment) @font-lock-comment-face))
+  "Font-lock settings for JSON.")
 
 
 (defvar js--json-treesit-indent-rules
@@ -3809,8 +3818,9 @@ js--json-treesit-enable
   (setq-local end-of-defun-function #'ignore)
 
   (setq-local font-lock-defaults '(nil t))
-  (setq-local treesit-font-lock-settings js--json-treesit-settings)
+  (setq-local treesit-font-lock-settings js-json--treesit-font-lock-settings)
 
+  (setq treesit-font-lock-feature-list '((minimal)))
   (treesit-font-lock-enable))
 
 
diff --git a/lisp/progmodes/ts-mode.el b/lisp/progmodes/ts-mode.el
index 6e4aeebde8..b5adf0744e 100644
--- a/lisp/progmodes/ts-mode.el
+++ b/lisp/progmodes/ts-mode.el
@@ -104,17 +104,49 @@ ts-mode--indent-rules
      (no-node parent-bol 0)))
   "Tree-sitter indent rules.")
 
-(defvar ts-mode--settings
+(defvar ts-mode--keywords
+  '("!" "abstract" "as" "async" "await" "break"
+    "case" "catch" "class" "const" "continue" "debugger"
+    "declare" "default" "delete" "do" "else" "enum"
+    "export" "extends" "finally" "for" "from" "function"
+    "get" "if" "implements" "import" "in" "instanceof" "interface"
+    "keyof" "let" "namespace" "new" "of" "private" "protected"
+    "public" "readonly" "return" "set" "static" "switch"
+    "target" "throw" "try" "type" "typeof" "var" "void"
+    "while" "with" "yield")
+  "TypeScript keywords for tree-sitter font-locking.")
+
+(defvar ts-mode--font-lock-settings
   (treesit-font-lock-rules
    :language 'tsx
    :override t
-   :feature 'basic
-   '(((identifier) @font-lock-constant-face
+   :feature 'minimal
+   `(
+     ((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
 
+     [,@ts-mode--keywords] @font-lock-keyword-face
+     [(this) (super)] @font-lock-keyword-face
+
+     [(true) (false) (null)] @font-lock-constant-face
+     (regex pattern: (regex_pattern)) @font-lock-string-face
+     (number) @font-lock-constant-face
+
+     (string) @font-lock-string-face
+
+     (template_string) @ts-mode--fontify-template-string
+     (template_substitution ["${" "}"] @font-lock-builtin-face)
+
+     (comment) @font-lock-comment-face)
+   :language 'tsx
+   :override t
+   :feature 'moderate
+   '(
      (nested_type_identifier
       module: (identifier) @font-lock-type-face)
+
      (type_identifier) @font-lock-type-face
+
      (predefined_type) @font-lock-type-face
 
      (new_expression
@@ -129,6 +161,29 @@ ts-mode--settings
      (method_definition
       name: (property_identifier) @font-lock-function-name-face)
 
+     (variable_declarator
+      name: (identifier) @font-lock-variable-name-face)
+
+     (enum_declaration (identifier) @font-lock-type-face)
+
+     (enum_body (property_identifier) @font-lock-type-face)
+
+     (enum_assignment name: (property_identifier) @font-lock-type-face)
+
+     (assignment_expression
+      left: [(identifier) @font-lock-variable-name-face
+             (member_expression
+              property: (property_identifier) @font-lock-variable-name-face)])
+
+     (for_in_statement
+      left: (identifier) @font-lock-variable-name-face)
+
+     (arrow_function
+      parameter: (identifier) @font-lock-variable-name-face))
+   :language 'tsx
+   :override t
+   :feature 'full
+   '(
      (variable_declarator
       name: (identifier) @font-lock-function-name-face
       value: [(function) (arrow_function)])
@@ -151,33 +206,12 @@ ts-mode--settings
        (member_expression
         property: (property_identifier) @font-lock-function-name-face)])
 
-     (variable_declarator
-      name: (identifier) @font-lock-variable-name-face)
-
-     (enum_declaration (identifier) @font-lock-type-face)
-
-     (enum_body (property_identifier) @font-lock-type-face)
-
-     (enum_assignment name: (property_identifier) @font-lock-type-face)
-
-     (assignment_expression
-      left: [(identifier) @font-lock-variable-name-face
-             (member_expression
-              property: (property_identifier) @font-lock-variable-name-face)])
-
-     (for_in_statement
-      left: (identifier) @font-lock-variable-name-face)
-
-     (arrow_function
-      parameter: (identifier) @font-lock-variable-name-face)
-
      (arrow_function
       parameters:
       [(_ (identifier) @font-lock-variable-name-face)
        (_ (_ (identifier) @font-lock-variable-name-face))
        (_ (_ (_ (identifier) @font-lock-variable-name-face)))])
 
-
      (pair key: (property_identifier) @font-lock-variable-name-face)
 
      (pair value: (identifier) @font-lock-variable-name-face)
@@ -211,80 +245,24 @@ ts-mode--settings
       [(nested_identifier (identifier)) (identifier)]
       @font-lock-function-name-face)
 
-     (jsx_attribute (property_identifier) @font-lock-constant-face)
-
-     [(this) (super)] @font-lock-keyword-face
-
-     [(true) (false) (null)] @font-lock-constant-face
-     (regex pattern: (regex_pattern)) @font-lock-string-face
-     (number) @font-lock-constant-face
-
-     (string) @font-lock-string-face
-
-     (template_string) @js--fontify-template-string
-     (template_substitution
-      ["${" "}"] @font-lock-constant-face)
-
-     ["!"
-      "abstract"
-      "as"
-      "async"
-      "await"
-      "break"
-      "case"
-      "catch"
-      "class"
-      "const"
-      "continue"
-      "debugger"
-      "declare"
-      "default"
-      "delete"
-      "do"
-      "else"
-      "enum"
-      "export"
-      "extends"
-      "finally"
-      "for"
-      "from"
-      "function"
-      "get"
-      "if"
-      "implements"
-      "import"
-      "in"
-      "instanceof"
-      "interface"
-      "keyof"
-      "let"
-      "namespace"
-      "new"
-      "of"
-      "private"
-      "protected"
-      "public"
-      "readonly"
-      "return"
-      "set"
-      "static"
-      "switch"
-      "target"
-      "throw"
-      "try"
-      "type"
-      "typeof"
-      "var"
-      "void"
-      "while"
-      "with"
-      "yield"
-      ] @font-lock-keyword-face
-
-     (comment) @font-lock-comment-face
-     ))
+     (jsx_attribute (property_identifier) @font-lock-constant-face)))
   "Tree-sitter font-lock settings.")
 
+(defun ts-mode--fontify-template-string (beg end node)
+  "Fontify template string but not substitution inside it.
+BEG, END, NODE refers to the template_string node."
+  (ignore end)
+  ;; Stolen from `js--fontify-template-string'
+  (let ((child (treesit-node-child node 0)))
+    (while child
+      (if (equal (treesit-node-type child) "template_substitution")
+          (put-text-property beg (treesit-node-start child)
+                             'face 'font-lock-string-face)
+        (put-text-property beg (treesit-node-end child)
+                           'face 'font-lock-string-face))
+      (setq beg (treesit-node-end child)
+            child (treesit-node-next-sibling child)))))
+
 (defvar ts-mode--defun-type-regexp
   (rx (or "class_declaration"
           "method_definition"
@@ -354,9 +332,10 @@ ts-mode
     (unless font-lock-defaults
       (setq font-lock-defaults '(nil t)))
 
-    (setq-local treesit-font-lock-settings ts-mode--settings)
+    (setq-local treesit-font-lock-settings ts-mode--font-lock-settings)
+
+    (setq treesit-font-lock-feature-list '((minimal) (moderate) (full)))
 
-    (setq treesit-font-lock-feature-list '((basic)))
     (treesit-font-lock-enable))
    (t
     (message "Tree sitter for TypeScript isn't available, defaulting to js-mode")
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Disable tree-sitter font-locking for smaller ranges
  2022-10-18 20:07                   ` Theodor Thornhill
@ 2022-10-18 20:44                     ` Yuan Fu
  0 siblings, 0 replies; 14+ messages in thread
From: Yuan Fu @ 2022-10-18 20:44 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: emacs-devel



> On Oct 18, 2022, at 1:07 PM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> Theodor Thornhill <theo@thornhill.no> writes:
>> The separate variables was more for readability, but I can change that back :)
> 
> 
> Something like this?
> 
> Theo
> 
> <0001-Add-more-granular-features-in-font-locking.patch>

Merged and pushed, thanks!

Yuan


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-10-18 20:44 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-16 10:32 Disable tree-sitter font-locking for smaller ranges Theodor Thornhill
2022-10-17  5:04 ` Yuan Fu
2022-10-17  5:49   ` Theodor Thornhill
2022-10-17  6:01     ` Yuan Fu
2022-10-17  6:33       ` Theodor Thornhill
2022-10-17  9:00         ` Yuan Fu
2022-10-17  9:41           ` Theodor Thornhill
2022-10-17 11:02             ` Theodor Thornhill via Emacs development discussions.
2022-10-18  0:20               ` Yuan Fu
2022-10-18  5:04                 ` Theodor Thornhill
2022-10-18 20:07                   ` Theodor Thornhill
2022-10-18 20:44                     ` Yuan Fu
2022-10-18  5:06             ` Yuan Fu
2022-10-18  1:23           ` Trey Peacock

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).