From 5fc39ea5745fced54ae4cae94bb63e2208dfbf69 Mon Sep 17 00:00:00 2001
From: Yuan Fu <casouri@gmail.com>
Date: Fri, 20 Sep 2024 01:16:44 -0700
Subject: [PATCH] Update csharp-ts-mode font-lock (bug#73369)

Adapt to the latest c-sharp grammar.

* lisp/progmodes/csharp-mode.el:
(csharp-ts-mode--test-this-expression):
(csharp-ts-mode--test-interpolated-string-text):
(csharp-ts-mode--test-type-constraint):
(csharp-ts-mode--test-type-of-expression):
(csharp-ts-mode--test-name-equals):
(csharp-ts-mode--test-if-directive):
(csharp-ts-mode--test-method-declaration-type-field): New
functions.
(csharp-ts-mode--type-field): New variable.
(csharp-ts-mode--font-lock-settings): Fix font-lock rules.
---
 lisp/progmodes/csharp-mode.el | 155 ++++++++++++++++++++++++++--------
 1 file changed, 118 insertions(+), 37 deletions(-)

diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 29325ab9632..755303a158d 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -730,6 +730,52 @@ csharp-ts-mode--keywords
     "readonly" "unmanaged")
   "C# keywords for tree-sitter font-locking.")
 
+(defun csharp-ts-mode--test-this-expression ()
+  "Return non-nil if (this_expression) is named in csharp grammar."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(this_expression)" t)
+    t))
+
+(defun csharp-ts-mode--test-interpolated-string-text ()
+  "Return non-nil if (interpolated_string_text) is in the grammar."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(interpolated_string_text)" t)
+    t))
+
+(defun csharp-ts-mode--test-type-constraint ()
+  "Return non-nil if (type_constraint) is in the grammar."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(type_constraint)" t)
+    t))
+
+(defun csharp-ts-mode--test-type-of-expression ()
+  "Return non-nil if (type_of_expression) is in the grammar."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(type_of_expression)" t)
+    t))
+
+(defun csharp-ts-mode--test-name-equals ()
+  "Return non-nil if (name_equals) is in the grammar."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(name_equals)" t)
+    t))
+
+(defun csharp-ts-mode--test-if-directive ()
+  "Return non-nil if (if_directive) is in the grammar."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(if_directive)" t)
+    t))
+
+(defun csharp-ts-mode--test-method-declaration-type-field ()
+  "Return non-nil if (method_declaration) has a type field."
+  (ignore-errors
+    (treesit-query-compile 'c-sharp "(method_declaration type: (_))" t)
+    t))
+
+(defvar csharp-ts-mode--type-field
+  (if (csharp-ts-mode--test-method-declaration-type-field)
+      'type: 'returns:))
+
 (defvar csharp-ts-mode--font-lock-settings
   (treesit-font-lock-rules
    :language 'c-sharp
@@ -760,7 +806,9 @@ csharp-ts-mode--font-lock-settings
    :feature 'keyword
    `([,@csharp-ts-mode--keywords] @font-lock-keyword-face
      (modifier) @font-lock-keyword-face
-     (this_expression) @font-lock-keyword-face)
+     ,@(if (csharp-ts-mode--test-this-expression)
+           '((this_expression) @font-lock-keyword-face)
+         '("this" @font-lock-keyword-face)))
 
    :language 'c-sharp
    :override t
@@ -786,18 +834,23 @@ csharp-ts-mode--font-lock-settings
    :feature 'string
    `([(string_literal)
       (verbatim_string_literal)
-      (interpolated_string_text)
-      (interpolated_verbatim_string_text)
-      (character_literal)
-      "\""
-      "$\""
-      "@$\""
-      "$@\""] @font-lock-string-face)
+      ,@(if (csharp-ts-mode--test-interpolated-string-text)
+            '((interpolated_string_text)
+              (interpolated_verbatim_string_text)
+              (character_literal)
+              "\""
+              "$\""
+              "@$\""
+              "$@\"")
+          '((interpolated_string_expression)
+            (interpolation_start)
+            (interpolation_quote)))]
+     @font-lock-string-face)
 
    :language 'c-sharp
    :override t
    :feature 'type
-   '((predefined_type) @font-lock-type-face
+   `((predefined_type) @font-lock-type-face
      (implicit_type) @font-lock-type-face
      (nullable_type) @font-lock-type-face
      (type_parameter
@@ -816,10 +869,17 @@ csharp-ts-mode--font-lock-settings
      (cast_expression (generic_name (identifier) @font-lock-type-face))
      ["operator"] @font-lock-type-face
      (type_parameter_constraints_clause
-      target: (identifier) @font-lock-type-face)
-     (type_constraint type: (identifier) @font-lock-type-face)
-     (type_constraint type: (generic_name (identifier) @font-lock-type-face))
-     (type_of_expression (identifier) @font-lock-type-face)
+      (identifier) @font-lock-type-face)
+     ,@(if (csharp-ts-mode--test-type-constraint)
+           '((type_constraint type: (identifier) @font-lock-type-face)
+             (type_constraint type: (generic_name (identifier) @font-lock-type-face)))
+         '((type_parameter_constraint (type type: (identifier) @font-lock-type-face))
+           (type_parameter_constraint (type type: (generic_name (identifier) @font-lock-type-face)))))
+
+     ,@(when (csharp-ts-mode--test-type-of-expression)
+         '((type_of_expression (identifier) @font-lock-type-face))
+         '((typeof_expression (identifier) @font-lock-type-face)))
+
      (object_creation_expression
       type: (identifier) @font-lock-type-face)
      (object_creation_expression
@@ -832,8 +892,9 @@ csharp-ts-mode--font-lock-settings
    :override t
    `((qualified_name (identifier) @font-lock-type-face)
      (using_directive (identifier) @font-lock-type-face)
-     (using_directive (name_equals
-                       (identifier) @font-lock-type-face))
+     ,@(when (csharp-ts-mode--test-name-equals)
+         '((using_directive (name_equals
+                             (identifier) @font-lock-type-face))))
 
      (enum_declaration (identifier) @font-lock-type-face)
      (enum_member_declaration (identifier) @font-lock-variable-name-face)
@@ -861,10 +922,10 @@ csharp-ts-mode--font-lock-settings
      ;;; Check if keyword void_keyword is available, then return the correct rule."
      ,@(condition-case nil
            (progn (treesit-query-capture 'csharp '((void_keyword) @capture))
-                  `((method_declaration type: [(identifier) (void_keyword)] @font-lock-type-face)))
+                  `((method_declaration ,csharp-ts-mode--type-field [(identifier) (void_keyword)] @font-lock-type-face)))
          (error
-          `((method_declaration type: [(identifier) (predefined_type)] @font-lock-type-face))))
-     (method_declaration type: (generic_name (identifier) @font-lock-type-face))
+          `((method_declaration ,csharp-ts-mode--type-field [(identifier) (predefined_type)] @font-lock-type-face))))
+     (method_declaration ,csharp-ts-mode--type-field (generic_name (identifier) @font-lock-type-face))
      (method_declaration name: (_) @font-lock-function-name-face)
 
      (catch_declaration
@@ -907,25 +968,45 @@ csharp-ts-mode--font-lock-settings
    :language 'c-sharp
    :feature 'directives
    :override t
-   '((if_directive
-      "if" @font-lock-preprocessor-face
-      (identifier) @font-lock-variable-use-face)
-     (elif_directive
-      "elif" @font-lock-preprocessor-face
-      (identifier) @font-lock-variable-use-face)
-     (else_directive) @font-lock-preprocessor-face
-     (endif_directive) @font-lock-preprocessor-face
-     (define_directive
-      "define" @font-lock-preprocessor-face
-      (identifier) @font-lock-variable-use-face)
-     (nullable_directive) @font-lock-preprocessor-face
-     (pragma_directive) @font-lock-preprocessor-face
-     (region_directive) @font-lock-preprocessor-face
-     (endregion_directive) @font-lock-preprocessor-face
-     (region_directive
-      (preproc_message) @font-lock-variable-use-face)
-     (endregion_directive
-      (preproc_message) @font-lock-variable-use-face))))
+   (if (csharp-ts-mode--test-if-directive)
+       '((if_directive
+          "if" @font-lock-preprocessor-face
+          (identifier) @font-lock-variable-use-face)
+         (elif_directive
+          "elif" @font-lock-preprocessor-face
+          (identifier) @font-lock-variable-use-face)
+         (else_directive) @font-lock-preprocessor-face
+         (endif_directive) @font-lock-preprocessor-face
+         (define_directive
+          "define" @font-lock-preprocessor-face
+          (identifier) @font-lock-variable-use-face)
+         (nullable_directive) @font-lock-preprocessor-face
+         (pragma_directive) @font-lock-preprocessor-face
+         (region_directive) @font-lock-preprocessor-face
+         (endregion_directive) @font-lock-preprocessor-face
+         (region_directive
+          (preproc_message) @font-lock-variable-use-face)
+         (endregion_directive
+          (preproc_message) @font-lock-variable-use-face))
+     '((preproc_if
+        "#if" @font-lock-preprocessor-face
+        (identifier) @font-lock-variable-use-face)
+       (preproc_elif
+        "#elif" @font-lock-preprocessor-face
+        (identifier) @font-lock-variable-use-face)
+       (preproc_else) @font-lock-preprocessor-face
+       "#endif" @font-lock-preprocessor-face
+       (preproc_define
+        "#define" @font-lock-preprocessor-face
+        (preproc_arg) @font-lock-variable-use-face)
+       (preproc_nullable) @font-lock-preprocessor-face
+       (preproc_pragma) @font-lock-preprocessor-face
+       (preproc_region) @font-lock-preprocessor-face
+       (preproc_endregion) @font-lock-preprocessor-face
+       (preproc_region
+        (preproc_arg) @font-lock-variable-use-face)
+       (preproc_endregion
+        (preproc_arg) @font-lock-variable-use-face)))))
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
-- 
2.39.5 (Apple Git-151)

