all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#59490: 29.0.50; Add C# support
@ 2022-11-22 20:52 Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-22 21:25 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-22 20:52 UTC (permalink / raw)
  To: 59490; +Cc: casouri, josteink

[-- Attachment #1: Type: text/plain, Size: 438 bytes --]


Hi Yuan, Jostein and others.

Added is support for C# in Emacs.  This is the original C# mode as found
on ELPA [0], as well as support for the new tree sitter mechanisms.

I made two new modes, 'csharp-cc-mode' and 'csharp-ts-mode'. The cc-mode
variant has that name as to not conflict with the ELPA package.

Please shoot comments at me, and I'll fix them.

Hope you like it,

Theodor

[0]: https://github.com/emacs-csharp/csharp-mode


[-- Attachment #2: 0001-Add-csharp-cc-ts-mode.patch --]
[-- Type: text/x-diff, Size: 34663 bytes --]

From 3e8f7a649c70e4222eb1123008623707afdd66b6 Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Tue, 22 Nov 2022 21:22:31 +0100
Subject: [PATCH] Add csharp-{cc|ts}-mode

* etc/NEWS: Mention new modes.
* lisp/progmodes/csharp-mode.el (csharp-cc-mode, csharp-ts-mode): New
major modes.
---
 etc/NEWS                      |   8 +
 lisp/progmodes/csharp-mode.el | 898 ++++++++++++++++++++++++++++++++++
 2 files changed, 906 insertions(+)
 create mode 100644 lisp/progmodes/csharp-mode.el

diff --git a/etc/NEWS b/etc/NEWS
index 5a65896d69..30e2b3780c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2990,6 +2990,14 @@ A major mode based on the tree-sitter library for editing programs
 in the JSON language.  It includes support for font-locking,
 indentation, Imenu, which-func, and navigation.
 
+** New mode 'csharp-ts-mode'.
+A major mode based on the tree-sitter library for editing programs
+in the C# language.  It includes support for font-locking,
+indentation, Imenu, which-func, and navigation.
+
+** New mode 'csharp-cc-mode'.
+A major mode based on CC Mode for editing programs in the C# language.
+
 \f
 * Incompatible Lisp Changes in Emacs 29.1
 
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
new file mode 100644
index 0000000000..0dcd69f8dd
--- /dev/null
+++ b/lisp/progmodes/csharp-mode.el
@@ -0,0 +1,898 @@
+;;; csharp-mode.el --- Support for editing C#  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022  Free Software Foundation, Inc.
+
+;; Author     : Theodor Thornhill <theo@thornhill.no>
+;; Maintainer : Theodor Thornhill <theo@thornhill.no>
+;; Created    : September 2022
+;; Keywords   : c# languages oop
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+
+(require 'cc-mode)
+(require 'cc-langs)
+(eval-when-compile
+  (require 'cc-fonts))
+
+(require 'compile)
+
+(defgroup csharp nil
+  "Major mode for editing C# code."
+  :group 'prog-mode)
+
+(eval-and-compile
+  (defconst csharp-cc-mode--regex-identifier
+    "[A-Za-z][A-Za-z0-9_]*"
+    "Regex describing an dentifier in C#.")
+
+  (defconst csharp-cc-mode--regex-identifier-matcher
+    (concat "\\(" csharp-cc-mode--regex-identifier "\\)")
+    "Regex matching an identifier in C#.")
+
+  (defconst csharp-cc-mode--regex-type-name
+    "[A-Z][A-Za-z0-9_]*"
+    "Regex describing a type identifier in C#.")
+
+  (defconst csharp-cc-mode--regex-type-name-matcher
+    (concat "\\(" csharp-cc-mode--regex-type-name "\\)")
+    "Regex matching a type identifier in C#.")
+
+  (defconst csharp-cc-mode--regex-using-or-namespace
+    (concat "^using" "\\|" "namespace"
+            "\\s *"
+            csharp-cc-mode--regex-type-name-matcher)
+    "Regex matching identifiers after a using or namespace
+    declaration."))
+
+(eval-and-compile
+  (c-add-language 'csharp-cc-mode 'java-mode)
+
+  (defun csharp-cc-mode--make-mode-syntax-table ()
+    (let ((table (make-syntax-table)))
+      (c-populate-syntax-table table)
+      (modify-syntax-entry ?@ "_" table)
+      table))
+
+  (defvar csharp-cc-mode--make-mode-syntax-table #'csharp-cc-mode--make-mode-syntax-table
+    "Workaround for Emacs bug#57065."))
+
+(c-lang-defconst c-make-mode-syntax-table
+  csharp #'csharp-cc-mode--make-mode-syntax-table)
+
+(c-lang-defconst c-identifier-syntax-modifications
+  csharp (append '((?@ . "w"))
+                 (c-lang-const c-identifier-syntax-modifications)))
+
+(c-lang-defconst c-symbol-start
+  csharp (concat "[" c-alpha "_@]"))
+
+(c-lang-defconst c-opt-type-suffix-key
+  csharp (concat "\\(\\[" (c-lang-const c-simple-ws) "*\\]\\|\\?\\)"))
+
+(c-lang-defconst c-identifier-ops
+  csharp '((left-assoc ".")))
+
+(c-lang-defconst c-overloadable-operators
+  csharp '("+" "-" "*" "/" "%" "&" "|" "^" "<<" ">>" "=="
+           "!=" ">" "<" ">=" "<="))
+
+(c-lang-defconst c-multiline-string-start-char
+  csharp ?@)
+
+(c-lang-defconst c-ml-string-opener-re
+  ;; "\\(\\(?:@\\$?\\)\\(\"\\)\\)"
+  csharp
+  (rx
+   (group
+    (or "@" "@$")
+    (group "\""))))
+
+(c-lang-defconst c-ml-string-max-opener-len
+  csharp 3)
+
+(c-lang-defconst c-ml-string-max-closer-len
+  csharp 2)
+
+(c-lang-defconst c-ml-string-any-closer-re
+  ;; "\\(?:\"\"\\)*\\(\\(\"\\)\\)\\(?:[^\"]\\|\\'\\)"
+  csharp
+  (rx
+   (seq
+    (zero-or-more "\"\"")
+    (group
+     (group "\""))
+    (or (not (any "\"")) eos))))
+
+(c-lang-defconst c-ml-string-back-closer-re
+  ;; "\\(?:\\`\\|[^\"]\\)\"*"
+  csharp
+  (rx
+   (seq
+    (or bos
+        (not (any "\"")))
+    (zero-or-more "\""))))
+
+(c-lang-defconst c-type-prefix-kwds
+  csharp '("class" "interface" "struct"))
+
+(c-lang-defconst c-class-decl-kwds
+  csharp '("class" "interface" "struct"))
+
+;;; Keyword lists
+
+(c-lang-defconst c-primitive-type-kwds
+  csharp '("bool" "byte" "sbyte" "char" "decimal" "double" "float" "int" "uint"
+           "long" "ulong" "short" "ushort" "void" "object" "string" "var"))
+
+(c-lang-defconst c-other-decl-kwds
+  csharp nil)
+
+(c-lang-defconst c-type-list-kwds
+  csharp nil)
+
+(c-lang-defconst c-other-block-decl-kwds
+  csharp nil)
+
+(c-lang-defconst c-return-kwds
+  csharp '("return"))
+
+(c-lang-defconst c-typedef-kwds
+  csharp nil)
+
+(c-lang-defconst c-typeof-kwds
+  csharp '("typeof" "is" "as"))
+
+(c-lang-defconst c-type-modifier-prefix-kwds
+  csharp '("volatile"))
+
+(c-lang-defconst c-type-modifier-kwds
+  csharp '("readonly" "new"))
+
+(c-lang-defconst c-brace-list-decl-kwds
+  csharp '("enum" "new"))
+
+(c-lang-defconst c-recognize-post-brace-list-type-p
+  csharp t)
+
+(c-lang-defconst c-ref-list-kwds
+  csharp nil)
+
+(c-lang-defconst c-using-kwds
+  csharp '("using"))
+
+(c-lang-defconst c-equals-type-clause-kwds
+  csharp '("using"))
+
+(defun csharp-cc-mode-at-vsemi-p (&optional pos)
+  (if pos (goto-char pos))
+  (save-excursion
+    (beginning-of-line)
+    (c-forward-syntactic-ws)
+    (looking-at "using\\s *(")))
+
+(c-lang-defconst c-at-vsemi-p-fn
+  csharp 'csharp-cc-mode-at-vsemi-p)
+
+(defun csharp-cc-mode-vsemi-status-unknown () t)
+
+(c-lang-defconst c-vsemi-status-unknown-p-fn
+  csharp 'csharp-cc-mode-vsemi-status-unknown-p)
+
+
+(c-lang-defconst c-modifier-kwds
+  csharp '("abstract" "default" "final" "native" "private" "protected"
+           "public" "partial" "internal" "readonly" "static" "event" "transient"
+           "volatile" "sealed" "ref" "out" "virtual" "implicit" "explicit"
+           "fixed" "override" "params" "async" "await" "extern" "unsafe"
+           "get" "set" "this" "const" "delegate"))
+
+(c-lang-defconst c-other-kwds
+  csharp '("select" "from" "where" "join" "in" "on" "equals" "into"
+           "orderby" "ascending" "descending" "group" "when"
+           "let" "by" "namespace"))
+
+(c-lang-defconst c-colon-type-list-kwds
+  csharp '("class" "struct" "interface"))
+
+(c-lang-defconst c-block-stmt-1-kwds
+  csharp '("do" "else" "finally" "try"))
+
+(c-lang-defconst c-block-stmt-1-2-kwds
+  csharp '("try"))
+
+(c-lang-defconst c-block-stmt-2-kwds
+  csharp '("for" "if" "switch" "while" "catch" "foreach" "fixed" "checked"
+           "unchecked" "using" "lock"))
+
+(c-lang-defconst c-simple-stmt-kwds
+  csharp '("break" "continue" "goto" "throw" "return" "yield"))
+
+(c-lang-defconst c-constant-kwds
+  csharp  '("true" "false" "null" "value"))
+
+(c-lang-defconst c-primary-expr-kwds
+  csharp '("this" "base" "operator"))
+
+(c-lang-defconst c-inexpr-class-kwds
+  csharp nil)
+
+(c-lang-defconst c-class-decl-kwds
+  csharp '("class" "struct" "interface"))
+
+(c-lang-defconst c-std-abbrev-keywords
+  csharp (append (c-lang-const c-std-abbrev-keywords) '("catch" "finally")))
+
+(c-lang-defconst c-decl-prefix-re
+  csharp "\\([{}(;,<]+\\)")
+
+(c-lang-defconst c-recognize-typeless-decls
+  csharp t)
+
+(c-lang-defconst c-recognize-<>-arglists
+  csharp t)
+
+(c-lang-defconst c-opt-cpp-prefix
+  csharp "\\s *#\\s *")
+
+(c-lang-defconst c-opt-cpp-macro-define
+  csharp (if (c-lang-const c-opt-cpp-prefix)
+             "define"))
+
+(c-lang-defconst c-cpp-message-directives
+  csharp '("error" "warning" "region"))
+
+(c-lang-defconst c-cpp-expr-directives
+  csharp '("if" "elif"))
+
+(c-lang-defconst c-other-op-syntax-tokens
+  csharp  (append '("#")
+                  (c-lang-const c-other-op-syntax-tokens)))
+
+(c-lang-defconst c-line-comment-starter
+  csharp "//")
+
+(c-lang-defconst c-doc-comment-start-regexp
+  csharp "///")
+
+(c-add-style "csharp"
+             '("java"
+               (c-basic-offset . 4)
+               (c-comment-only-line-offset . (0 . 0))
+               (c-offsets-alist . ((inline-open           . 0)
+                                   (arglist-intro         . +)
+                                   (arglist-close         . 0)
+                                   (inexpr-class          . 0)
+                                   (case-label            . +)
+                                   (cpp-macro             . c-lineup-dont-change)
+                                   (substatement-open     . 0)))))
+
+(eval-and-compile
+  (unless (or (stringp c-default-style)
+              (assoc 'csharp-cc-mode-mode c-default-style))
+    (setq c-default-style
+          (cons '(csharp-cc-mode . "csharp")
+                c-default-style))))
+
+(defun csharp-cc-mode--color-forwards (font-lock-face)
+  (let (id-beginning)
+    (goto-char (match-beginning 0))
+    (forward-word)
+    (while (and (not (or (eq (char-after) ?\;)
+                         (eq (char-after) ?\{)))
+                (progn
+                  (forward-char)
+                  (c-forward-syntactic-ws)
+                  (setq id-beginning (point))
+                  (> (skip-chars-forward
+                      (c-lang-const c-symbol-chars))
+                     0))
+                (not (get-text-property (point) 'face)))
+      (c-put-font-lock-face id-beginning (point) font-lock-face)
+      (c-forward-syntactic-ws))))
+
+(c-lang-defconst c-basic-matchers-before
+  csharp `(
+           ;; Warning face on unclosed strings
+           ,@(if (version< emacs-version "27.0")
+                 ;; Taken from 26.1 branch
+                 `(,(c-make-font-lock-search-function
+                     (concat ".\\(" c-string-limit-regexp "\\)")
+                     '((c-font-lock-invalid-string))))
+               `(("\\s|" 0 font-lock-warning-face t nil)))
+
+           ;; Invalid single quotes
+           c-font-lock-invalid-single-quotes
+
+           ;; Keyword constants
+           ,@(when (c-lang-const c-constant-kwds)
+               (let ((re (c-make-keywords-re nil (c-lang-const c-constant-kwds))))
+                 `((eval . (list ,(concat "\\<\\(" re "\\)\\>")
+                                 1 c-constant-face-name)))))
+
+           ;; Keywords except the primitive types.
+           ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp))
+              1 font-lock-keyword-face)
+
+           ;; Chained identifiers in using/namespace statements
+           ,`(,(c-make-font-lock-search-function
+                csharp-cc-mode--regex-using-or-namespace
+                `((csharp-cc-mode--color-forwards font-lock-variable-name-face)
+                  nil
+                  (goto-char (match-end 0)))))
+
+
+           ;; Negation character
+           (eval . (list "\\(!\\)[^=]" 1 c-negation-char-face-name))
+
+           ;; Types after 'new'
+           (eval . (list (concat "\\<new\\> *" csharp-cc-mode--regex-type-name-matcher)
+                         1 font-lock-type-face))
+
+           ;; Single identifier in attribute
+           (eval . (list (concat "\\[" csharp-cc-mode--regex-type-name-matcher "\\][^;]")
+                         1 font-lock-variable-name-face t))
+
+           ;; Function names
+           (eval . (list "\\([A-Za-z0-9_]+\\)\\(<[a-zA-Z0-9, ]+>\\)?("
+                         1 font-lock-function-name-face))
+
+           ;; Nameof
+           (eval . (list (concat "\\(\\<nameof\\>\\) *(")
+                         1 font-lock-function-name-face))
+
+           (eval . (list (concat "\\<nameof\\> *( *"
+                                 csharp-cc-mode--regex-identifier-matcher
+                                 " *) *")
+                         1 font-lock-variable-name-face))
+
+           ;; Catch statements with type only
+           (eval . (list (concat "\\<catch\\> *( *"
+                                 csharp-cc-mode--regex-type-name-matcher
+                                 " *) *")
+                         1 font-lock-type-face))
+           ))
+
+(c-lang-defconst c-basic-matchers-after
+  csharp (append
+          ;; Merge with cc-mode defaults - enables us to add more later
+          (c-lang-const c-basic-matchers-after)))
+
+(defcustom csharp-cc-mode-codedoc-tag-face 'c-doc-markup-face-name
+  "Face to be used on the codedoc docstring tags.
+
+Should be one of the font lock faces, such as
+`font-lock-variable-name-face' and friends.
+
+Needs to be set before `csharp-cc-mode' is loaded, because of
+compilation and evaluation time conflicts."
+  :type 'symbol)
+
+(defcustom csharp-cc-mode-font-lock-extra-types
+  (list csharp-cc-mode--regex-type-name)
+  (c-make-font-lock-extra-types-blurb "C#" "csharp-cc-mode" (concat))
+  :type 'c-extra-types-widget
+  :group 'c)
+
+(defconst csharp-cc-mode-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp)
+  "Minimal font locking for C# mode.")
+
+(defconst csharp-cc-mode-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp)
+  "Fast normal font locking for C# mode.")
+
+(defconst csharp-cc-mode-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp)
+  "Accurate normal font locking for C# mode.")
+
+(defvar csharp-cc-mode-font-lock-keywords csharp-cc-mode-font-lock-keywords-3
+  "Default expressions to highlight in C# mode.")
+
+(defun csharp-cc-mode-font-lock-keywords-2 ()
+  (c-compose-keywords-list csharp-cc-mode-font-lock-keywords-2))
+(defun csharp-cc-mode-font-lock-keywords-3 ()
+  (c-compose-keywords-list csharp-cc-mode-font-lock-keywords-3))
+(defun csharp-cc-mode-font-lock-keywords ()
+  (c-compose-keywords-list csharp-cc-mode-font-lock-keywords))
+
+;;; Doc comments
+
+(defconst codedoc-font-lock-doc-comments
+  ;; Most of this is taken from the javadoc example, however, we don't use the
+  ;; '@foo' syntax, so I removed that. Supports the XML tags only
+  `((,(concat "</?\\sw"                 ; XML tags.
+              "\\("
+              (concat "\\sw\\|\\s \\|[=\n\r*.:]\\|"
+                      "\"[^\"]*\"\\|'[^']*'")
+              "\\)*/?>")
+     0 ,csharp-cc-mode-codedoc-tag-face prepend nil)
+    ("&\\(\\sw\\|[.:]\\)+;"             ; XML entities.
+     0 ,csharp-cc-mode-codedoc-tag-face prepend nil)))
+
+(defconst codedoc-font-lock-keywords
+  `((,(lambda (limit)
+        (c-font-lock-doc-comments "///" limit
+          codedoc-font-lock-doc-comments)))))
+
+;;; End of doc comments
+
+;;; Adding syntax constructs
+
+(advice-add 'c-looking-at-inexpr-block
+            :around #'csharp-cc-mode-looking-at-inexpr-block)
+
+(defun csharp-cc-mode-looking-at-inexpr-block (orig-fun &rest args)
+  (let ((res (csharp-cc-mode-at-lambda-header)))
+    (if res
+        res
+      (apply orig-fun args))))
+
+(defun csharp-cc-mode-at-lambda-header ()
+  (save-excursion
+    (c-backward-syntactic-ws)
+    (unless (bobp)
+      (backward-char)
+      (c-safe (goto-char (scan-sexps (point) -1)))
+      (when (or (looking-at "([[:alnum:][:space:]_,]*)[ \t\n]*=>[ \t\n]*{")
+                (looking-at "[[:alnum:]_]+[ \t\n]*=>[ \t\n]*{"))
+        ;; If we are at a C# lambda header
+        (cons 'inexpr (point))))))
+
+(advice-add 'c-guess-basic-syntax
+            :around #'csharp-cc-mode-guess-basic-syntax)
+
+(defun csharp-cc-mode-guess-basic-syntax (orig-fun &rest args)
+  (cond
+   (;; Attributes
+    (save-excursion
+      (goto-char (c-point 'iopl))
+      (and
+       (eq (char-after) ?\[)
+       (save-excursion
+         (c-go-list-forward)
+         (and (eq (char-before) ?\])
+              (not (eq (char-after) ?\;))))))
+    `((annotation-top-cont ,(c-point 'iopl))))
+
+   ((and
+     ;; Heuristics to find object initializers
+     (save-excursion
+       ;; Next non-whitespace character should be '{'
+       (goto-char (c-point 'boi))
+       (eq (char-after) ?{))
+     (save-excursion
+       ;; 'new' should be part of the line
+       (goto-char (c-point 'iopl))
+       (looking-at ".*\\s *new\\s *.*"))
+     ;; Line should not already be terminated
+     (save-excursion
+       (goto-char (c-point 'eopl))
+       (or (not (eq (char-before) ?\;))
+           (not (eq (char-before) ?\{)))))
+    (if (save-excursion
+          ;; if we have a hanging brace on line before
+          (goto-char (c-point 'eopl))
+          (eq (char-before) ?\{))
+        `((brace-list-intro ,(c-point 'iopl)))
+      `((block-open) (statement ,(c-point 'iopl)))))
+   (t
+    (apply orig-fun args))))
+
+;;; End of new syntax constructs
+
+;;; Compilation support
+
+;; When invoked by MSBuild, csc’s errors look like this:
+;; subfolder\file.cs(6,18): error CS1006: Name of constructor must
+;; match name of class [c:\Users\user\project.csproj]
+
+(defun csharp-cc-mode--compilation-error-file-resolve ()
+  "Resolve an msbuild error to a (filename . dirname) cons cell."
+  ;; http://stackoverflow.com/a/18049590/429091
+  (cons (match-string 1) (file-name-directory (match-string 4))))
+
+(defconst csharp-cc-mode-compilation-re-msbuild-error
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): "
+   "error [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$")
+  "Regexp to match compilation error from msbuild.")
+
+(defconst csharp-cc-mode-compilation-re-msbuild-warning
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): "
+   "warning [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$")
+  "Regexp to match compilation warning from msbuild.")
+
+;; Notes on xbuild and devenv commonalities
+;;
+;; These regexes were tailored for xbuild, but apart from the concurrent
+;; build-marker ("1>") they share exactly the same match-markers.
+;;
+;; If we don't exclude the match-markers explicitly, these regexes
+;; will also be used to match for devenv as well, including the build-marker
+;; in the file-name, causing the lookup to fail.
+;;
+;; So if we don't want devenv to fail, we actually need to handle it in our
+;; xbuild-regexes, but then we automatically get devenv-support for free.
+
+(defconst csharp-cc-mode-compilation-re-xbuild-error
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?"
+   ;; handle weird devenv output format with 4 numbers, not 2 by having optional
+   ;; extra capture-groups.
+   "\\(?:,\\([0-9]+\\)\\)*): "
+   "error [[:alnum:]]+: .+$")
+  "Regexp to match compilation error from xbuild.")
+
+(defconst csharp-cc-mode-compilation-re-xbuild-warning
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?"
+   ;; handle weird devenv output format with 4 numbers, not 2 by having optional
+   ;; extra capture-groups.
+   "\\(?:,\\([0-9]+\\)\\)?*): "
+   "warning [[:alnum:]]+: .+$")
+  "Regexp to match compilation warning from xbuild.")
+
+(defconst csharp-cc-mode-compilation-re-dotnet-error
+  "\\([^\r\n]+\\) : error [A-Z]+[0-9]+:")
+
+(defconst csharp-cc-mode-compilation-re-dotnet-warning
+  "\\([^\r\n]+\\) : warning [A-Z]+[0-9]+:")
+
+(defconst csharp-cc-mode-compilation-re-dotnet-testfail
+  (concat
+   "[[:blank:]]+Stack Trace:\n"
+   "[[:blank:]]+at [^\n]+ in \\([^\n]+\\):line \\([0-9]+\\)"))
+
+(eval-after-load 'compile
+  (lambda ()
+    (dolist
+        (regexp
+         `((dotnet-testfail
+            ,csharp-cc-mode-compilation-re-dotnet-testfail
+            1 2)
+           (xbuild-error
+            ,csharp-cc-mode-compilation-re-xbuild-error
+            1 2 3 2)
+           (xbuild-warning
+            ,csharp-cc-mode-compilation-re-xbuild-warning
+            1 2 3 1)
+           (msbuild-error
+            ,csharp-cc-mode-compilation-re-msbuild-error
+            csharp-cc-mode--compilation-error-file-resolve
+            2
+            3
+            2
+            nil
+            (1 compilation-error-face)
+            (4 compilation-error-face))
+           (msbuild-warning
+            ,csharp-cc-mode-compilation-re-msbuild-warning
+            csharp-cc-mode--compilation-error-file-resolve
+            2
+            3
+            1
+            nil
+            (1 compilation-warning-face)
+            (4 compilation-warning-face))
+           (dotnet-error
+            ,csharp-cc-mode-compilation-re-dotnet-error
+            1)
+           (dotnet-warning
+            ,csharp-cc-mode-compilation-re-dotnet-warning
+            1 nil nil 1)))
+      (add-to-list 'compilation-error-regexp-alist-alist regexp)
+      (add-to-list 'compilation-error-regexp-alist (car regexp)))))
+
+(defvar csharp-cc-mode-mode-syntax-table
+  (funcall (c-lang-const c-make-mode-syntax-table csharp))
+  "Syntax table used in `csharp-cc-mode' buffers.")
+
+(defvar csharp-cc-mode-map
+  (let ((map (c-make-inherited-keymap)))
+    map)
+  "Keymap used in `csharp-cc-mode' buffers.")
+
+(easy-menu-define csharp-cc-mode-menu csharp-cc-mode-map "C# Mode Commands."
+  (cons "C#" (c-lang-const c-mode-menu csharp)))
+
+;;; Tree-sitter support
+
+(defcustom csharp-ts-mode-indent-offset 4
+  "Number of spaces for each indentation step in `csharp-ts-mode'."
+  :type 'integer
+  :safe 'integerp
+  :group 'csharp)
+
+(defvar csharp-ts-mode--indent-rules
+  `((c-sharp
+     ((parent-is "compilation_unit") parent-bol 0)
+     ((node-is "}") parent-bol 0)
+     ((node-is ")") parent-bol 0)
+     ((node-is "]") parent-bol 0)
+     ((parent-is "namespace_declaration") parent-bol 0)
+     ((parent-is "class_declaration") parent-bol 0)
+     ((parent-is "constructor_declaration") parent-bol 0)
+     ((parent-is "method_declaration") parent-bol 0)
+     ((parent-is "enum_declaration") parent-bol 0)
+     ((parent-is "operator_declaration") parent-bol 0)
+     ((parent-is "field_declaration") parent-bol 0)
+     ((parent-is "struct_declaration") parent-bol 0)
+     ((parent-is "declaration_list") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "argument_list") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "interpolation") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "binary_expression") parent 0)
+     ((parent-is "block") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "local_function_statement") parent-bol 0)
+     ((parent-is "if_statement") parent-bol 0)
+     ((parent-is "for_statement") parent-bol 0)
+     ((parent-is "for_each_statement") parent-bol 0)
+     ((parent-is "while_statement") parent-bol 0)
+     ((match "{" "switch_expression") parent-bol 0)
+     ((parent-is "switch_statement") parent-bol 0)
+     ((parent-is "switch_body") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "switch_section") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "switch_expression") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "case_statement") parent-bol 0)
+     ((parent-is "do_statement") parent-bol 0)
+     ((parent-is "equals_value_clause") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "ternary_expression") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "conditional_expression") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "statement_block") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "type_arguments") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "variable_declarator") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "arguments") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "array") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "formal_parameters") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "template_substitution") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "object_pattern") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "object") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "object_type") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "enum_body") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "arrow_function") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "parenthesized_expression") parent-bol csharp-ts-mode-indent-offset))))
+
+(defvar csharp-ts-mode--keywords
+  '("using" "namespace" "class" "if" "else" "throw" "new" "for"
+    "return" "await" "struct" "enum" "switch" "case"
+    "default" "typeof" "try" "catch" "finally" "break"
+    "foreach" "in" "yield" "get" "set" "when" "as" "out"
+    "is" "while" "continue" "this" "ref" "goto" "interface"
+    "from" "where" "select" "lock" "base" "record" "init"
+    "with" "let" "static" "var" "do" "public" "private"
+    "readonly" "unmanaged")
+  "C# keywords for tree-sitter font-locking.")
+
+(defvar csharp-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'c-sharp
+   :override t
+   :feature 'comment
+   '((comment)  @font-lock-comment-face)
+   :language 'c-sharp
+   :override t
+   :feature 'keyword
+   `([,@csharp-ts-mode--keywords] @font-lock-keyword-face
+     (modifier) @font-lock-keyword-face
+     (this_expression) @font-lock-keyword-face)
+   :language 'c-sharp
+   :override t
+   :feature 'attribute
+   `((attribute (identifier) @font-lock-property-face (attribute_argument_list))
+     (attribute (identifier) @font-lock-property-face))
+   :language 'c-sharp
+   :override t
+   :feature 'escape-sequence
+   '((escape_sequence) @font-lock-escape-face)
+   :language 'c-sharp
+   :override t
+   :feature 'literal
+   `((integer_literal) @font-lock-constant-face
+     (real_literal) @font-lock-constant-face
+     (null_literal) @font-lock-constant-face
+     (boolean_literal) @font-lock-constant-face)
+   :language 'c-sharp
+   :override t
+   :feature 'string
+   `([(string_literal)
+      (verbatim_string_literal)
+      (interpolated_string_text)
+      (interpolated_verbatim_string_text)
+      (character_literal)
+      "\""
+      "$\""
+      "@$\""
+      "$@\""] @font-lock-string-face)
+   :language 'c-sharp
+   :override t
+   :feature 'type
+   '((predefined_type) @font-lock-type-face
+     (implicit_type) @font-lock-type-face
+     (nullable_type) @font-lock-type-face
+     (type_parameter
+      (identifier) @font-lock-type-face)
+     (type_argument_list
+      (identifier) @font-lock-type-face)
+     (generic_name
+      (identifier) @font-lock-type-face)
+     (array_type
+      (identifier) @font-lock-type-face)
+     (cast_expression (identifier) @font-lock-type-face)
+     ["operator"] @font-lock-type-face
+     (type_parameter_constraints_clause
+      target: (identifier) @font-lock-type-face))
+   :language 'c-sharp
+   :feature 'definition
+   :override t
+   '((qualified_name (identifier) @font-lock-variable-name-face)
+     (using_directive (identifier) @font-lock-type-face)
+
+     (enum_declaration (identifier) @font-lock-type-face)
+     (enum_member_declaration (identifier) @font-lock-variable-name-face)
+
+     (interface_declaration (identifier) @font-lock-type-face)
+
+     (struct_declaration (identifier) @font-lock-type-face)
+
+     (record_declaration (identifier) @font-lock-type-face)
+     (namespace_declaration (identifier) @font-lock-type-face)
+     (base_list (identifier) @font-lock-type-face)
+     (property_declaration (generic_name))
+     (property_declaration
+      type: (nullable_type) @font-lock-type-face
+      name: (identifier) @font-lock-variable-name-face)
+     (property_declaration
+      type: (predefined_type) @font-lock-type-face
+      name: (identifier) @font-lock-variable-name-face)
+     (property_declaration
+      type: (identifier) @font-lock-type-face
+      name: (identifier) @font-lock-variable-name-face)
+     (class_declaration (identifier) @font-lock-type-face)
+
+     (constructor_declaration name: (_) @font-lock-type-face)
+
+     (method_declaration type: (_) @font-lock-type-face)
+     (method_declaration name: (_) @font-lock-function-name-face)
+
+     (variable_declaration (identifier) @font-lock-type-face)
+     (variable_declarator (identifier) @font-lock-variable-name-face)
+
+     (parameter type: (identifier) @font-lock-type-face)
+     (parameter name: (identifier) @font-lock-variable-name-face))
+   :language 'c-sharp
+   :feature 'expression
+   '((conditional_expression (identifier) @font-lock-variable-name-face)
+     (postfix_unary_expression (identifier)* @font-lock-variable-name-face)
+     (assignment_expression (identifier) @font-lock-variable-name-face))
+   :language 'c-sharp
+   :feature 'bracket
+   '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
+
+   :language 'c-sharp
+   :feature 'delimiter
+   '((["," ":" ";"]) @font-lock-delimiter-face)))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-cc-mode))
+
+(defun csharp-ts-mode--imenu-1 (node)
+  "Helper for `csharp-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (subtrees (mapcan #'csharp-ts-mode--imenu-1 (cdr node)))
+         (name (when ts-node
+                 (or (treesit-node-text
+                      (or (treesit-node-child-by-field-name
+                           ts-node "name"))
+                      t)
+                     "Unnamed node")))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((null ts-node) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+(defun csharp-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (class-tree (treesit-induce-sparse-tree
+                      node "^class_declaration$" nil 1000))
+         (interface-tree (treesit-induce-sparse-tree
+                          node "^interface_declaration$" nil 1000))
+         (enum-tree (treesit-induce-sparse-tree
+                     node "^enum_declaration$" nil 1000))
+         (struct-tree (treesit-induce-sparse-tree
+                       node "^struct_declaration$"  nil 1000))
+         (record-tree (treesit-induce-sparse-tree
+                       node "^record_declaration$"  nil 1000))
+         (method-tree (treesit-induce-sparse-tree
+                       node "^method_declaration$" nil 1000))
+         (class-index (csharp-ts-mode--imenu-1 class-tree))
+         (interface-index (csharp-ts-mode--imenu-1 interface-tree))
+         (enum-index (csharp-ts-mode--imenu-1 enum-tree))
+         (record-index (csharp-ts-mode--imenu-1 record-tree))
+         (struct-index (csharp-ts-mode--imenu-1 struct-tree))
+         (method-index (csharp-ts-mode--imenu-1 method-tree)))
+    (append
+     (when class-index `(("Class" . ,class-index)))
+     (when interface-index `(("Interface" . ,interface-index)))
+     (when enum-index `(("Enum" . ,enum-index)))
+     (when record-index `(("Record" . ,record-index)))
+     (when struct-index `(("Struct" . ,struct-index)))
+     (when method-index `(("Method" . ,method-index))))))
+
+;;;###autoload
+(define-derived-mode csharp-cc-mode prog-mode "C#"
+  "Major mode for editing Csharp code.
+Key bindings:
+\\{csharp-mode-map}"
+  :after-hook (c-update-modeline)
+  (c-initialize-cc-mode t)
+  (c-init-language-vars csharp-mode)
+  (c-common-init 'csharp-mode)
+  (setq-local c-doc-comment-style '((csharp-mode . codedoc)))
+  (run-mode-hooks 'c-mode-common-hook))
+
+;;;###autoload
+(define-derived-mode csharp-ts-mode prog-mode "C#"
+  "Major mode for editing C# code."
+
+  (unless (treesit-ready-p 'c-sharp)
+    (error "Tree-sitter for C# isn't available"))
+
+  ;; Tree-sitter.
+  (treesit-parser-create 'c-sharp)
+
+  ;; Comments.
+  (setq-local comment-start "// ")
+  (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
+  (setq-local comment-end "")
+
+  ;; Indent.
+  (setq-local treesit-simple-indent-rules csharp-ts-mode--indent-rules)
+
+  ;; Electric
+  (setq-local electric-indent-chars
+              (append "{}():;," electric-indent-chars))
+
+  ;; Navigation.
+  (setq-local treesit-defun-type-regexp "declaration")
+
+  ;; Font-lock.
+  (setq-local treesit-font-lock-settings csharp-ts-mode--font-lock-settings)
+  (setq-local treesit-font-lock-feature-list
+              '((comment keyword constant string)
+                (type definition expression literal attribute)
+                (bracket delimiter)))
+
+  ;; Imenu.
+  (setq-local imenu-create-index-function #'csharp-ts-mode--imenu)
+  (setq-local which-func-functions nil) ;; Piggyback on imenu
+  (treesit-major-mode-setup))
+
+(provide 'csharp-mode)
+
+;;; csharp-mode.el ends here
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-22 20:52 bug#59490: 29.0.50; Add C# support Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-22 21:25 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
       [not found] ` <handler.59490.B.166915036216965.ack@debbugs.gnu.org>
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 12+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-22 21:25 UTC (permalink / raw)
  To: 59490


Hmm, It seems I've made a mistake in the C# CC mode variant.  Just wait
a little, and let me find the problem :-)

Theo





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
       [not found] ` <handler.59490.B.166915036216965.ack@debbugs.gnu.org>
@ 2022-11-22 21:47   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-23 12:16     ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-22 21:47 UTC (permalink / raw)
  To: 59490

[-- Attachment #1: Type: text/plain, Size: 67 bytes --]


Ok so this works.

Sorry for the mess.

What do you think?

Theo


[-- Attachment #2: 0001-Add-csharp-mode-and-csharp-ts-mode.patch --]
[-- Type: text/x-diff, Size: 36488 bytes --]

From 07ff9e24d55cafad735eb4aa7cba0c772b295c25 Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Tue, 22 Nov 2022 21:48:21 +0100
Subject: [PATCH] Add csharp-mode and csharp-ts-mode

* etc/NEWS: Mention new modes.
* lisp/progmodes/csharp-mode.el (csharp-mode, csharp-ts-mode): New
major modes.
---
 etc/NEWS                      |   8 +
 lisp/progmodes/csharp-mode.el | 964 ++++++++++++++++++++++++++++++++++
 2 files changed, 972 insertions(+)
 create mode 100644 lisp/progmodes/csharp-mode.el

diff --git a/etc/NEWS b/etc/NEWS
index 5a65896d69..4024c5cac3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2990,6 +2990,14 @@ A major mode based on the tree-sitter library for editing programs
 in the JSON language.  It includes support for font-locking,
 indentation, Imenu, which-func, and navigation.
 
+** New mode 'csharp-ts-mode'.
+A major mode based on the tree-sitter library for editing programs
+in the C# language.  It includes support for font-locking,
+indentation, Imenu, which-func, and navigation.
+
+** New mode 'csharp-mode'.
+A major mode based on CC Mode for editing programs in the C# language.
+
 \f
 * Incompatible Lisp Changes in Emacs 29.1
 
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
new file mode 100644
index 0000000000..f8fe5bed20
--- /dev/null
+++ b/lisp/progmodes/csharp-mode.el
@@ -0,0 +1,964 @@
+;;; csharp-mode.el --- Support for editing C#  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022  Free Software Foundation, Inc.
+
+;; Author     : Theodor Thornhill <theo@thornhill.no>
+;; Maintainer : Theodor Thornhill <theo@thornhill.no>
+;; Created    : September 2022
+;; Keywords   : c# languages oop
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'compile)
+(require 'cc-mode)
+(require 'cc-langs)
+
+(eval-when-compile
+  (require 'cc-fonts))
+
+(defgroup csharp nil
+  "Major mode for editing C# code."
+  :group 'prog-mode)
+
+(eval-and-compile
+  (defconst csharp--regex-identifier
+    "[A-Za-z][A-Za-z0-9_]*"
+    "Regex describing an dentifier in C#.")
+
+  (defconst csharp--regex-identifier-matcher
+    (concat "\\(" csharp--regex-identifier "\\)")
+    "Regex matching an identifier in C#.")
+
+  (defconst csharp--regex-type-name
+    "[A-Z][A-Za-z0-9_]*"
+    "Regex describing a type identifier in C#.")
+
+  (defconst csharp--regex-type-name-matcher
+    (concat "\\(" csharp--regex-type-name "\\)")
+    "Regex matching a type identifier in C#.")
+
+  (defconst csharp--regex-using-or-namespace
+    (concat "^using" "\\|" "namespace"
+            "\\s *"
+            csharp--regex-type-name-matcher)
+    "Regex matching identifiers after a using or namespace
+    declaration."))
+
+(eval-and-compile
+  (c-add-language 'csharp-mode 'java-mode)
+
+  (defun csharp--make-mode-syntax-table ()
+    (let ((table (make-syntax-table)))
+      (c-populate-syntax-table table)
+      (modify-syntax-entry ?@ "_" table)
+      table))
+  (defvar csharp--make-mode-syntax-table #'csharp--make-mode-syntax-table
+    "Workaround for Emacs bug#57065."))
+
+(c-lang-defconst c-make-mode-syntax-table
+  csharp #'csharp--make-mode-syntax-table)
+
+(c-lang-defconst c-identifier-syntax-modifications
+  csharp (append '((?@ . "w"))
+                 (c-lang-const c-identifier-syntax-modifications)))
+
+(c-lang-defconst c-symbol-start
+  csharp (concat "[" c-alpha "_@]"))
+
+(c-lang-defconst c-opt-type-suffix-key
+  csharp (concat "\\(\\[" (c-lang-const c-simple-ws) "*\\]\\|\\?\\)"))
+
+(c-lang-defconst c-identifier-ops
+  csharp '((left-assoc ".")))
+
+(c-lang-defconst c-overloadable-operators
+  csharp '("+" "-" "*" "/" "%" "&" "|" "^" "<<" ">>" "=="
+           "!=" ">" "<" ">=" "<="))
+
+(c-lang-defconst c-multiline-string-start-char
+  csharp ?@)
+
+(c-lang-defconst c-ml-string-opener-re
+  ;; "\\(\\(?:@\\$?\\)\\(\"\\)\\)"
+  csharp
+  (rx
+   (group
+    (or "@" "@$")
+    (group "\""))))
+
+(c-lang-defconst c-ml-string-max-opener-len
+  csharp 3)
+
+(c-lang-defconst c-ml-string-max-closer-len
+  csharp 2)
+
+(c-lang-defconst c-ml-string-any-closer-re
+  ;; "\\(?:\"\"\\)*\\(\\(\"\\)\\)\\(?:[^\"]\\|\\'\\)"
+  csharp
+  (rx
+   (seq
+    (zero-or-more "\"\"")
+    (group
+     (group "\""))
+    (or (not (any "\"")) eos))))
+
+(c-lang-defconst c-ml-string-back-closer-re
+  ;; "\\(?:\\`\\|[^\"]\\)\"*"
+  csharp
+  (rx
+   (seq
+    (or bos
+        (not (any "\"")))
+    (zero-or-more "\""))))
+
+(c-lang-defconst c-type-prefix-kwds
+  csharp '("class" "interface" "struct"))
+
+(c-lang-defconst c-class-decl-kwds
+  csharp '("class" "interface" "struct"))
+
+;;; Keyword lists
+
+(c-lang-defconst c-primitive-type-kwds
+  csharp '("bool" "byte" "sbyte" "char" "decimal" "double" "float" "int" "uint"
+           "long" "ulong" "short" "ushort" "void" "object" "string" "var"))
+
+(c-lang-defconst c-other-decl-kwds
+  csharp nil)
+
+(c-lang-defconst c-type-list-kwds
+  csharp nil)
+
+(c-lang-defconst c-other-block-decl-kwds
+  csharp nil)
+
+(c-lang-defconst c-return-kwds
+  csharp '("return"))
+
+(c-lang-defconst c-typedef-kwds
+  csharp nil)
+
+(c-lang-defconst c-typeof-kwds
+  csharp '("typeof" "is" "as"))
+
+(c-lang-defconst c-type-modifier-prefix-kwds
+  csharp '("volatile"))
+
+(c-lang-defconst c-type-modifier-kwds
+  csharp '("readonly" "new"))
+
+(c-lang-defconst c-brace-list-decl-kwds
+  csharp '("enum" "new"))
+
+(c-lang-defconst c-recognize-post-brace-list-type-p
+  csharp t)
+
+(c-lang-defconst c-ref-list-kwds
+  csharp nil)
+
+(c-lang-defconst c-using-kwds
+  csharp '("using"))
+
+(c-lang-defconst c-equals-type-clause-kwds
+  csharp '("using"))
+
+(defun csharp-at-vsemi-p (&optional pos)
+  (if pos (goto-char pos))
+  (save-excursion
+    (beginning-of-line)
+    (c-forward-syntactic-ws)
+    (looking-at "using\\s *(")))
+
+(c-lang-defconst c-at-vsemi-p-fn
+  csharp 'csharp-at-vsemi-p)
+
+(defun csharp-vsemi-status-unknown () t)
+
+(c-lang-defconst c-vsemi-status-unknown-p-fn
+  csharp 'csharp-vsemi-status-unknown-p)
+
+
+(c-lang-defconst c-modifier-kwds
+  csharp '("abstract" "default" "final" "native" "private" "protected"
+           "public" "partial" "internal" "readonly" "static" "event" "transient"
+           "volatile" "sealed" "ref" "out" "virtual" "implicit" "explicit"
+           "fixed" "override" "params" "async" "await" "extern" "unsafe"
+           "get" "set" "this" "const" "delegate"))
+
+(c-lang-defconst c-other-kwds
+  csharp '("select" "from" "where" "join" "in" "on" "equals" "into"
+           "orderby" "ascending" "descending" "group" "when"
+           "let" "by" "namespace"))
+
+(c-lang-defconst c-colon-type-list-kwds
+  csharp '("class" "struct" "interface"))
+
+(c-lang-defconst c-block-stmt-1-kwds
+  csharp '("do" "else" "finally" "try"))
+
+(c-lang-defconst c-block-stmt-1-2-kwds
+  csharp '("try"))
+
+(c-lang-defconst c-block-stmt-2-kwds
+  csharp '("for" "if" "switch" "while" "catch" "foreach" "fixed" "checked"
+           "unchecked" "using" "lock"))
+
+(c-lang-defconst c-simple-stmt-kwds
+  csharp '("break" "continue" "goto" "throw" "return" "yield"))
+
+(c-lang-defconst c-constant-kwds
+  csharp  '("true" "false" "null" "value"))
+
+(c-lang-defconst c-primary-expr-kwds
+  csharp '("this" "base" "operator"))
+
+(c-lang-defconst c-inexpr-class-kwds
+  csharp nil)
+
+(c-lang-defconst c-class-decl-kwds
+  csharp '("class" "struct" "interface"))
+
+(c-lang-defconst c-std-abbrev-keywords
+  csharp (append (c-lang-const c-std-abbrev-keywords) '("catch" "finally")))
+
+(c-lang-defconst c-decl-prefix-re
+  csharp "\\([{}(;,<]+\\)")
+
+(c-lang-defconst c-recognize-typeless-decls
+  csharp t)
+
+(c-lang-defconst c-recognize-<>-arglists
+  csharp t)
+
+(c-lang-defconst c-opt-cpp-prefix
+  csharp "\\s *#\\s *")
+
+(c-lang-defconst c-opt-cpp-macro-define
+  csharp (if (c-lang-const c-opt-cpp-prefix)
+             "define"))
+
+(c-lang-defconst c-cpp-message-directives
+  csharp '("error" "warning" "region"))
+
+(c-lang-defconst c-cpp-expr-directives
+  csharp '("if" "elif"))
+
+(c-lang-defconst c-other-op-syntax-tokens
+  csharp  (append '("#")
+                  (c-lang-const c-other-op-syntax-tokens)))
+
+(c-lang-defconst c-line-comment-starter
+  csharp "//")
+
+(c-lang-defconst c-doc-comment-start-regexp
+  csharp "///")
+
+(c-add-style "csharp"
+             '("java"
+               (c-basic-offset . 4)
+               (c-comment-only-line-offset . (0 . 0))
+               (c-offsets-alist . ((inline-open           . 0)
+                                   (arglist-intro         . +)
+                                   (arglist-close         . 0)
+                                   (inexpr-class          . 0)
+                                   (case-label            . +)
+                                   (cpp-macro             . c-lineup-dont-change)
+                                   (substatement-open     . 0)))))
+
+(eval-and-compile
+  (unless (or (stringp c-default-style)
+              (assoc 'csharp-mode c-default-style))
+    (setq c-default-style
+          (cons '(csharp-mode . "csharp")
+                c-default-style))))
+
+(defun csharp--color-forwards (font-lock-face)
+  (let (id-beginning)
+    (goto-char (match-beginning 0))
+    (forward-word)
+    (while (and (not (or (eq (char-after) ?\;)
+                         (eq (char-after) ?\{)))
+                (progn
+                  (forward-char)
+                  (c-forward-syntactic-ws)
+                  (setq id-beginning (point))
+                  (> (skip-chars-forward
+                      (c-lang-const c-symbol-chars))
+                     0))
+                (not (get-text-property (point) 'face)))
+      (c-put-font-lock-face id-beginning (point) font-lock-face)
+      (c-forward-syntactic-ws))))
+
+(c-lang-defconst c-basic-matchers-before
+  csharp `(
+           ;; Warning face on unclosed strings
+           ,@(if (version< emacs-version "27.0")
+                 ;; Taken from 26.1 branch
+                 `(,(c-make-font-lock-search-function
+                     (concat ".\\(" c-string-limit-regexp "\\)")
+                     '((c-font-lock-invalid-string))))
+               `(("\\s|" 0 font-lock-warning-face t nil)))
+
+           ;; Invalid single quotes
+           c-font-lock-invalid-single-quotes
+
+           ;; Keyword constants
+           ,@(when (c-lang-const c-constant-kwds)
+               (let ((re (c-make-keywords-re nil (c-lang-const c-constant-kwds))))
+                 `((eval . (list ,(concat "\\<\\(" re "\\)\\>")
+                                 1 c-constant-face-name)))))
+
+           ;; Keywords except the primitive types.
+           ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp))
+              1 font-lock-keyword-face)
+
+           ;; Chained identifiers in using/namespace statements
+           ,`(,(c-make-font-lock-search-function
+                csharp--regex-using-or-namespace
+                `((csharp--color-forwards font-lock-variable-name-face)
+                  nil
+                  (goto-char (match-end 0)))))
+
+
+           ;; Negation character
+           (eval . (list "\\(!\\)[^=]" 1 c-negation-char-face-name))
+
+           ;; Types after 'new'
+           (eval . (list (concat "\\<new\\> *" csharp--regex-type-name-matcher)
+                         1 font-lock-type-face))
+
+           ;; Single identifier in attribute
+           (eval . (list (concat "\\[" csharp--regex-type-name-matcher "\\][^;]")
+                         1 font-lock-variable-name-face t))
+
+           ;; Function names
+           (eval . (list "\\([A-Za-z0-9_]+\\)\\(<[a-zA-Z0-9, ]+>\\)?("
+                         1 font-lock-function-name-face))
+
+           ;; Nameof
+           (eval . (list (concat "\\(\\<nameof\\>\\) *(")
+                         1 font-lock-function-name-face))
+
+           (eval . (list (concat "\\<nameof\\> *( *"
+                                 csharp--regex-identifier-matcher
+                                 " *) *")
+                         1 font-lock-variable-name-face))
+
+           ;; Catch statements with type only
+           (eval . (list (concat "\\<catch\\> *( *"
+                                 csharp--regex-type-name-matcher
+                                 " *) *")
+                         1 font-lock-type-face))
+           ))
+
+(c-lang-defconst c-basic-matchers-after
+  csharp (append
+          ;; Merge with cc-mode defaults - enables us to add more later
+          (c-lang-const c-basic-matchers-after)))
+
+(defcustom csharp-codedoc-tag-face 'c-doc-markup-face-name
+  "Face to be used on the codedoc docstring tags.
+
+Should be one of the font lock faces, such as
+`font-lock-variable-name-face' and friends.
+
+Needs to be set before `csharp-mode' is loaded, because of
+compilation and evaluation time conflicts."
+  :type 'symbol)
+
+(defcustom csharp-font-lock-extra-types
+  (list csharp--regex-type-name)
+  (c-make-font-lock-extra-types-blurb "C#" "csharp-mode" (concat))
+  :type 'c-extra-types-widget
+  :group 'c)
+
+(defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp)
+  "Minimal font locking for C# mode.")
+
+(defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp)
+  "Fast normal font locking for C# mode.")
+
+(defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp)
+  "Accurate normal font locking for C# mode.")
+
+(defvar csharp-font-lock-keywords csharp-font-lock-keywords-3
+  "Default expressions to highlight in C# mode.")
+
+(defun csharp-font-lock-keywords-2 ()
+  (c-compose-keywords-list csharp-font-lock-keywords-2))
+(defun csharp-font-lock-keywords-3 ()
+  (c-compose-keywords-list csharp-font-lock-keywords-3))
+(defun csharp-font-lock-keywords ()
+  (c-compose-keywords-list csharp-font-lock-keywords))
+
+;;; Doc comments
+
+(defconst codedoc-font-lock-doc-comments
+  ;; Most of this is taken from the javadoc example, however, we don't use the
+  ;; '@foo' syntax, so I removed that. Supports the XML tags only
+  `((,(concat "</?\\sw"         ; XML tags.
+              "\\("
+              (concat "\\sw\\|\\s \\|[=\n\r*.:]\\|"
+                      "\"[^\"]*\"\\|'[^']*'")
+              "\\)*/?>")
+     0 ,csharp-codedoc-tag-face prepend nil)
+    ;; ("\\([a-zA-Z0-9_]+\\)=" 0 font-lock-variable-name-face prepend nil)
+    ;; ("\".*\"" 0 font-lock-string-face prepend nil)
+    ("&\\(\\sw\\|[.:]\\)+;"     ; XML entities.
+     0 ,csharp-codedoc-tag-face prepend nil)))
+
+(defconst codedoc-font-lock-keywords
+  `((,(lambda (limit)
+        (c-font-lock-doc-comments "///" limit
+          codedoc-font-lock-doc-comments)))))
+
+;;; End of doc comments
+
+;;; Adding syntax constructs
+
+(advice-add 'c-looking-at-inexpr-block
+            :around #'csharp-looking-at-inexpr-block)
+
+(defun csharp-looking-at-inexpr-block (orig-fun &rest args)
+  (let ((res (csharp-at-lambda-header)))
+    (if res
+        res
+      (apply orig-fun args))))
+
+(defun csharp-at-lambda-header ()
+  (save-excursion
+    (c-backward-syntactic-ws)
+    (unless (bobp)
+      (backward-char)
+      (c-safe (goto-char (scan-sexps (point) -1)))
+      (when (or (looking-at "([[:alnum:][:space:]_,]*)[ \t\n]*=>[ \t\n]*{")
+                (looking-at "[[:alnum:]_]+[ \t\n]*=>[ \t\n]*{"))
+        ;; If we are at a C# lambda header
+        (cons 'inexpr (point))))))
+
+(advice-add 'c-guess-basic-syntax
+            :around #'csharp-guess-basic-syntax)
+
+(defun csharp-guess-basic-syntax (orig-fun &rest args)
+  (cond
+   (;; Attributes
+    (save-excursion
+      (goto-char (c-point 'iopl))
+      (and
+       (eq (char-after) ?\[)
+       (save-excursion
+         (c-go-list-forward)
+         (and (eq (char-before) ?\])
+              (not (eq (char-after) ?\;))))))
+    `((annotation-top-cont ,(c-point 'iopl))))
+
+   ((and
+     ;; Heuristics to find object initializers
+     (save-excursion
+       ;; Next non-whitespace character should be '{'
+       (goto-char (c-point 'boi))
+       (eq (char-after) ?{))
+     (save-excursion
+       ;; 'new' should be part of the line
+       (goto-char (c-point 'iopl))
+       (looking-at ".*\\s *new\\s *.*"))
+     ;; Line should not already be terminated
+     (save-excursion
+       (goto-char (c-point 'eopl))
+       (or (not (eq (char-before) ?\;))
+           (not (eq (char-before) ?\{)))))
+    (if (save-excursion
+          ;; if we have a hanging brace on line before
+          (goto-char (c-point 'eopl))
+          (eq (char-before) ?\{))
+        `((brace-list-intro ,(c-point 'iopl)))
+      `((block-open) (statement ,(c-point 'iopl)))))
+   (t
+    (apply orig-fun args))))
+
+;;; End of new syntax constructs
+
+
+
+;;; Fix for strings on version 27.1
+
+(when (version= emacs-version "27.1")
+  ;; See:
+  ;; https://github.com/emacs-csharp/csharp-mode/issues/175
+  ;; https://github.com/emacs-csharp/csharp-mode/issues/151
+  ;; for the full story.
+  (defun c-pps-to-string-delim (end)
+    (let* ((start (point))
+           (no-st-s `(0 nil nil ?\" nil nil 0 nil ,start nil nil))
+           (st-s `(0 nil nil t nil nil 0 nil ,start nil nil))
+           no-st-pos st-pos
+           )
+      (parse-partial-sexp start end nil nil no-st-s 'syntax-table)
+      (setq no-st-pos (point))
+      (goto-char start)
+      (while (progn
+               (parse-partial-sexp (point) end nil nil st-s 'syntax-table)
+               (unless (bobp)
+                 (c-clear-syn-tab (1- (point))))
+               (setq st-pos (point))
+               (and (< (point) end)
+                    (not (eq (char-before) ?\")))))
+      (goto-char (min no-st-pos st-pos))
+      nil))
+
+  (defun c-multiline-string-check-final-quote ()
+    (let (pos-ll pos-lt)
+      (save-excursion
+        (goto-char (point-max))
+        (skip-chars-backward "^\"")
+        (while
+            (and
+             (not (bobp))
+             (cond
+              ((progn
+                 (setq pos-ll (c-literal-limits)
+                       pos-lt (c-literal-type pos-ll))
+                 (memq pos-lt '(c c++)))
+               ;; In a comment.
+               (goto-char (car pos-ll)))
+              ((save-excursion
+                 (backward-char)        ; over "
+                 (c-is-escaped (point)))
+               ;; At an escaped string.
+               (backward-char)
+               t)
+              (t
+               ;; At a significant "
+               (c-clear-syn-tab (1- (point)))
+               (setq pos-ll (c-literal-limits)
+                     pos-lt (c-literal-type pos-ll))
+               nil)))
+          (skip-chars-backward "^\""))
+        (cond
+         ((bobp))
+         ((eq pos-lt 'string)
+          (c-put-syn-tab (1- (point)) '(15)))
+         (t nil))))))
+
+;;; End of fix for strings on version 27.1
+
+;; When invoked by MSBuild, csc’s errors look like this:
+;; subfolder\file.cs(6,18): error CS1006: Name of constructor must
+;; match name of class [c:\Users\user\project.csproj]
+
+(defun csharp--compilation-error-file-resolve ()
+  "Resolve an msbuild error to a (filename . dirname) cons cell."
+  ;; http://stackoverflow.com/a/18049590/429091
+  (cons (match-string 1) (file-name-directory (match-string 4))))
+
+(defconst csharp-compilation-re-msbuild-error
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): "
+   "error [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$")
+  "Regexp to match compilation error from msbuild.")
+
+(defconst csharp-compilation-re-msbuild-warning
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): "
+   "warning [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$")
+  "Regexp to match compilation warning from msbuild.")
+
+;; Notes on xbuild and devenv commonalities
+;;
+;; These regexes were tailored for xbuild, but apart from the concurrent
+;; build-marker ("1>") they share exactly the same match-markers.
+;;
+;; If we don't exclude the match-markers explicitly, these regexes
+;; will also be used to match for devenv as well, including the build-marker
+;; in the file-name, causing the lookup to fail.
+;;
+;; So if we don't want devenv to fail, we actually need to handle it in our
+;; xbuild-regexes, but then we automatically get devenv-support for free.
+
+(defconst csharp-compilation-re-xbuild-error
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?"
+   ;; handle weird devenv output format with 4 numbers, not 2 by having optional
+   ;; extra capture-groups.
+   "\\(?:,\\([0-9]+\\)\\)*): "
+   "error [[:alnum:]]+: .+$")
+  "Regexp to match compilation error from xbuild.")
+
+(defconst csharp-compilation-re-xbuild-warning
+  (concat
+   "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
+   "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?"
+   ;; handle weird devenv output format with 4 numbers, not 2 by having optional
+   ;; extra capture-groups.
+   "\\(?:,\\([0-9]+\\)\\)?*): "
+   "warning [[:alnum:]]+: .+$")
+  "Regexp to match compilation warning from xbuild.")
+
+(defconst csharp-compilation-re-dotnet-error
+  "\\([^\r\n]+\\) : error [A-Z]+[0-9]+:")
+
+(defconst csharp-compilation-re-dotnet-warning
+  "\\([^\r\n]+\\) : warning [A-Z]+[0-9]+:")
+
+(defconst csharp-compilation-re-dotnet-testfail
+  (concat
+   "[[:blank:]]+Stack Trace:\n"
+   "[[:blank:]]+at [^\n]+ in \\([^\n]+\\):line \\([0-9]+\\)"))
+
+
+(eval-after-load 'compile
+  (lambda ()
+    (dolist
+        (regexp
+         `((dotnet-testfail
+            ,csharp-compilation-re-dotnet-testfail
+            1 2)
+           (xbuild-error
+            ,csharp-compilation-re-xbuild-error
+            1 2 3 2)
+           (xbuild-warning
+            ,csharp-compilation-re-xbuild-warning
+            1 2 3 1)
+           (msbuild-error
+            ,csharp-compilation-re-msbuild-error
+            csharp--compilation-error-file-resolve
+            2
+            3
+            2
+            nil
+            (1 compilation-error-face)
+            (4 compilation-error-face))
+           (msbuild-warning
+            ,csharp-compilation-re-msbuild-warning
+            csharp--compilation-error-file-resolve
+            2
+            3
+            1
+            nil
+            (1 compilation-warning-face)
+            (4 compilation-warning-face))
+           (dotnet-error
+            ,csharp-compilation-re-dotnet-error
+            1)
+           (dotnet-warning
+            ,csharp-compilation-re-dotnet-warning
+            1 nil nil 1)))
+      (add-to-list 'compilation-error-regexp-alist-alist regexp)
+      (add-to-list 'compilation-error-regexp-alist (car regexp)))))
+
+(defvar csharp-mode-syntax-table
+  (funcall (c-lang-const c-make-mode-syntax-table csharp))
+  "Syntax table used in `csharp-mode' buffers.")
+
+(defvar csharp-mode-map
+  (let ((map (c-make-inherited-keymap)))
+    map)
+  "Keymap used in `csharp-mode' buffers.")
+
+(easy-menu-define csharp-mode-menu csharp-mode-map "C# Mode Commands."
+  (cons "C#" (c-lang-const c-mode-menu csharp)))
+
+;;; Tree-sitter support
+
+(defcustom csharp-ts-mode-indent-offset 4
+  "Number of spaces for each indentation step in `csharp-ts-mode'."
+  :type 'integer
+  :safe 'integerp
+  :group 'csharp)
+
+(defvar csharp-ts-mode--indent-rules
+  `((c-sharp
+     ((parent-is "compilation_unit") parent-bol 0)
+     ((node-is "}") parent-bol 0)
+     ((node-is ")") parent-bol 0)
+     ((node-is "]") parent-bol 0)
+     ((parent-is "namespace_declaration") parent-bol 0)
+     ((parent-is "class_declaration") parent-bol 0)
+     ((parent-is "constructor_declaration") parent-bol 0)
+     ((parent-is "method_declaration") parent-bol 0)
+     ((parent-is "enum_declaration") parent-bol 0)
+     ((parent-is "operator_declaration") parent-bol 0)
+     ((parent-is "field_declaration") parent-bol 0)
+     ((parent-is "struct_declaration") parent-bol 0)
+     ((parent-is "declaration_list") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "argument_list") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "interpolation") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "binary_expression") parent 0)
+     ((parent-is "block") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "local_function_statement") parent-bol 0)
+     ((parent-is "if_statement") parent-bol 0)
+     ((parent-is "for_statement") parent-bol 0)
+     ((parent-is "for_each_statement") parent-bol 0)
+     ((parent-is "while_statement") parent-bol 0)
+     ((match "{" "switch_expression") parent-bol 0)
+     ((parent-is "switch_statement") parent-bol 0)
+     ((parent-is "switch_body") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "switch_section") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "switch_expression") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "case_statement") parent-bol 0)
+     ((parent-is "do_statement") parent-bol 0)
+     ((parent-is "equals_value_clause") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "ternary_expression") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "conditional_expression") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "statement_block") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "type_arguments") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "variable_declarator") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "arguments") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "array") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "formal_parameters") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "template_substitution") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "object_pattern") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "object") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "object_type") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "enum_body") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "arrow_function") parent-bol csharp-ts-mode-indent-offset)
+     ((parent-is "parenthesized_expression") parent-bol csharp-ts-mode-indent-offset))))
+
+(defvar csharp-ts-mode--keywords
+  '("using" "namespace" "class" "if" "else" "throw" "new" "for"
+    "return" "await" "struct" "enum" "switch" "case"
+    "default" "typeof" "try" "catch" "finally" "break"
+    "foreach" "in" "yield" "get" "set" "when" "as" "out"
+    "is" "while" "continue" "this" "ref" "goto" "interface"
+    "from" "where" "select" "lock" "base" "record" "init"
+    "with" "let" "static" "var" "do" "public" "private"
+    "readonly" "unmanaged")
+  "C# keywords for tree-sitter font-locking.")
+
+(defvar csharp-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'c-sharp
+   :override t
+   :feature 'comment
+   '((comment)  @font-lock-comment-face)
+   :language 'c-sharp
+   :override t
+   :feature 'keyword
+   `([,@csharp-ts-mode--keywords] @font-lock-keyword-face
+     (modifier) @font-lock-keyword-face
+     (this_expression) @font-lock-keyword-face)
+   :language 'c-sharp
+   :override t
+   :feature 'attribute
+   `((attribute (identifier) @font-lock-property-face (attribute_argument_list))
+     (attribute (identifier) @font-lock-property-face))
+   :language 'c-sharp
+   :override t
+   :feature 'escape-sequence
+   '((escape_sequence) @font-lock-escape-face)
+   :language 'c-sharp
+   :override t
+   :feature 'literal
+   `((integer_literal) @font-lock-constant-face
+     (real_literal) @font-lock-constant-face
+     (null_literal) @font-lock-constant-face
+     (boolean_literal) @font-lock-constant-face)
+   :language 'c-sharp
+   :override t
+   :feature 'string
+   `([(string_literal)
+      (verbatim_string_literal)
+      (interpolated_string_text)
+      (interpolated_verbatim_string_text)
+      (character_literal)
+      "\""
+      "$\""
+      "@$\""
+      "$@\""] @font-lock-string-face)
+   :language 'c-sharp
+   :override t
+   :feature 'type
+   '((predefined_type) @font-lock-type-face
+     (implicit_type) @font-lock-type-face
+     (nullable_type) @font-lock-type-face
+     (type_parameter
+      (identifier) @font-lock-type-face)
+     (type_argument_list
+      (identifier) @font-lock-type-face)
+     (generic_name
+      (identifier) @font-lock-type-face)
+     (array_type
+      (identifier) @font-lock-type-face)
+     (cast_expression (identifier) @font-lock-type-face)
+     ["operator"] @font-lock-type-face
+     (type_parameter_constraints_clause
+      target: (identifier) @font-lock-type-face))
+   :language 'c-sharp
+   :feature 'definition
+   :override t
+   '((qualified_name (identifier) @font-lock-variable-name-face)
+     (using_directive (identifier) @font-lock-type-face)
+
+     (enum_declaration (identifier) @font-lock-type-face)
+     (enum_member_declaration (identifier) @font-lock-variable-name-face)
+
+     (interface_declaration (identifier) @font-lock-type-face)
+
+     (struct_declaration (identifier) @font-lock-type-face)
+
+     (record_declaration (identifier) @font-lock-type-face)
+     (namespace_declaration (identifier) @font-lock-type-face)
+     (base_list (identifier) @font-lock-type-face)
+     (property_declaration (generic_name))
+     (property_declaration
+      type: (nullable_type) @font-lock-type-face
+      name: (identifier) @font-lock-variable-name-face)
+     (property_declaration
+      type: (predefined_type) @font-lock-type-face
+      name: (identifier) @font-lock-variable-name-face)
+     (property_declaration
+      type: (identifier) @font-lock-type-face
+      name: (identifier) @font-lock-variable-name-face)
+     (class_declaration (identifier) @font-lock-type-face)
+
+     (constructor_declaration name: (_) @font-lock-type-face)
+
+     (method_declaration type: (_) @font-lock-type-face)
+     (method_declaration name: (_) @font-lock-function-name-face)
+
+     (variable_declaration (identifier) @font-lock-type-face)
+     (variable_declarator (identifier) @font-lock-variable-name-face)
+
+     (parameter type: (identifier) @font-lock-type-face)
+     (parameter name: (identifier) @font-lock-variable-name-face))
+   :language 'c-sharp
+   :feature 'expression
+   '((conditional_expression (identifier) @font-lock-variable-name-face)
+     (postfix_unary_expression (identifier)* @font-lock-variable-name-face)
+     (assignment_expression (identifier) @font-lock-variable-name-face))
+   :language 'c-sharp
+   :feature 'bracket
+   '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
+
+   :language 'c-sharp
+   :feature 'delimiter
+   '((["," ":" ";"]) @font-lock-delimiter-face)))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-cc-mode))
+
+(defun csharp-ts-mode--imenu-1 (node)
+  "Helper for `csharp-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (subtrees (mapcan #'csharp-ts-mode--imenu-1 (cdr node)))
+         (name (when ts-node
+                 (or (treesit-node-text
+                      (or (treesit-node-child-by-field-name
+                           ts-node "name"))
+                      t)
+                     "Unnamed node")))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((null ts-node) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+(defun csharp-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (class-tree (treesit-induce-sparse-tree
+                      node "^class_declaration$" nil 1000))
+         (interface-tree (treesit-induce-sparse-tree
+                          node "^interface_declaration$" nil 1000))
+         (enum-tree (treesit-induce-sparse-tree
+                     node "^enum_declaration$" nil 1000))
+         (struct-tree (treesit-induce-sparse-tree
+                       node "^struct_declaration$"  nil 1000))
+         (record-tree (treesit-induce-sparse-tree
+                       node "^record_declaration$"  nil 1000))
+         (method-tree (treesit-induce-sparse-tree
+                       node "^method_declaration$" nil 1000))
+         (class-index (csharp-ts-mode--imenu-1 class-tree))
+         (interface-index (csharp-ts-mode--imenu-1 interface-tree))
+         (enum-index (csharp-ts-mode--imenu-1 enum-tree))
+         (record-index (csharp-ts-mode--imenu-1 record-tree))
+         (struct-index (csharp-ts-mode--imenu-1 struct-tree))
+         (method-index (csharp-ts-mode--imenu-1 method-tree)))
+    (append
+     (when class-index `(("Class" . ,class-index)))
+     (when interface-index `(("Interface" . ,interface-index)))
+     (when enum-index `(("Enum" . ,enum-index)))
+     (when record-index `(("Record" . ,record-index)))
+     (when struct-index `(("Struct" . ,struct-index)))
+     (when method-index `(("Method" . ,method-index))))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
+
+;;;###autoload
+(define-derived-mode csharp-mode prog-mode "C#"
+  "Major mode for editing Csharp code.
+
+Key bindings:
+\\{csharp-mode-map}"
+  :after-hook (c-update-modeline)
+  (c-initialize-cc-mode t)
+  (c-init-language-vars csharp-mode)
+  (c-common-init 'csharp-mode)
+  (setq-local c-doc-comment-style '((csharp-mode . codedoc)))
+  (run-mode-hooks 'c-mode-common-hook))
+
+;;;###autoload
+(define-derived-mode csharp-ts-mode prog-mode "C#"
+  "Major mode for editing C# code."
+
+  (unless (treesit-ready-p 'c-sharp)
+    (error "Tree-sitter for C# isn't available"))
+
+  ;; Tree-sitter.
+  (treesit-parser-create 'c-sharp)
+
+  ;; Comments.
+  (setq-local comment-start "// ")
+  (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
+  (setq-local comment-end "")
+
+  ;; Indent.
+  (setq-local treesit-simple-indent-rules csharp-ts-mode--indent-rules)
+
+  ;; Electric
+  (setq-local electric-indent-chars
+              (append "{}():;," electric-indent-chars))
+
+  ;; Navigation.
+  (setq-local treesit-defun-type-regexp "declaration")
+
+  ;; Font-lock.
+  (setq-local treesit-font-lock-settings csharp-ts-mode--font-lock-settings)
+  (setq-local treesit-font-lock-feature-list
+              '((comment keyword constant string)
+                (type definition expression literal attribute)
+                (bracket delimiter)))
+
+  ;; Imenu.
+  (setq-local imenu-create-index-function #'csharp-ts-mode--imenu)
+  (setq-local which-func-functions nil) ;; Piggyback on imenu
+  (treesit-major-mode-setup))
+
+(provide 'csharp-mode)
+
+;;; csharp-mode.el ends here
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-22 21:47   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-23 12:16     ` Eli Zaretskii
  0 siblings, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2022-11-23 12:16 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: 59490

> Date: Tue, 22 Nov 2022 22:47:12 +0100
> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> Ok so this works.
> 
> Sorry for the mess.
> 
> What do you think?

LGTM, thanks.  I'll let Yuan review and install.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-22 20:52 bug#59490: 29.0.50; Add C# support Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-22 21:25 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
       [not found] ` <handler.59490.B.166915036216965.ack@debbugs.gnu.org>
@ 2022-11-23 18:29 ` Yuan Fu
  2022-11-23 18:44   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-23 20:38 ` Yuan Fu
  3 siblings, 1 reply; 12+ messages in thread
From: Yuan Fu @ 2022-11-23 18:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: theo, 59490


Eli Zaretskii <eliz@gnu.org> writes:

>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>> 
>> Ok so this works.
>> 
>> Sorry for the mess.
>> 
>> What do you think?
>
> LGTM, thanks.  I'll let Yuan review and install.

Thanks Theo! I’ve merged it. One general comment is that we should have
a "standard" list of features consistent across major modes. I think by
now we’ve worked on font-lock enough to know what those features should
be. I’ll start a discussion on the ML.

Yuan





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-23 18:29 ` Yuan Fu
@ 2022-11-23 18:44   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 12+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-23 18:44 UTC (permalink / raw)
  To: Yuan Fu, Eli Zaretskii; +Cc: 59490



On 23 November 2022 19:29:57 CET, Yuan Fu <casouri@gmail.com> wrote:
>
>Eli Zaretskii <eliz@gnu.org> writes:
>
>>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>> 
>>> Ok so this works.
>>> 
>>> Sorry for the mess.
>>> 
>>> What do you think?
>>
>> LGTM, thanks.  I'll let Yuan review and install.
>
>Thanks Theo! I’ve merged it. One general comment is that we should have
>a "standard" list of features consistent across major modes. I think by
>now we’ve worked on font-lock enough to know what those features should
>be. I’ll start a discussion on the ML.
>
>Yuan

I agree!





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-22 20:52 bug#59490: 29.0.50; Add C# support Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
                   ` (2 preceding siblings ...)
  2022-11-23 18:29 ` Yuan Fu
@ 2022-11-23 20:38 ` Yuan Fu
  2022-11-23 20:43   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-24  6:25   ` Eli Zaretskii
  3 siblings, 2 replies; 12+ messages in thread
From: Yuan Fu @ 2022-11-23 20:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: theo, 59490


Yuan Fu <casouri@gmail.com> writes:

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>> 
>>> Ok so this works.
>>> 
>>> Sorry for the mess.
>>> 
>>> What do you think?
>>
>> LGTM, thanks.  I'll let Yuan review and install.
>
> Thanks Theo! I’ve merged it. One general comment is that we should have
> a "standard" list of features consistent across major modes. I think by
> now we’ve worked on font-lock enough to know what those features should
> be. I’ll start a discussion on the ML.

Actually, another thing: it seems the mode defined is still named
csharp-mode rather than csharp-cc-mode.

Yuan





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-23 20:38 ` Yuan Fu
@ 2022-11-23 20:43   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-23 21:19     ` Yuan Fu
  2022-11-24  6:25   ` Eli Zaretskii
  1 sibling, 1 reply; 12+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-23 20:43 UTC (permalink / raw)
  To: Yuan Fu, Eli Zaretskii; +Cc: 59490



On 23 November 2022 21:38:19 CET, Yuan Fu <casouri@gmail.com> wrote:
>
>Yuan Fu <casouri@gmail.com> writes:
>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>>>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>>>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>>>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>>> 
>>>> Ok so this works.
>>>> 
>>>> Sorry for the mess.
>>>> 
>>>> What do you think?
>>>
>>> LGTM, thanks.  I'll let Yuan review and install.
>>
>> Thanks Theo! I’ve merged it. One general comment is that we should have
>> a "standard" list of features consistent across major modes. I think by
>> now we’ve worked on font-lock enough to know what those features should
>> be. I’ll start a discussion on the ML.
>
>Actually, another thing: it seems the mode defined is still named
>csharp-mode rather than csharp-cc-mode.
>
>Yuan

Yeah that's right. Imo that's ok, because it's unlikely there will be much new development on the cc mode variant. So it will be identical to the upstream one, and the upstream one will be marked as deprecated very soon.

What do you think?





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-23 20:43   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-23 21:19     ` Yuan Fu
  2022-11-23 21:25       ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 12+ messages in thread
From: Yuan Fu @ 2022-11-23 21:19 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: Eli Zaretskii, 59490



> On Nov 23, 2022, at 12:43 PM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> 
> 
> On 23 November 2022 21:38:19 CET, Yuan Fu <casouri@gmail.com> wrote:
>> 
>> Yuan Fu <casouri@gmail.com> writes:
>> 
>>> Eli Zaretskii <eliz@gnu.org> writes:
>>> 
>>>>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>>>>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>>>> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>>>> 
>>>>> Ok so this works.
>>>>> 
>>>>> Sorry for the mess.
>>>>> 
>>>>> What do you think?
>>>> 
>>>> LGTM, thanks.  I'll let Yuan review and install.
>>> 
>>> Thanks Theo! I’ve merged it. One general comment is that we should have
>>> a "standard" list of features consistent across major modes. I think by
>>> now we’ve worked on font-lock enough to know what those features should
>>> be. I’ll start a discussion on the ML.
>> 
>> Actually, another thing: it seems the mode defined is still named
>> csharp-mode rather than csharp-cc-mode.
>> 
>> Yuan
> 
> Yeah that's right. Imo that's ok, because it's unlikely there will be much new development on the cc mode variant. So it will be identical to the upstream one, and the upstream one will be marked as deprecated very soon.
> 
> What do you think?

Yeah I was just confused because you said

> I made two new modes, 'csharp-cc-mode' and 'csharp-ts-mode'. The cc-mode
> variant has that name as to not conflict with the ELPA package.

And I only see csharp-mode.

So the mode we provide in Emacs are csharp-mode and csharp-ts-mode? Then I assume this line is a typo?

;;;###autoload
(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-cc-mode))

Yuan






^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-23 21:19     ` Yuan Fu
@ 2022-11-23 21:25       ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-23 23:03         ` Yuan Fu
  0 siblings, 1 reply; 12+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-23 21:25 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Eli Zaretskii, 59490



On 23 November 2022 22:19:21 CET, Yuan Fu <casouri@gmail.com> wrote:
>
>
>> On Nov 23, 2022, at 12:43 PM, Theodor Thornhill <theo@thornhill.no> wrote:
>> 
>> 
>> 
>> On 23 November 2022 21:38:19 CET, Yuan Fu <casouri@gmail.com> wrote:
>>> 
>>> Yuan Fu <casouri@gmail.com> writes:
>>> 
>>>> Eli Zaretskii <eliz@gnu.org> writes:
>>>> 
>>>>>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>>>>>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>>>>> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>>>>> 
>>>>>> Ok so this works.
>>>>>> 
>>>>>> Sorry for the mess.
>>>>>> 
>>>>>> What do you think?
>>>>> 
>>>>> LGTM, thanks.  I'll let Yuan review and install.
>>>> 
>>>> Thanks Theo! I’ve merged it. One general comment is that we should have
>>>> a "standard" list of features consistent across major modes. I think by
>>>> now we’ve worked on font-lock enough to know what those features should
>>>> be. I’ll start a discussion on the ML.
>>> 
>>> Actually, another thing: it seems the mode defined is still named
>>> csharp-mode rather than csharp-cc-mode.
>>> 
>>> Yuan
>> 
>> Yeah that's right. Imo that's ok, because it's unlikely there will be much new development on the cc mode variant. So it will be identical to the upstream one, and the upstream one will be marked as deprecated very soon.
>> 
>> What do you think?
>
>Yeah I was just confused because you said
>
>> I made two new modes, 'csharp-cc-mode' and 'csharp-ts-mode'. The cc-mode
>> variant has that name as to not conflict with the ELPA package.

Yep, that was unclear. I decided to skip it in the second patch :)

>
>And I only see csharp-mode.
>
>So the mode we provide in Emacs are csharp-mode and csharp-ts-mode? Then I assume this line is a typo?
>
>;;;###autoload
>(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-cc-mode))
>
>Yuan
>

That's correct. That's a typo. My bad :) make it csharp-mode. You want a new patch?





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-23 21:25       ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-23 23:03         ` Yuan Fu
  0 siblings, 0 replies; 12+ messages in thread
From: Yuan Fu @ 2022-11-23 23:03 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: Eli Zaretskii, 59490



> On Nov 23, 2022, at 1:25 PM, Theodor Thornhill <theo@thornhill.no> wrote:
> 
> 
> 
> On 23 November 2022 22:19:21 CET, Yuan Fu <casouri@gmail.com> wrote:
>> 
>> 
>>> On Nov 23, 2022, at 12:43 PM, Theodor Thornhill <theo@thornhill.no> wrote:
>>> 
>>> 
>>> 
>>> On 23 November 2022 21:38:19 CET, Yuan Fu <casouri@gmail.com> wrote:
>>>> 
>>>> Yuan Fu <casouri@gmail.com> writes:
>>>> 
>>>>> Eli Zaretskii <eliz@gnu.org> writes:
>>>>> 
>>>>>>> Date: Tue, 22 Nov 2022 22:47:12 +0100
>>>>>>> From:  Theodor Thornhill via "Bug reports for GNU Emacs,
>>>>>>> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>>>>>>> 
>>>>>>> Ok so this works.
>>>>>>> 
>>>>>>> Sorry for the mess.
>>>>>>> 
>>>>>>> What do you think?
>>>>>> 
>>>>>> LGTM, thanks.  I'll let Yuan review and install.
>>>>> 
>>>>> Thanks Theo! I’ve merged it. One general comment is that we should have
>>>>> a "standard" list of features consistent across major modes. I think by
>>>>> now we’ve worked on font-lock enough to know what those features should
>>>>> be. I’ll start a discussion on the ML.
>>>> 
>>>> Actually, another thing: it seems the mode defined is still named
>>>> csharp-mode rather than csharp-cc-mode.
>>>> 
>>>> Yuan
>>> 
>>> Yeah that's right. Imo that's ok, because it's unlikely there will be much new development on the cc mode variant. So it will be identical to the upstream one, and the upstream one will be marked as deprecated very soon.
>>> 
>>> What do you think?
>> 
>> Yeah I was just confused because you said
>> 
>>> I made two new modes, 'csharp-cc-mode' and 'csharp-ts-mode'. The cc-mode
>>> variant has that name as to not conflict with the ELPA package.
> 
> Yep, that was unclear. I decided to skip it in the second patch :)
> 
>> 
>> And I only see csharp-mode.
>> 
>> So the mode we provide in Emacs are csharp-mode and csharp-ts-mode? Then I assume this line is a typo?
>> 
>> ;;;###autoload
>> (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-cc-mode))
>> 
>> Yuan
>> 
> 
> That's correct. That's a typo. My bad :) make it csharp-mode. You want a new patch?

I applied the patch with that change :-)

Yuan






^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#59490: 29.0.50; Add C# support
  2022-11-23 20:38 ` Yuan Fu
  2022-11-23 20:43   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-24  6:25   ` Eli Zaretskii
  1 sibling, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2022-11-24  6:25 UTC (permalink / raw)
  To: Yuan Fu; +Cc: theo, 59490

> From: Yuan Fu <casouri@gmail.com>
> Date: Wed, 23 Nov 2022 12:38:19 -0800
> Cc: theo@thornhill.no,
>  59490@debbugs.gnu.org
> 
> Actually, another thing: it seems the mode defined is still named
> csharp-mode rather than csharp-cc-mode.

I think it is better in general to keep the name of the existing mode for
which this one is supposed to be a replacement/continuation.





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2022-11-24  6:25 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-22 20:52 bug#59490: 29.0.50; Add C# support Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-22 21:25 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
     [not found] ` <handler.59490.B.166915036216965.ack@debbugs.gnu.org>
2022-11-22 21:47   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-23 12:16     ` Eli Zaretskii
2022-11-23 18:29 ` Yuan Fu
2022-11-23 18:44   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-23 20:38 ` Yuan Fu
2022-11-23 20:43   ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-23 21:19     ` Yuan Fu
2022-11-23 21:25       ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-23 23:03         ` Yuan Fu
2022-11-24  6:25   ` Eli Zaretskii

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.