>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