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
next prev parent 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).