From c4ad36cd2daab764649db451c4a3f1a35c5f519a 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, '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 | 84 +++++++++--------- lisp/progmodes/ts-mode.el | 175 +++++++++++++++++--------------------- 2 files changed, 122 insertions(+), 137 deletions(-) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 51f5b720479..fa548e4df7e 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3454,19 +3454,34 @@ indentation, which-function and movement functions." "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 @@ indentation, which-function and movement functions." (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 @@ indentation, which-function and movement functions." 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 @@ indentation, which-function and movement functions." (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. @@ -3651,12 +3660,11 @@ For BACKEND and WARN see `treesit-mode-function'." (setq-local beginning-of-defun-function #'js--treesit-beginning-of-defun) (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))) - (add-hook 'which-func-functions #'js-treesit-current-defun nil t) + (setq-local font-lock-keywords-only t) + (setq-local treesit-font-lock-settings js--treesit-font-lock-settings) + (setq-local treesit-font-lock-feature-list '((minimal) (moderate) (full))) (treesit-font-lock-enable)) ;; Elisp. ((eq backend 'elisp) @@ -3753,10 +3761,10 @@ For BACKEND and WARN see `treesit-mode-function'." (js--backend-toggle 'elisp nil) (setq-local major-mode-backend-function #'js--backend-toggle)) -(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 @@ -3770,8 +3778,8 @@ For BACKEND and WARN see `treesit-mode-function'." (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 @@ -3793,7 +3801,7 @@ For BACKEND and WARN see `treesit-mode-function'." (setq-local indent-line-function #'treesit-indent) (setq-local font-lock-keywords-only t) - (setq-local treesit-font-lock-settings js--json-treesit-settings) + (setq-local treesit-font-lock-settings js-json--treesit-font-lock-settings) (treesit-font-lock-enable)) ;; Elisp. ((eq backend 'elisp) diff --git a/lisp/progmodes/ts-mode.el b/lisp/progmodes/ts-mode.el index dffe9fcfcf2..a3a2d9f78e7 100644 --- a/lisp/progmodes/ts-mode.el +++ b/lisp/progmodes/ts-mode.el @@ -104,17 +104,49 @@ (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 @@ (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 @@ (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 @@ [(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" @@ -351,9 +329,8 @@ ARG is the same as in `end-of-defun." (setq-local end-of-defun-function #'ts-mode--end-of-defun) (setq font-lock-keywords-only t) - (setq-local treesit-font-lock-settings ts-mode--settings) - - (setq treesit-font-lock-feature-list '((basic))) + (setq-local treesit-font-lock-settings ts-mode--font-lock-settings) + (setq treesit-font-lock-feature-list '((minimal) (moderate) (full))) (treesit-font-lock-enable)) (t (message "Tree-sitter for TypeScript isn't available, falling back to `js-mode'") -- 2.39.2