From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Theodor Thornhill via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#43559: 28.0.50; [PATCH] Add csharp support to cc-mode Date: Tue, 22 Sep 2020 12:37:54 +0200 Message-ID: <87zh5iyu4d.fsf@thornhill.no> Reply-To: Theodor Thornhill Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="19368"; mail-complaints-to="usenet@ciao.gmane.io" Cc: acm@muc.de, jostein@kjonigsen.net To: 43559@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Sep 22 12:44:59 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kKfn8-0004q9-Rp for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 22 Sep 2020 12:44:59 +0200 Original-Received: from localhost ([::1]:58882 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kKfn7-0004RY-O7 for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 22 Sep 2020 06:44:57 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:56474) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kKfhS-00053U-Q5 for bug-gnu-emacs@gnu.org; Tue, 22 Sep 2020 06:39:08 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:45758) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kKfhO-0007Dm-NO for bug-gnu-emacs@gnu.org; Tue, 22 Sep 2020 06:39:06 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1kKfhO-0005tp-Js for bug-gnu-emacs@gnu.org; Tue, 22 Sep 2020 06:39:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Theodor Thornhill Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 22 Sep 2020 10:39:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 43559 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.160077109022610 (code B ref -1); Tue, 22 Sep 2020 10:39:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 22 Sep 2020 10:38:10 +0000 Original-Received: from localhost ([127.0.0.1]:57303 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kKfgX-0005sa-HL for submit@debbugs.gnu.org; Tue, 22 Sep 2020 06:38:10 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:60232) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kKfgU-0005sS-Ju for submit@debbugs.gnu.org; Tue, 22 Sep 2020 06:38:07 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:56206) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kKfgT-0003he-BL for bug-gnu-emacs@gnu.org; Tue, 22 Sep 2020 06:38:06 -0400 Original-Received: from out1.migadu.com ([91.121.223.63]:25556) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kKfgM-00078f-Gh for bug-gnu-emacs@gnu.org; Tue, 22 Sep 2020 06:38:03 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thornhill.no; s=key1; t=1600771072; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type; bh=fIFGzmNLWawhGSvzOIKH6qcy+LgLXJMGI168Mb7aEdI=; b=PamFjSAcsC5anZWZUQzjhJYTC8F3HoxuGkJTcrzCLoFpbyfEomWzxDs3+oAxvwp1FMKmb6 Hsju5CtQxWrWgxnTxtQJJJR1vbrGxUuHXgclnTLM7HpRd+PNKelF8X+Kk5xXpwOoJXJDDi ZGfXuFzi5+7gx6+Oe/HXV940GZyFqP44+nFknilvky32rynL0oJKlkY9UR1P2Ir0Ff1zsN cwT9nJNpINQ6CNnXKe+foyOF4cCvtEZYcyjnhpeydCPiTlMjfhzch24Y2qkljO+PqUU1G5 a96IvjZRatXx0vO7w3ZwTmHj6DQ1rvR2GzSxVgM3GWJlatraST8OY94TiYJxOw== Received-SPF: pass client-ip=91.121.223.63; envelope-from=theo@thornhill.no; helo=out1.migadu.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/22 06:37:53 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:188672 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hello! For some time, I've been a little dissatisfied with the support for C# in emacs. Recently, there has been some breakage in handling of strings and fontification, more precisely: - https://github.com/josteink/csharp-mode/issues/162 Also, it is using a lot of internal c-mode functions: - https://github.com/josteink/csharp-mode/issues/162 I've had some discussions with with the current maintainer, Jostein Kj=C3=B8nigsen (cc'd) about the future of this mode in https://github.com/josteink/csharp-mode/issues/162. Some points of note: - It cannot easily be donated to emacs due to paperwork - Jostein does not have time to do it himself - I took upon myself to rewrite it in a separate branch, as an end goal for it to be included in emacs While working on this, I realized the easiest way to get something good here is to overall reduce the complexity. As such I created this patch. It seems to work nicely, removing the need for the external mode completely. However, I see that including csharp here is most likely a bigger effort than just sending this patch, but I wanted to send what I have, and hopefully get some pointers. Or in worst case stop before I go too far.. This patch is written without consulting the current mode, so paperwork should not be an issue. In addition, the current mode has an implementation of imenu rewritten from scratch by Jostein, and as such I think this can be included as well. I tried not to do too much, since I believe most of the advanced functionality should be provided by an lsp mode such as eglot or lsp-mode. Have a nice day! Theodor Thornhill --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Add-csharp-support-to-cc-mode.patch >From bb5bd8390ac969bad593b1c9383ce6e2bd0e7cf7 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Tue, 22 Sep 2020 12:09:38 +0200 Subject: [PATCH] Add csharp support to cc-mode --- lisp/progmodes/cc-defs.el | 27 +++---- lisp/progmodes/cc-fonts.el | 33 ++++++++ lisp/progmodes/cc-langs.el | 149 +++++++++++++++++++++++------------- lisp/progmodes/cc-mode.el | 65 +++++++++++++--- lisp/progmodes/cc-styles.el | 37 +++++++++ lisp/progmodes/cc-vars.el | 22 ++++++ 6 files changed, 255 insertions(+), 78 deletions(-) diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index 77e263f1aa..ac1c421e37 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -95,12 +95,12 @@ c-version-sym (defvar c-buffer-is-cc-mode nil "Non-nil for all buffers with a major mode derived from CC Mode. -Otherwise, this variable is nil. I.e. this variable is non-nil for -`c-mode', `c++-mode', `objc-mode', `java-mode', `idl-mode', -`pike-mode', `awk-mode', and any other non-CC Mode mode that calls -`c-initialize-cc-mode'. The value is the mode symbol itself -\(i.e. `c-mode' etc) of the original CC Mode mode, or just t if it's -not known.") +Otherwise, this variable is nil. I.e. this variable is non-nil +for `c-mode', `c++-mode', `objc-mode', `csharp-mode', +`java-mode', `idl-mode', `pike-mode', `awk-mode', and any other +non-CC Mode mode that calls `c-initialize-cc-mode'. The value is +the mode symbol itself \(i.e. `c-mode' etc) of the original CC +Mode mode, or just t if it's not known.") (make-variable-buffer-local 'c-buffer-is-cc-mode) ;; Have to make `c-buffer-is-cc-mode' permanently local so that it @@ -1874,13 +1874,14 @@ c-keep-region-active (and (boundp 'zmacs-region-stays) (setq zmacs-region-stays t))) -(put 'c-mode 'c-mode-prefix "c-") -(put 'c++-mode 'c-mode-prefix "c++-") -(put 'objc-mode 'c-mode-prefix "objc-") -(put 'java-mode 'c-mode-prefix "java-") -(put 'idl-mode 'c-mode-prefix "idl-") -(put 'pike-mode 'c-mode-prefix "pike-") -(put 'awk-mode 'c-mode-prefix "awk-") +(put 'c-mode 'c-mode-prefix "c-") +(put 'c++-mode 'c-mode-prefix "c++-") +(put 'objc-mode 'c-mode-prefix "objc-") +(put 'csharp-mode 'c-mode-prefix "csharp-") +(put 'java-mode 'c-mode-prefix "java-") +(put 'idl-mode 'c-mode-prefix "idl-") +(put 'pike-mode 'c-mode-prefix "pike-") +(put 'awk-mode 'c-mode-prefix "awk-") (defsubst c-mode-symbol (suffix) "Prefix the current mode prefix (e.g. \"c-\") to SUFFIX and return diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index bb7e5bea6e..c361609e0f 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -2579,6 +2579,39 @@ objc-font-lock-keywords (setq objc-font-lock-extra-types (cc-eval-when-compile (list (concat "[" c-upper "]\\sw*"))))) + +;;; Csharp. + +(c-override-default-keywords 'csharp-font-lock-keywords) + +(defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp) + "Minimal font locking for C# mode. +Fontifies nothing except the syntactic fontification of strings and +comments.") + +(defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp) + "Fast normal font locking for C# mode. +In addition to `csharp-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `csharp-font-lock-extra-types', and the doc +comment styles specified by `c-doc-comment-style'.") + +(defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp) + "Accurate normal font locking for C# mode. +Like variable `csharp-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `csharp-font-lock-extra-types'.") + +(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)) + ;;; Java. diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 13e70a3251..65b1419bb1 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -378,7 +378,8 @@ c-make-mode-syntax-table (let ((table (make-syntax-table))) (c-populate-syntax-table table) ;; Mode specific syntaxes. - ,(cond ((or (c-major-mode-is 'objc-mode) (c-major-mode-is 'java-mode)) + ,(cond ((or (c-major-mode-is 'objc-mode) (c-major-mode-is 'java-mode) + (c-major-mode-is 'csharp-mode)) ;; Let '@' be part of symbols in ObjC to cope with ;; its compiler directives as single keyword tokens. ;; This is then necessary since it's assumed that @@ -430,7 +431,7 @@ c-identifier-syntax-modifications ;; it as an identifier character since it's often used in various ;; machine generated identifiers. t '((?_ . "w") (?$ . "w")) - (objc java) (append '((?@ . "w")) + (objc java csharp) (append '((?@ . "w")) (c-lang-const c-identifier-syntax-modifications)) awk '((?_ . "w"))) (c-lang-defvar c-identifier-syntax-modifications @@ -467,6 +468,9 @@ c-get-state-before-change-functions c-truncate-bs-cache c-before-change-check-unbalanced-strings c-parse-quotes-before-change) + csharp '(c-parse-quotes-before-change + c-before-change-check-unbalanced-strings + c-before-change-check-<>-operators) java '(c-parse-quotes-before-change c-before-change-check-unbalanced-strings c-before-change-check-<>-operators) @@ -516,6 +520,12 @@ c-before-font-lock-functions c-neutralize-syntax-in-CPP c-restore-<>-properties c-change-expand-fl-region) + csharp '(c-depropertize-new-text + c-after-change-escape-NL-in-string + c-parse-quotes-after-change + c-after-change-mark-abnormal-strings + c-restore-<>-properties + c-change-expand-fl-region) java '(c-depropertize-new-text c-after-change-escape-NL-in-string c-parse-quotes-after-change @@ -648,10 +658,11 @@ c-symbol-start "Regexp that matches the start of a symbol, i.e. any identifier or keyword. It's unspecified how far it matches. Does not contain a \\| operator at the top level." - t (concat "[" c-alpha "_]") - java (concat "[" c-alpha "_@]") - objc (concat "[" c-alpha "_@]") - pike (concat "[" c-alpha "_`]")) + t (concat "[" c-alpha "_]") + csharp (concat "[" c-alpha "_@]") + java (concat "[" c-alpha "_@]") + objc (concat "[" c-alpha "_@]") + pike (concat "[" c-alpha "_`]")) (c-lang-defvar c-symbol-start (c-lang-const c-symbol-start)) (c-lang-defconst c-symbol-chars @@ -718,6 +729,7 @@ c-identifier-ops ;; naming conventions. We still define "." here to make ;; `c-forward-name' move over as long names as possible which is ;; necessary to e.g. handle throws clauses correctly. + csharp '((left-assoc ".")) java '((left-assoc ".")) idl '((left-assoc "::") (prefix "::")) @@ -1247,6 +1259,8 @@ c-overloadable-operators "<<" ">>" ">>=" "<<=" "==" "!=" "not_eq" "<=" ">=" "&&" "and" "||" "??!??!" "or" "++" "--" "," "->*" "->" "()" "[]" "<::>" "??(??)") + csharp '("+" "-" "*" "/" "%" "&" "|" "^" "<<" ">>" "==" + "!=" ">" "<" ">=" "<=") ;; These work like identifiers in Pike. pike '("`+" "`-" "`&" "`|" "`^" "`<<" "`>>" "`*" "`/" "`%" "`~" "`==" "`<" "`>" "`!" "`[]" "`[]=" "`->" "`->=" "`()" "``+" @@ -2023,6 +2037,8 @@ c-primitive-type-kwds objc (append '("id" "Class" "SEL" "IMP" "BOOL") (c-lang-const c-primitive-type-kwds)) + csharp '("bool" "byte" "sbyte" "char" "decimal" "double" "float" "int" "uint" + "long" "ulong" "short" "ushort" "void" "object" "string") java '("boolean" "byte" "char" "double" "float" "int" "long" "short" "void") idl '("Object" "ValueBase" "any" "boolean" "char" "double" "fixed" "float" "long" "octet" "sequence" "short" "string" "void" "wchar" "wstring" @@ -2137,7 +2153,8 @@ c-type-modifier-kwds on `c-primitive-type-kwds', they are fontified with the keyword face and not the type face." t (c-lang-const c-type-modifier-prefix-kwds) - c++ (append (c-lang-const c-type-modifier-prefix-kwds) '("throw"))) + c++ (append (c-lang-const c-type-modifier-prefix-kwds) '("throw")) + csharp '("readonly" "const" "volatile" "new")) (c-lang-defconst c-opt-type-modifier-key ;; Adorned regexp matching `c-type-modifier-kwds', or nil in @@ -2229,8 +2246,9 @@ c-brace-list-decl-kwds `c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', `c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses will be handled." - t '("enum") - (awk) nil) + t '("enum") + csharp '("enum" "new") + (awk) nil) (c-lang-defconst c-brace-list-key ;; Regexp matching the start of declarations where the following @@ -2281,6 +2299,7 @@ c-other-block-decl-kwds t nil (c objc) '("extern") c++ '("namespace" "extern") + csharp '("namespace") idl '("module" ;; In CORBA CIDL: "composition")) @@ -2341,7 +2360,8 @@ c-typedef-decl-key (c-lang-defconst c-using-kwds "Keywords which behave like `using' in C++" t nil - c++ '("using")) + c++ '("using") + csharp '("using")) (c-lang-defconst c-using-key ;; Regexp matching C++'s `using'. @@ -2410,6 +2430,10 @@ c-modifier-kwds "primary" "state" ;; In CORBA CIDL: "bindsTo" "delegatesTo" "implements" "proxy" "storedOn") + csharp '("abstract" "const" "default" "final" "native" "private" "protected" + "public" "partial" "internal" "readonly" "static" "event" "transient" + "volatile" "sealed" "ref" "out" "virtual" "implicit" "explicit" + "fixed" "override" "params" "async" "extern" "unsafe") ;; Note: "const" is not used in Java, but it's still a reserved keyword. java '("abstract" "const" "default" "final" "native" "private" "protected" "public" "static" "strictfp" "synchronized" "transient" "volatile") @@ -2634,14 +2658,16 @@ c-type-list-kwds Note: Use `c-typeless-decl-kwds' for keywords followed by a function or variable identifier (that's being defined)." - t nil - c++ '("operator") - objc '("@class") - java '("import" "new" "extends" "super" "implements" "throws") - idl '("manages" "native" "primarykey" "supports" - ;; In CORBA PSDL: - "as" "implements" "of" "scope") - pike '("inherit")) + t nil + c++ '("operator") + objc '("@class") + csharp '("struct" "class" "interface" "delegate" "event" "get" "set" "add" + "remove" "is" "as" "operator") + java '("import" "new" "extends" "super" "implements" "throws") + idl '("manages" "native" "primarykey" "supports" + ;; In CORBA PSDL: + "as" "implements" "of" "scope") + pike '("inherit")) (c-lang-defconst c-ref-list-kwds "Keywords that may be followed by a comma separated list of @@ -2652,24 +2678,26 @@ c-ref-list-kwds Note: Use `c-typeless-decl-kwds' for keywords followed by a function or variable identifier (that's being defined)." - t nil - c++ '("namespace") - java '("package") - idl '("import" "module" - ;; In CORBA CIDL: - "composition") - pike '("import")) + t nil + c++ '("namespace") + csharp '("var") + java '("package") + idl '("import" "module" + ;; In CORBA CIDL: + "composition") + pike '("import")) (c-lang-defconst c-colon-type-list-kwds "Keywords that may be followed (not necessarily directly) by a colon and then a comma separated list of type identifiers, where each optionally can be prefixed by keywords. (Can also be used for the special case when the list can contain only one element.)" - t nil - c++ '("class" "struct") - idl '("component" "eventtype" "home" "interface" "valuetype" - ;; In CORBA PSDL: - "storagehome" "storagetype")) + t nil + c++ '("class" "struct") + csharp '("class" "struct" "interface") + idl '("component" "eventtype" "home" "interface" "valuetype" + ;; In CORBA PSDL: + "storagehome" "storagetype")) (c-lang-defconst c-colon-type-list-re "Regexp matched after the keywords in `c-colon-type-list-kwds' to skip @@ -2765,11 +2793,12 @@ c-brace-id-list-kwds (c-lang-defconst c-block-stmt-1-kwds "Statement keywords followed directly by a substatement." - t '("do" "else") - c++ '("do" "else" "try") - objc '("do" "else" "@finally" "@try" "@autoreleasepool") - java '("do" "else" "finally" "try") - idl nil) + t '("do" "else") + c++ '("do" "else" "try") + objc '("do" "else" "@finally" "@try" "@autoreleasepool") + csharp '("do" "else" "finally" "try") + java '("do" "else" "finally" "try") + idl nil) (c-lang-defconst c-block-stmt-1-key ;; Regexp matching the start of any statement followed directly by a @@ -2781,7 +2810,8 @@ c-block-stmt-1-2-kwds "Statement keywords optionally followed by a paren sexp. Keywords here should also be in `c-block-stmt-1-kwds'." t nil - java '("try")) + csharp '("try") + java '("try")) (c-lang-defconst c-block-stmt-1-2-key ;; Regexp matching the start of a statement which may be followed by a @@ -2791,13 +2821,15 @@ c-block-stmt-1-2-key (c-lang-defconst c-block-stmt-2-kwds "Statement keywords followed by a paren sexp and then by a substatement." - t '("for" "if" "switch" "while") - c++ '("for" "if" "switch" "while" "catch") - objc '("for" "if" "switch" "while" "@catch" "@synchronized") - java '("for" "if" "switch" "while" "catch" "synchronized") - idl nil - pike '("for" "if" "switch" "while" "foreach") - awk '("for" "if" "switch" "while")) + t '("for" "if" "switch" "while") + c++ '("for" "if" "switch" "while" "catch") + objc '("for" "if" "switch" "while" "@catch" "@synchronized") + csharp '("for" "if" "switch" "while" "catch" "foreach" "fixed" "checked" + "unchecked" "using" "lock") + java '("for" "if" "switch" "while" "catch" "synchronized") + idl nil + pike '("for" "if" "switch" "while" "foreach") + awk '("for" "if" "switch" "while")) (c-lang-defconst c-block-stmt-2-key ;; Regexp matching the start of any statement followed by a paren sexp @@ -2838,6 +2870,7 @@ c-simple-stmt-kwds t '("break" "continue" "goto" "return") c++ '("break" "continue" "goto" "return" "co_return") objc '("break" "continue" "goto" "return" "@throw") + csharp '("break" "continue" "goto" "return" "throw") ;; Note: `goto' is not valid in Java, but the keyword is still reserved. java '("break" "continue" "goto" "return" "throw") idl nil @@ -2912,16 +2945,18 @@ c-constant-kwds objc '("nil" "Nil" "YES" "NO" "IBAction" "IBOutlet" "NS_DURING" "NS_HANDLER" "NS_ENDHANDLER") idl '("TRUE" "FALSE") + csharp '("true" "false" "null" "value") java '("true" "false" "null") ; technically "literals", not keywords pike '("UNDEFINED")) ;; Not a keyword, but practically works as one. (c-lang-defconst c-primary-expr-kwds "Keywords besides constants and operators that start primary expressions." - t nil - c++ '("operator" "this") - objc '("super" "self") - java '("this") - pike '("this")) ;; Not really a keyword, but practically works as one. + t nil + c++ '("operator" "this") + objc '("super" "self") + csharp '("this" "base" "operator") + java '("this") + pike '("this")) ;; Not really a keyword, but practically works as one. (c-lang-defconst c-expr-kwds ;; Keywords that can occur anywhere in expressions. Built from @@ -2948,16 +2983,18 @@ c-inexpr-block-kwds (c-lang-defconst c-inexpr-class-kwds "Keywords that can start classes inside expressions." - t nil - java '("new") - pike '("class")) + t nil + csharp '("new") + java '("new") + pike '("class")) (c-lang-defconst c-inexpr-brace-list-kwds "Keywords that can start brace list blocks inside expressions. Note that Java specific rules are currently applied to tell this from `c-inexpr-class-kwds'." - t nil - java '("new")) + t nil + csharp '("new") + java '("new")) (c-lang-defconst c-opt-inexpr-brace-list-key ;; Regexp matching the start of a brace list in an expression, or @@ -3049,6 +3086,7 @@ c-std-abbrev-keywords "List of keywords which may need to cause electric indentation." t '("else" "while") c++ (append (c-lang-const c-std-abbrev-keywords) '("catch")) + csharp (append (c-lang-const c-std-abbrev-keywords) '("catch" "finally")) java (append (c-lang-const c-std-abbrev-keywords) '("catch" "finally")) idl nil) (c-lang-defvar c-std-abbrev-keywords (c-lang-const c-std-abbrev-keywords)) @@ -3274,6 +3312,7 @@ c-decl-prefix-re ;; in all languages except Java for when a cpp macro definition ;; begins with a declaration. t "\\([{}();,]+\\)" + csharp "\\([{}(;,<]+\\)" java "\\([{}(;,<]+\\)" ;; Match "<" in C++ to get the first argument in a template arglist. ;; In that case there's an additional check in `c-find-decl-spots' @@ -3585,6 +3624,7 @@ c-opt-type-suffix-key is in effect or not." t nil (c c++ objc pike) "\\(\\.\\.\\.\\)" + csharp (concat "\\(\\[" (c-lang-const c-simple-ws) "*\\]\\|\\.\\.\\.\\)") java (concat "\\(\\[" (c-lang-const c-simple-ws) "*\\]\\|\\.\\.\\.\\)")) (c-lang-defvar c-opt-type-suffix-key (c-lang-const c-opt-type-suffix-key)) @@ -3644,7 +3684,7 @@ c-recognize-typeless-decls that are preceded by a declaration starting keyword, so e.g. `c-typeless-decl-kwds' may still be used when it's set to nil." t nil - (c c++ objc java) t) + (c c++ objc csharp java) t) (c-lang-defvar c-recognize-typeless-decls (c-lang-const c-recognize-typeless-decls)) @@ -3657,6 +3697,7 @@ c-recognize-<>-arglists expression is considered to be a type." t (or (consp (c-lang-const c-<>-type-kwds)) (consp (c-lang-const c-<>-arglist-kwds))) + csharp t java t) ; 2008-10-19. This is crude. The syntax for java ; generics is not yet coded in CC Mode. (c-lang-defvar c-recognize-<>-arglists (c-lang-const c-recognize-<>-arglists)) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index c6dd671051..56cc476fad 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -36,12 +36,12 @@ ;; Note: The version string is in cc-defs. ;; This package provides GNU Emacs major modes for editing C, C++, -;; Objective-C, Java, CORBA's IDL, Pike and AWK code. As of the +;; Objective-C, C#, Java, CORBA's IDL, Pike and AWK code. As of the ;; latest Emacs and XEmacs releases, it is the default package for ;; editing these languages. This package is called "CC Mode", and ;; should be spelled exactly this way. -;; CC Mode supports K&R and ANSI C, ANSI C++, Objective-C, Java, +;; CC Mode supports K&R and ANSI C, ANSI C++, Objective-C, C#, Java, ;; CORBA's IDL, Pike and AWK with a consistent indentation model ;; across all modes. This indentation model is intuitive and very ;; flexible, so that almost any desired style of indentation can be @@ -75,7 +75,6 @@ ;; Externally maintained major modes which use CC-mode's engine include: ;; - cuda-mode -;; - csharp-mode (https://github.com/josteink/csharp-mode) ;; - haxe-mode ;; - d-mode ;; - dart-mode @@ -195,13 +194,14 @@ c-init-language-vars-for `c-init-language-vars' macro if the language you want to use is one of those, rather than a derived language defined through the language variable system (see \"cc-langs.el\")." - (cond ((eq mode 'c-mode) (c-init-language-vars c-mode)) - ((eq mode 'c++-mode) (c-init-language-vars c++-mode)) - ((eq mode 'objc-mode) (c-init-language-vars objc-mode)) - ((eq mode 'java-mode) (c-init-language-vars java-mode)) - ((eq mode 'idl-mode) (c-init-language-vars idl-mode)) - ((eq mode 'pike-mode) (c-init-language-vars pike-mode)) - ((eq mode 'awk-mode) (c-init-language-vars awk-mode)) + (cond ((eq mode 'c-mode) (c-init-language-vars c-mode)) + ((eq mode 'c++-mode) (c-init-language-vars c++-mode)) + ((eq mode 'objc-mode) (c-init-language-vars objc-mode)) + ((eq mode 'csharp-mode) (c-init-language-vars csharp-mode)) + ((eq mode 'java-mode) (c-init-language-vars java-mode)) + ((eq mode 'idl-mode) (c-init-language-vars idl-mode)) + ((eq mode 'pike-mode) (c-init-language-vars pike-mode)) + ((eq mode 'awk-mode) (c-init-language-vars awk-mode)) (t (error "Unsupported mode %s" mode)))) ;;;###autoload @@ -649,7 +649,8 @@ c-basic-common-init (when (or c-recognize-<>-arglists (c-major-mode-is 'awk-mode) - (c-major-mode-is '(java-mode c-mode c++-mode objc-mode pike-mode))) + (c-major-mode-is + '(java-mode c-mode c++-mode objc-mode pike-mode csharp-mode))) ;; We'll use the syntax-table text property to change the syntax ;; of some chars for this language, so do the necessary setup for ;; that. @@ -2739,6 +2740,48 @@ objc-mode (cc-imenu-init nil 'cc-imenu-objc-function) (c-run-mode-hooks 'c-mode-common-hook)) + +;; Support for C# + +(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.") +;; Add bindings which are only useful for C#. + +(easy-menu-define c-csharp-menu csharp-mode-map "C# Mode Commands" + (cons "C#" (c-lang-const c-mode-menu csharp))) + +;;;###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. +To submit a problem report, enter `\\[c-submit-bug-report]' from a +csharp-mode buffer. This automatically sets up a mail buffer with +version information already added. You just need to add a description +of the problem, including a reproducible test case, and send the +message. + +To see what version of CC Mode you are running, enter `\\[c-version]'. + +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `csharp-mode-hook'. + +Key bindings: +\\{csharp-mode-map}" + :after-hook (c-update-modeline) + (c-initialize-cc-mode t) + (setq abbrev-mode t) + (c-init-language-vars-for 'csharp-mode) + (c-common-init 'csharp-mode) + (easy-menu-add c-csharp-menu) + (c-run-mode-hooks 'c-mode-common-hook)) + ;; Support for Java diff --git a/lisp/progmodes/cc-styles.el b/lisp/progmodes/cc-styles.el index 36be9f6c74..4b84bd7dff 100644 --- a/lisp/progmodes/cc-styles.el +++ b/lisp/progmodes/cc-styles.el @@ -215,6 +215,43 @@ c-style-alist (arglist-cont-nonempty))) (c-block-comment-prefix . "")) + ("csharp" + (c-basic-offset . 4) + (c-comment-only-line-offset . (0 . 0)) + (c-offsets-alist . ((inline-open . 0) + (topmost-intro . 0) + (topmost-intro-cont . +) + (statement-block-intro . +) + (statement-case-intro . +) + (statement-case-open . +) + (substatement . +) + (substatement-open . 0) + (substatement-label . +) + (label . +) + (statement-case-open . +) + (statement-cont . +) + (arglist-intro . c-lineup-arglist-intro-after-paren) + (arglist-close . c-lineup-arglist) + (string . c-lineup-dont-change) + (arglist-cont . 0) + (block-open . 0) + (block-close . 0) + (block-list-entry . 0) + (block-list-open . 0) + (block-list-close . 0) + (case-label . +) + (catch-label . 0) + (class-open . 0) + (class-close . 0) + (defun-open . 0) + (defun-close . 0) + (else-clause . 0) + (brace-list-intro . (first + c-lineup-2nd-brace-entry-in-arglist + c-lineup-class-decl-init-+ +)) + (access-label . -) + (inher-cont . c-lineup-java-inher) + (func-decl-cont . c-lineup-java-throws)))) ("java" (c-basic-offset . 4) (c-comment-only-line-offset . (0 . 0)) diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 9e6f9527ca..559531fafe 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -549,6 +549,8 @@ c-comment-prefix-regexp (const :format "C++ " c++-mode) (regexp :format "%v")) (cons :format "%v" (const :format "ObjC " objc-mode) (regexp :format "%v")) + (cons :format "%v" + (const :format "C# " csharp-mode) (regexp :format "%v")) (cons :format "%v" (const :format "Java " java-mode) (regexp :format "%v")) (cons :format "%v" @@ -919,6 +921,9 @@ c-require-final-newline (cons :format "%v" (const :format "ObjC " objc-mode) (symbol :format "%v" :value ,require-final-newline)) + (cons :format "%v" + (const :format "C# " csharp-mode) + (symbol :format "%v" :value ,require-final-newline)) (cons :format "%v" (const :format "Java " java-mode) (symbol :format "%v" :value ,require-final-newline)) @@ -1003,6 +1008,7 @@ c-objc-method-parameter-offset :group 'c) (defcustom c-default-style '((java-mode . "java") (awk-mode . "awk") + (csharp-mode . "csharp") (other . "gnu")) "Style which gets installed by default when a file is visited. @@ -1031,6 +1037,8 @@ c-default-style (const :format "C++ " c++-mode) (string :format "%v")) (cons :format "%v" (const :format "ObjC " objc-mode) (string :format "%v")) + (cons :format "%v" + (const :format "C# " csharp-mode) (string :format "%v")) (cons :format "%v" (const :format "Java " java-mode) (string :format "%v")) (cons :format "%v" @@ -1459,6 +1467,11 @@ objc-mode-hook :type 'hook :group 'c) +(defcustom csharp-mode-hook nil + "Hook called by `csharp-mode'." + :type 'hook + :group 'c) + (defcustom java-mode-hook nil "Hook called by `java-mode'." :type 'hook @@ -1613,6 +1626,15 @@ objc-font-lock-extra-types :type 'c-extra-types-widget :group 'c) +(defcustom csharp-font-lock-extra-types + (list (concat "[" c-upper "]\\sw*[" c-lower "]\\sw")) + (c-make-font-lock-extra-types-blurb "C#" "csharp-mode" (concat +"For example, a value of (\"[" c-upper "]\\\\sw*[" c-lower "]\\\\sw*\") means +capitalized words are treated as type names (the requirement for a +lower case char is to avoid recognizing all-caps constant names).")) + :type 'c-extra-types-widget + :group 'c) + (defcustom java-font-lock-extra-types (list (concat "[" c-upper "]\\sw*[" c-lower "]\\sw")) (c-make-font-lock-extra-types-blurb "Java" "java-mode" (concat -- 2.28.0 --=-=-=--