From 2135e7aa0169639083996fb2a3f82792cdd7a9c0 Mon Sep 17 00:00:00 2001 From: Jostein Kjønigsen Date: Wed, 27 Aug 2025 11:05:28 +0200 Subject: Fixes for csharp-ts-mode fontification (bug#79406) - hightlight reserved keywords agressively, dont allow misuse as variables etc (the compiler will fail!) - highlight lambda-valued variables as funtions. - improve semantics of function/class annotations using attributes (maps closer to using-something than declaring it). also: rename to "attribute". "property" has a different, defined meaning in C#. - better highlight variable-use in different scenarios (function-calls, if-statements, assignment-expressions, property-use, anonymous object initializers). - better highlight for property-use (anonymous object initializers). - highlight field-declaration using font-lock-variable-face. - fontify attributes using new face csharp-ts-mode-attribute-face (defaults to font-lock-property-use-face). - remove extensive use of "override" making evalutation hard-to-reason about. * lisp/progmodes/csharp-mode.el (csharp-ts-mode--indent-rules): Update indent rules. (csharp-ts-mode-faces): New group. (csharp-ts-mode-attribute-face): New face. (csharp-ts-mode--font-lock-settings): Rule updates. (csharp-ts-mode): Change property feature to attribute --- etc/NEWS | 6 +++ lisp/progmodes/csharp-mode.el | 89 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 1a54de9de2e..1d8e85f7d1a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -972,6 +972,12 @@ are highlighted like other comments. When non-nil, Doxygen comment blocks are syntax-highlighted if the Doxygen grammar library is available. +** Csharp-ts-mode + +*** Renamed feature in 'treesit-font-lock-feature-list' +The feature 'property' has been renamed to 'attribute', since this is +what it is called in the general C# community. + ** Go-ts mode +++ diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index 0c44fff18bf..d8b20e1f6f0 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -673,7 +673,7 @@ compilation and evaluation time conflicts." ((parent-is "namespace_declaration") parent-bol 0) ((parent-is "class_declaration") parent-bol 0) ((parent-is "constructor_declaration") parent-bol 0) - ((parent-is "array_creation_expression") parent-bol 0) ;; actual initialization is in contained initializer_expression + ((parent-is "array_creation_expression") parent-bol 0) ;; actual initialization is in contained initializer_expression. ((match "{" "initializer_expression" ) parent-bol 0) ((parent-is "initializer_expression") parent-bol csharp-ts-mode-indent-offset) ((match "{" "anonymous_object_creation_expression") parent-bol 0) @@ -735,6 +735,15 @@ compilation and evaluation time conflicts." "readonly" "unmanaged") "C# keywords for tree-sitter font-locking.") +(defgroup csharp-ts-mode-faces nil + "Font faces." + :group 'cshap) + +(defface csharp-ts-mode-attribute-face + '((t . (:inherit font-lock-property-use-face))) + "Font face used for fontification of attributes." + :group 'csharp-ts-mode-faces) + (defun csharp-ts-mode--test-this-expression () "Return non-nil if (this_expression) is named in csharp grammar." (treesit-query-valid-p 'c-sharp "(this_expression)")) @@ -782,6 +791,18 @@ compilation and evaluation time conflicts." '((conditional_expression (identifier) @font-lock-variable-use-face) (postfix_unary_expression (identifier)* @font-lock-variable-use-face) (initializer_expression (assignment_expression left: (identifier) @font-lock-property-use-face)) + (anonymous_object_creation_expression + (identifier) @font-lock-property-use-face + (identifier) @font-lock-variable-use-face) + (anonymous_object_creation_expression + (identifier) @font-lock-property-use-face + [(object_creation_expression) + (integer_literal) + (string_literal) + (binary_expression) + (invocation_expression) + (member_access_expression) + (conditional_expression)]) (interpolated_string_expression (interpolation (identifier) @font-lock-variable-use-face)) @@ -823,7 +844,24 @@ compilation and evaluation time conflicts." (:match "^[a-z][A-Za-z0-9]+" @font-lock-variable-use-face)) ((binary_expression right: (identifier) @font-lock-variable-use-face) - (:match "^[a-z][A-Za-z0-9]+" @font-lock-variable-use-face))) + (:match "^[a-z][A-Za-z0-9]+" @font-lock-variable-use-face)) + (assignment_expression + right: (identifier) @font-lock-variable-use-face) + (expression_statement ;; capture parent node to NOT shadow variable_declaration. + (assignment_expression + left: (identifier) @font-lock-variable-use-face)) + (if_statement condition: (identifier) @font-lock-variable-use-face) + + ;; handle more specific matchers before generalized variable-use fallback. + (invocation_expression + function: (member_access_expression + name: (identifier) @font-lock-function-call-face)) + (invocation_expression + function: (member_access_expression + name: (generic_name (identifier) @font-lock-function-call-face))) + (member_access_expression + expression: (identifier) @font-lock-variable-use-face + name: (identifier) @font-lock-property-use-face)) :language 'c-sharp :feature 'bracket @@ -849,13 +887,19 @@ compilation and evaluation time conflicts." (modifier) @font-lock-keyword-face ,@(if (csharp-ts-mode--test-this-expression) '((this_expression) @font-lock-keyword-face) - '("this" @font-lock-keyword-face))) + '("this" @font-lock-keyword-face)) + + ;; avoid fontifying indentifiers with a keyword-values as identifiers. + ((identifier) @font-lock-keyword-face + (:match ,(concat "\\`" (regexp-opt csharp-ts-mode--keywords t) "\\'") @font-lock-keyword-face))) :language 'c-sharp :override t - :feature 'property - `((attribute (identifier) @font-lock-property-use-face (attribute_argument_list)) - (attribute (identifier) @font-lock-property-use-face)) + :feature 'attribute + `((attribute_list + "[" @csharp-ts-mode-attribute-face + (attribute name: (identifier) @csharp-ts-mode-attribute-face) + "]" @csharp-ts-mode-attribute-face)) :language 'c-sharp :override t @@ -890,7 +934,6 @@ compilation and evaluation time conflicts." @font-lock-string-face) :language 'c-sharp - :override t :feature 'type `((predefined_type) @font-lock-type-face (implicit_type) @font-lock-type-face @@ -935,7 +978,6 @@ compilation and evaluation time conflicts." :language 'c-sharp :feature 'definition - :override t `((qualified_name (identifier) @font-lock-type-face) (using_directive (identifier) @font-lock-type-face) ,@(when (csharp-ts-mode--test-name-equals) @@ -944,6 +986,8 @@ compilation and evaluation time conflicts." (enum_declaration (identifier) @font-lock-type-face) (enum_member_declaration (identifier) @font-lock-variable-name-face) + (field_declaration (variable_declaration (variable_declarator + name: (identifier) @font-lock-variable-name-face))) (interface_declaration (identifier) @font-lock-type-face) @@ -974,6 +1018,18 @@ compilation and evaluation time conflicts." (method_declaration ,csharp-ts-mode--type-field (generic_name (identifier) @font-lock-type-face)) (method_declaration name: (_) @font-lock-function-name-face) + ;; only fontify known expression-types, to avoid the need to use :override + ;; for lambda-expressions in 'function below. + (variable_declarator + name: (identifier) @font-lock-variable-name-face + [(object_creation_expression) + (integer_literal) + (string_literal) + (binary_expression) + (invocation_expression) + (member_access_expression) + (conditional_expression)]) + (catch_declaration ((identifier) @font-lock-type-face)) (catch_declaration @@ -984,7 +1040,6 @@ compilation and evaluation time conflicts." (variable_declaration (qualified_name name: (generic_name (identifier) @font-lock-type-face))) (variable_declaration (generic_name (identifier) @font-lock-type-face)) - (variable_declarator (identifier) @font-lock-variable-name-face) (parameter type: (identifier) @font-lock-type-face) (parameter type: (generic_name (identifier) @font-lock-type-face)) @@ -1001,14 +1056,6 @@ compilation and evaluation time conflicts." :feature 'function '((invocation_expression function: (identifier) @font-lock-function-call-face) - (invocation_expression - function: (member_access_expression - name: (identifier) @font-lock-function-call-face)) - (invocation_expression - function: (member_access_expression - name: (generic_name (identifier) @font-lock-function-call-face))) - (invocation_expression - function: (generic_name (identifier) @font-lock-function-call-face)) ((invocation_expression function: (member_access_expression expression: (identifier) @font-lock-variable-use-face)) @@ -1018,7 +1065,11 @@ compilation and evaluation time conflicts." expression: (identifier) @font-lock-variable-use-face)) (:match "^[a-z][A-Za-z0-9]+" @font-lock-variable-use-face)) (argument (member_access_expression - name: (identifier) @font-lock-property-use-face))) + name: (identifier) @font-lock-property-use-face)) + ;; only highlight as function if variable contains lambda expression + (variable_declarator + name: (identifier) @font-lock-function-name-face + (lambda_expression))) :language 'c-sharp :feature 'escape-sequence @@ -1198,7 +1249,7 @@ Key bindings: (setq-local treesit-font-lock-feature-list '(( comment definition) ( keyword string type directives) - ( constant escape-sequence expression literal property) + ( constant escape-sequence expression literal attribute) ( function bracket delimiter error))) ;; Imenu. -- cgit v1.2.1