Fix font lock in php-ts-mode

Fix font lock in php-ts-mode when the tree-sitter grammars are
automatically installed.  Also, update php-ts-mode to call the new
`mhtml-ts-mode--treesit-font-lock-settings' function.

* lisp/progmodes/php-ts-mode.el (php-ts-mode--keywords)
(php-ts-mode--operators): Generate the lists after the tree-sitter
grammars are installed.
(php-ts-mode--font-lock-settings, php-ts-mode--font-lock-settings-cached)
(php-ts-mode--custom-html-font-lock-settings)
(php-ts-mode--custom-html-font-lock-settings-cached): Evaluate the rules
after the tree-sitter grammars are installed.  Also, add cache for the
rules.
(php-ts-mode): Call the new
`php-ts-mode--custom-html-font-lock-settings' function.  (Bug#79363)
This commit is contained in:
Roi Martin
2025-09-21 20:07:12 +02:00
committed by Juri Linkov
parent 77ca60b48d
commit 85c42b3a87

View File

@@ -888,31 +888,29 @@ characters of the current line."
"Return t if the operator '|>' is defined, nil otherwise."
(treesit-query-valid-p 'php '("|>")))
(defvar php-ts-mode--keywords
(when (treesit-available-p)
(append
'("abstract" "and" "array" "as" "break" "case" "catch"
"class" "clone" "const" "continue" "declare" "default" "do" "echo"
"else" "elseif" "enddeclare" "endfor" "endforeach" "endif"
"endswitch" "endwhile" "enum" "exit" "extends" "final" "finally" "fn"
"for" "foreach" "function" "global" "goto" "if" "implements"
"include" "include_once" "instanceof" "insteadof" "interface"
"list" "match" "namespace" "new" "null" "or" "print" "private"
"protected" "public" "readonly" "require" "require_once" "return"
"static" "switch" "throw" "trait" "try" "unset" "use" "while" "xor"
"yield")
(if (php-ts-mode--test-yield-from-p) '("yield from") '("from"))))
"PHP keywords for tree-sitter font-locking.")
(defun php-ts-mode--keywords ()
"PHP keywords for tree-sitter font-locking."
(append
'("abstract" "and" "array" "as" "break" "case" "catch"
"class" "clone" "const" "continue" "declare" "default" "do" "echo"
"else" "elseif" "enddeclare" "endfor" "endforeach" "endif"
"endswitch" "endwhile" "enum" "exit" "extends" "final" "finally" "fn"
"for" "foreach" "function" "global" "goto" "if" "implements"
"include" "include_once" "instanceof" "insteadof" "interface"
"list" "match" "namespace" "new" "null" "or" "print" "private"
"protected" "public" "readonly" "require" "require_once" "return"
"static" "switch" "throw" "trait" "try" "unset" "use" "while" "xor"
"yield")
(if (php-ts-mode--test-yield-from-p) '("yield from") '("from"))))
(defvar php-ts-mode--operators
(when (treesit-available-p)
(append
'("--" "**=" "*=" "/=" "%=" "+=" "-=" ".=" "<<=" ">>=" "&=" "^="
"|=" "??" "??=" "||" "&&" "|" "^" "&" "==" "!=" "<>" "===" "!=="
"<" ">" "<=" ">=" "<=>" "<<" ">>" "+" "-" "." "*" "**" "/" "%"
"->" "?->" "...")
(when (php-ts-mode--test-pipe-p) '("|>"))))
"PHP operators for tree-sitter font-locking.")
(defun php-ts-mode--operators ()
"PHP operators for tree-sitter font-locking."
(append
'("--" "**=" "*=" "/=" "%=" "+=" "-=" ".=" "<<=" ">>=" "&=" "^="
"|=" "??" "??=" "||" "&&" "|" "^" "&" "==" "!=" "<>" "===" "!=="
"<" ">" "<=" ">=" "<=>" "<<" ">>" "+" "-" "." "*" "**" "/" "%"
"->" "?->" "...")
(when (php-ts-mode--test-pipe-p) '("|>"))))
(defconst php-ts-mode--predefined-constant
'(;; predefined constant
@@ -957,228 +955,244 @@ characters of the current line."
("::" . ?∷))
"Value for `prettify-symbols-alist' in `php-ts-mode'.")
(defvar php-ts-mode--font-lock-settings-cached nil
"Cached tree-sitter font-lock settings for `php-ts-mode'.")
(defun php-ts-mode--font-lock-settings ()
"Tree-sitter font-lock settings."
(treesit-font-lock-rules
"Return tree-sitter font-lock settings for `php-ts-mode'.
:language 'php
:feature 'keyword
:override t
`([,@php-ts-mode--keywords] @font-lock-keyword-face
,@(when (php-ts-mode--test-visibility-modifier-operation-p)
'((visibility_modifier (operation) @font-lock-builtin-face)))
(var_modifier) @font-lock-builtin-face)
Tree-sitter font-lock settings are evaluated the first time this
function is called. Subsequent calls return the first evaluated value."
(or php-ts-mode--font-lock-settings-cached
(setq php-ts-mode--font-lock-settings-cached
(treesit-font-lock-rules
:language 'php
:feature 'comment
:override t
'((comment) @font-lock-comment-face)
:language 'php
:feature 'keyword
:override t
`([,@(php-ts-mode--keywords)] @font-lock-keyword-face
,@(when (php-ts-mode--test-visibility-modifier-operation-p)
'((visibility_modifier (operation) @font-lock-builtin-face)))
(var_modifier) @font-lock-builtin-face)
:language 'php
:feature 'constant
`((boolean) @font-lock-constant-face
(null) @font-lock-constant-face
;; predefined constant or built in constant (part of PHP core)
((name) @font-lock-builtin-face
(:match ,(rx-to-string
`(: bos (or ,@php-ts-mode--predefined-constant) eos))
@font-lock-builtin-face))
;; user defined constant
((name) @font-lock-constant-face
(:match "\\`_*[A-Z][0-9A-Z_]+\\'" @font-lock-constant-face))
(const_declaration
(const_element (name) @font-lock-constant-face))
;; declare directive
(declare_directive ["strict_types" "encoding" "ticks"] @font-lock-constant-face))
:language 'php
:feature 'comment
:override t
'((comment) @font-lock-comment-face)
:language 'php
:feature 'name
'((goto_statement (name) @font-lock-constant-face)
(named_label_statement (name) @font-lock-constant-face))
:language 'php
:feature 'constant
`((boolean) @font-lock-constant-face
(null) @font-lock-constant-face
;; predefined constant or built in constant (part of PHP core)
((name) @font-lock-builtin-face
(:match ,(rx-to-string
`(: bos (or ,@php-ts-mode--predefined-constant) eos))
@font-lock-builtin-face))
;; user defined constant
((name) @font-lock-constant-face
(:match "\\`_*[A-Z][0-9A-Z_]+\\'" @font-lock-constant-face))
(const_declaration
(const_element (name) @font-lock-constant-face))
;; declare directive
(declare_directive ["strict_types" "encoding" "ticks"] @font-lock-constant-face))
:language 'php
:feature 'delimiter
`((["," ":" ";" "\\"]) @font-lock-delimiter-face)
:language 'php
:feature 'name
'((goto_statement (name) @font-lock-constant-face)
(named_label_statement (name) @font-lock-constant-face))
:language 'php
:feature 'operator
`((error_suppression_expression "@" @font-lock-keyword-face)
[,@php-ts-mode--operators] @font-lock-operator-face)
:language 'php
:feature 'delimiter
`((["," ":" ";" "\\"]) @font-lock-delimiter-face)
:language 'php
:feature 'variable-name
:override t
'(((name) @font-lock-keyword-face (:equal "this" @font-lock-keyword-face))
(variable_name (name) @font-lock-variable-name-face)
(relative_scope ["parent" "self" "static"] @font-lock-builtin-face)
(relative_scope) @font-lock-constant-face
(dynamic_variable_name (name) @font-lock-variable-name-face)
(member_access_expression
name: (_) @font-lock-variable-name-face)
(scoped_property_access_expression
scope: (name) @font-lock-constant-face)
(nullsafe_member_access_expression (name) @font-lock-variable-name-face)
(error_suppression_expression (name) @font-lock-property-name-face))
:language 'php
:feature 'operator
`((error_suppression_expression "@" @font-lock-keyword-face)
[,@(php-ts-mode--operators)] @font-lock-operator-face)
:language 'php
:feature 'string
`(("\"") @font-lock-string-face
(encapsed_string) @font-lock-string-face
(string_content) @font-lock-string-face
(string) @font-lock-string-face)
:language 'php
:feature 'variable-name
:override t
'(((name) @font-lock-keyword-face (:equal "this" @font-lock-keyword-face))
(variable_name (name) @font-lock-variable-name-face)
(relative_scope ["parent" "self" "static"] @font-lock-builtin-face)
(relative_scope) @font-lock-constant-face
(dynamic_variable_name (name) @font-lock-variable-name-face)
(member_access_expression
name: (_) @font-lock-variable-name-face)
(scoped_property_access_expression
scope: (name) @font-lock-constant-face)
(nullsafe_member_access_expression (name) @font-lock-variable-name-face)
(error_suppression_expression (name) @font-lock-property-name-face))
:language 'php
:feature 'literal
'((integer) @font-lock-number-face
(float) @font-lock-number-face
(heredoc identifier: (heredoc_start) @font-lock-constant-face)
(heredoc_body (string_content) @font-lock-string-face)
(heredoc end_tag: (heredoc_end) @font-lock-constant-face)
(nowdoc identifier: (heredoc_start) @font-lock-constant-face)
(nowdoc_body (nowdoc_string) @font-lock-string-face)
(nowdoc end_tag: (heredoc_end) @font-lock-constant-face)
(shell_command_expression) @font-lock-string-face)
:language 'php
:feature 'string
`(("\"") @font-lock-string-face
(encapsed_string) @font-lock-string-face
(string_content) @font-lock-string-face
(string) @font-lock-string-face)
:language 'php
:feature 'type
:override t
'((union_type "|" @font-lock-operator-face)
(union_type) @font-lock-type-face
(bottom_type) @font-lock-type-face
(primitive_type) @font-lock-type-face
((primitive_type) @font-lock-keyword-face
(:equal "callable" @font-lock-keyword-face))
(cast_type) @font-lock-type-face
(named_type) @font-lock-type-face
(optional_type) @font-lock-type-face)
:language 'php
:feature 'literal
'((integer) @font-lock-number-face
(float) @font-lock-number-face
(heredoc identifier: (heredoc_start) @font-lock-constant-face)
(heredoc_body (string_content) @font-lock-string-face)
(heredoc end_tag: (heredoc_end) @font-lock-constant-face)
(nowdoc identifier: (heredoc_start) @font-lock-constant-face)
(nowdoc_body (nowdoc_string) @font-lock-string-face)
(nowdoc end_tag: (heredoc_end) @font-lock-constant-face)
(shell_command_expression) @font-lock-string-face)
:language 'php
:feature 'definition
:override t
`((php_tag) @font-lock-preprocessor-face
,@(if (php-ts-mode--test-php-end-tag-p)
'((php_end_tag) @font-lock-preprocessor-face)
'(("?>") @font-lock-preprocessor-face))
;; Highlights identifiers in declarations.
(class_declaration
name: (_) @font-lock-type-face)
(class_interface_clause (name) @font-lock-type-face)
(interface_declaration
name: (_) @font-lock-type-face)
(trait_declaration
name: (_) @font-lock-type-face)
(enum_declaration
name: (_) @font-lock-type-face)
(function_definition
name: (_) @font-lock-function-name-face)
,@(when (php-ts-mode--test-property-hook-p)
'((property_hook (name) @font-lock-function-name-face)))
(method_declaration
name: (_) @font-lock-function-name-face)
(method_declaration
name: (name) @font-lock-builtin-face
(:match ,(rx-to-string
`(: bos (or ,@php-ts-mode--class-magic-methods) eos))
@font-lock-builtin-face))
("=>") @font-lock-keyword-face
(object_creation_expression
(name) @font-lock-type-face)
,@(when (php-ts-mode--test-namespace-name-as-prefix-p)
'((namespace_name_as_prefix "\\" @font-lock-delimiter-face)
(namespace_name_as_prefix
(namespace_name (name)) @font-lock-type-face)))
,@(if (php-ts-mode--test-namespace-aliasing-clause-p)
'((namespace_aliasing_clause (name) @font-lock-type-face))
'((namespace_use_clause alias: (name) @font-lock-type-face)))
,@(when (not (php-ts-mode--test-namespace-use-group-clause-p))
'((namespace_use_group
(namespace_use_clause (name) @font-lock-type-face))))
(namespace_use_clause (name) @font-lock-type-face)
(namespace_name "\\" @font-lock-delimiter-face)
(namespace_name (name) @font-lock-type-face)
(use_declaration (name) @font-lock-property-use-face)
(use_instead_of_clause (name) @font-lock-type-face)
(binary_expression
operator: "instanceof"
right: (name) @font-lock-type-face))
:language 'php
:feature 'type
:override t
'((union_type "|" @font-lock-operator-face)
(union_type) @font-lock-type-face
(bottom_type) @font-lock-type-face
(primitive_type) @font-lock-type-face
((primitive_type) @font-lock-keyword-face
(:equal "callable" @font-lock-keyword-face))
(cast_type) @font-lock-type-face
(named_type) @font-lock-type-face
(optional_type) @font-lock-type-face)
:language 'php
:feature 'function-scope
:override t
'((scoped_call_expression
scope: (name) @font-lock-constant-face)
(class_constant_access_expression (name) @font-lock-constant-face))
:language 'php
:feature 'definition
:override t
`((php_tag) @font-lock-preprocessor-face
,@(if (php-ts-mode--test-php-end-tag-p)
'((php_end_tag) @font-lock-preprocessor-face)
'(("?>") @font-lock-preprocessor-face))
;; Highlights identifiers in declarations.
(class_declaration
name: (_) @font-lock-type-face)
(class_interface_clause (name) @font-lock-type-face)
(interface_declaration
name: (_) @font-lock-type-face)
(trait_declaration
name: (_) @font-lock-type-face)
(enum_declaration
name: (_) @font-lock-type-face)
(function_definition
name: (_) @font-lock-function-name-face)
,@(when (php-ts-mode--test-property-hook-p)
'((property_hook (name) @font-lock-function-name-face)))
(method_declaration
name: (_) @font-lock-function-name-face)
(method_declaration
name: (name) @font-lock-builtin-face
(:match ,(rx-to-string
`(: bos (or ,@php-ts-mode--class-magic-methods) eos))
@font-lock-builtin-face))
("=>") @font-lock-keyword-face
(object_creation_expression
(name) @font-lock-type-face)
,@(when (php-ts-mode--test-namespace-name-as-prefix-p)
'((namespace_name_as_prefix "\\" @font-lock-delimiter-face)
(namespace_name_as_prefix
(namespace_name (name)) @font-lock-type-face)))
,@(if (php-ts-mode--test-namespace-aliasing-clause-p)
'((namespace_aliasing_clause (name) @font-lock-type-face))
'((namespace_use_clause alias: (name) @font-lock-type-face)))
,@(when (not (php-ts-mode--test-namespace-use-group-clause-p))
'((namespace_use_group
(namespace_use_clause (name) @font-lock-type-face))))
(namespace_use_clause (name) @font-lock-type-face)
(namespace_name "\\" @font-lock-delimiter-face)
(namespace_name (name) @font-lock-type-face)
(use_declaration (name) @font-lock-property-use-face)
(use_instead_of_clause (name) @font-lock-type-face)
(binary_expression
operator: "instanceof"
right: (name) @font-lock-type-face))
:language 'php
:feature 'function-call
:override t
'((function_call_expression
function: (name) @font-lock-function-call-face)
(scoped_call_expression
name: (name) @font-lock-function-call-face)
(member_call_expression
name: (name) @font-lock-function-call-face)
(nullsafe_member_call_expression
name: (_) @font-lock-function-call-face))
:language 'php
:feature 'function-scope
:override t
'((scoped_call_expression
scope: (name) @font-lock-constant-face)
(class_constant_access_expression (name) @font-lock-constant-face))
:language 'php
:feature 'argument
'((argument
name: (_) @font-lock-constant-face))
:language 'php
:feature 'function-call
:override t
'((function_call_expression
function: (name) @font-lock-function-call-face)
(scoped_call_expression
name: (name) @font-lock-function-call-face)
(member_call_expression
name: (name) @font-lock-function-call-face)
(nullsafe_member_call_expression
name: (_) @font-lock-function-call-face))
:language 'php
:feature 'escape-sequence
:override t
'((string (escape_sequence) @font-lock-escape-face)
(encapsed_string (escape_sequence) @font-lock-escape-face)
(heredoc_body (escape_sequence) @font-lock-escape-face))
:language 'php
:feature 'argument
'((argument
name: (_) @font-lock-constant-face))
:language 'php
:feature 'base-clause
:override t
`((base_clause (name) @font-lock-type-face)
(use_as_clause (name) @font-lock-property-use-face)
,@(when (not (php-ts-mode--test-namespace-name-as-prefix-p))
'((qualified_name prefix: "\\" @font-lock-delimiter-face)))
(qualified_name (name) @font-lock-constant-face)
,@(when (php-ts-mode--test-relative-name-p)
'((relative_name (name) @font-lock-constant-face))))
:language 'php
:feature 'escape-sequence
:override t
'((string (escape_sequence) @font-lock-escape-face)
(encapsed_string (escape_sequence) @font-lock-escape-face)
(heredoc_body (escape_sequence) @font-lock-escape-face))
:language 'php
:feature 'property
'((enum_case
name: (_) @font-lock-type-face))
:language 'php
:feature 'base-clause
:override t
`((base_clause (name) @font-lock-type-face)
(use_as_clause (name) @font-lock-property-use-face)
,@(when (not (php-ts-mode--test-namespace-name-as-prefix-p))
'((qualified_name prefix: "\\" @font-lock-delimiter-face)))
(qualified_name (name) @font-lock-constant-face)
,@(when (php-ts-mode--test-relative-name-p)
'((relative_name (name) @font-lock-constant-face))))
:language 'php
:feature 'attribute
'((((attribute (_) @attribute_name) @font-lock-preprocessor-face)
(:equal "Deprecated" @attribute_name))
(attribute_group (attribute (name) @font-lock-constant-face)))
:language 'php
:feature 'property
'((enum_case
name: (_) @font-lock-type-face))
:language 'php
:feature 'bracket
'((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
:language 'php
:feature 'attribute
'((((attribute (_) @attribute_name) @font-lock-preprocessor-face)
(:equal "Deprecated" @attribute_name))
(attribute_group (attribute (name) @font-lock-constant-face)))
:language 'php
:feature 'error
:override t
'((ERROR) @php-ts-mode--fontify-error)))
:language 'php
:feature 'bracket
'((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
:language 'php
:feature 'error
:override t
'((ERROR) @php-ts-mode--fontify-error)))))
;;; Font-lock helpers
(defconst php-ts-mode--custom-html-font-lock-settings
(treesit-replace-font-lock-feature-settings
(treesit-font-lock-rules
:language 'html
:override t
:feature 'comment
'((comment) @font-lock-comment-face
;; handle shebang path and others type of comment
(document (text) @font-lock-comment-face)))
mhtml-ts-mode--treesit-font-lock-settings)
(defvar php-ts-mode--custom-html-font-lock-settings-cached nil
"Cached tree-sitter font-lock settings for HTML when embedded in PHP.")
(defun php-ts-mode--custom-html-font-lock-settings ()
"Tree-sitter Font-lock settings for HTML when embedded in PHP.
Like `mhtml-ts-mode--font-lock-settings' but adapted for `php-ts-mode'.")
Like `mhtml-ts-mode--font-lock-settings' but adapted for `php-ts-mode'.
Tree-sitter font-lock settings are evaluated the first time this
function is called. Subsequent calls return the first evaluated value."
(or php-ts-mode--custom-html-font-lock-settings-cached
(setq php-ts-mode--custom-html-font-lock-settings-cached
(treesit-replace-font-lock-feature-settings
(treesit-font-lock-rules
:language 'html
:override t
:feature 'comment
'((comment) @font-lock-comment-face
;; handle shebang path and others type of comment
(document (text) @font-lock-comment-face)))
(mhtml-ts-mode--treesit-font-lock-settings)))))
(defvar php-ts-mode--phpdoc-font-lock-settings
(treesit-font-lock-rules
@@ -1676,7 +1690,7 @@ If FORCE is t setup comment for PHP. Depends on
(setq-local treesit-font-lock-settings
(append
(php-ts-mode--font-lock-settings)
php-ts-mode--custom-html-font-lock-settings
(php-ts-mode--custom-html-font-lock-settings)
php-ts-mode--phpdoc-font-lock-settings))
(setq-local treesit-font-lock-feature-list php-ts-mode--feature-list)