unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Theodor Thornhill via "Emacs development discussions." <emacs-devel@gnu.org>
To: Yuan Fu <casouri@gmail.com>
Cc: emacs-devel@gnu.org
Subject: Re: Disable tree-sitter font-locking for smaller ranges
Date: Mon, 17 Oct 2022 13:02:02 +0200	[thread overview]
Message-ID: <87o7uazpat.fsf@thornhill.no> (raw)
In-Reply-To: <87tu42zt0d.fsf@thornhill.no>

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


  reply	other threads:[~2022-10-17 11:02 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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. [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87o7uazpat.fsf@thornhill.no \
    --to=emacs-devel@gnu.org \
    --cc=casouri@gmail.com \
    --cc=theo@thornhill.no \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).