From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Theodor Thornhill via "Emacs development discussions." Newsgroups: gmane.emacs.devel Subject: Re: Disable tree-sitter font-locking for smaller ranges Date: Mon, 17 Oct 2022 13:02:02 +0200 Message-ID: <87o7uazpat.fsf@thornhill.no> References: <877d109hz1.fsf@thornhill.no> <672FF8D1-E5FB-44D8-8E6D-38EB94843B3B@gmail.com> <543ACCB7-9EE3-41AF-B1E3-704B6E6BC085@gmail.com> <87o7ub0xjs.fsf@thornhill.no> <1001F2D8-5976-4E39-BC7B-9EF2A2714B61@gmail.com> <87tu42zt0d.fsf@thornhill.no> Reply-To: Theodor Thornhill Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="17481"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Yuan Fu Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Oct 17 13:11:32 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1okO1r-0004N5-P2 for ged-emacs-devel@m.gmane-mx.org; Mon, 17 Oct 2022 13:11:32 +0200 Original-Received: from localhost ([::1]:49232 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1okO1l-0006md-JB for ged-emacs-devel@m.gmane-mx.org; Mon, 17 Oct 2022 07:11:27 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:60526) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1okNsq-0000jx-8K for emacs-devel@gnu.org; Mon, 17 Oct 2022 07:02:12 -0400 Original-Received: from out0.migadu.com ([94.23.1.103]:61510) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1okNsm-0000im-HN for emacs-devel@gnu.org; Mon, 17 Oct 2022 07:02:11 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thornhill.no; s=key1; t=1666004523; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=hBoXKkAdHTIt1H+CUtYhI4G0ZDm+rjX1FAIhTuCAgco=; b=Qt/ql0GNBW1hj7YurBCQn5+fSFomXFSVui9n3mSCf5O+zYGZMGAFwFMMw9FzMjK78Bdgvl vyr+cYt5AuF4rbcCmM1T4AZ2I3xPYjlUs8KSiQ0+pCWa5JyzPOSdHRV95LY0ympV4pqJeu s3Fj4h76+gGAUob5LSVXqvVggyotqXp68E/Qns1ogN/86579iM2E62SjnqIaTnyEvdaY/m 3+TNNBEP9mn0lLRetLSHtUkuV53Ht8pZyjYOSXrcJUdQm/vRyHMddsZ2qfu8Mt6e9id93Q MVHZwFpexoPj9Zhkzqys3LZm7JvmRhQe2rmulwAOnk5urLUwy0oOBcVcr/EaBw== In-Reply-To: <87tu42zt0d.fsf@thornhill.no> X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=94.23.1.103; envelope-from=theo@thornhill.no; helo=out0.migadu.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:297951 Archived-At: --=-=-= Content-Type: text/plain >> 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 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Add-more-granular-features-in-font-locking.patch >From 1f4f6c6ede3198af4f8c252dd0a56a3ad1bdbd2f Mon Sep 17 00:00:00 2001 From: Theodor Thornhill 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 --=-=-=--