[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/csharp-mode 084192f 002/459: initial import
From: |
ELPA Syncer |
Subject: |
[elpa] externals/csharp-mode 084192f 002/459: initial import |
Date: |
Sun, 22 Aug 2021 13:58:42 -0400 (EDT) |
branch: externals/csharp-mode
commit 084192f9050ee78578c134585621a5b56f9ef6f0
Author: Dino Chiesa <dpchiesa@mailinator.com>
Commit: Dino Chiesa <dpchiesa@mailinator.com>
initial import
---
csharp-mode.el | 2643 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 2643 insertions(+)
diff --git a/csharp-mode.el b/csharp-mode.el
new file mode 100644
index 0000000..6bd9e96
--- /dev/null
+++ b/csharp-mode.el
@@ -0,0 +1,2643 @@
+;;; csharp-mode.el --- C# mode derived mode
+
+;; Author: Dylan R. E. Moonfire (original)
+;; Maintainer: Dino Chiesa <dpchiesa@hotmail.com>
+;; Created: Feburary 2005
+;; Modified: April 2010
+;; Version: 0.7.5
+;; Keywords: c# languages oop mode
+
+;; 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 2 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; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+;;
+;; This is a separate mode to implement the C# constructs and
+;; font-locking. It is based on the java-mode example from cc-mode.
+;;
+;; csharp-mode requires CC Mode 5.30 or later. It works with
+;; cc-mode 5.31.3, which is current at this time.
+;;
+;; Features:
+;;
+;; - font-lock and indent of C# syntax including:
+;; all c# keywords and major syntax
+;; attributes that decorate methods, classes, fields, properties
+;; enum types
+;; #if/#endif #region/#endregion
+;; instance initializers
+;; anonymous functions and methods
+;; verbatim literal strings (those that begin with @)
+;; generics
+;;
+;; - automagic code-doc generation when you type three slashes.
+;;
+;; - intelligent inserttion of matched pairs of curly braces.
+;;
+;; - sets the compiler regex for next-error, for csc.exe output.
+;;
+;;
+
+;;; To use:
+;;
+;; put this in your .emacs:
+;;
+;; (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t)
+;;
+;; or:
+;;
+;; (require 'csharp-mode)
+;;
+;;
+;; AND:
+;;
+;; (setq auto-mode-alist
+;; (append '(("\\.cs$" . csharp-mode)) auto-mode-alist))
+;; (defun my-csharp-mode-fn ()
+;; "function that runs when csharp-mode is initialized for a buffer."
+;; ...insert your code here...
+;; ...most commonly, your custom key bindings ...
+;; )
+;; (add-hook 'csharp-mode-hook 'my-csharp-mode-fn t)
+;;
+;;
+
+
+;;; Known Bugs:
+;;
+;; Leading identifiers are no longer being fontified, for some reason.
+;; See matchers-before.
+;;
+;; Method names with a preceding attribute are not fontified.
+;;
+;; The symbol followng #if is not fontified. It should be treated like
+;; define and get font-lock-variable-name-face .
+;;
+;; This code doesn't seem to work when you compile it, then
+;; load/require in the emacs file. You will get an error (error
+;; "`c-lang-defconst' must be used in a file") which happens because
+;; cc-mode doesn't think it is in a buffer while loading directly
+;; from the init. However, if you call it based on a file extension,
+;; it works properly. Interestingly enough, this doesn't happen if
+;; you don't byte-compile cc-mode.
+;;
+;;
+;;
+;; Todo:
+;;
+;; Get csharp-mode.el accepted as part of the emacs standard distribution.
+;; Must contact monnier at iro.umontreal.ca to make this happen.
+;;
+;;
+;;
+;; Acknowledgements:
+;;
+;; Thanks to Alan Mackenzie and Stefan Monnier for answering questions
+;; and making suggestions. And to Trey Jackson for sharing his
+;; knowledge of emacs lisp.
+;;
+;;
+
+;;; Versions:
+;;
+;; 0.1.0 - Initial release.
+;; 0.2.0 - Fixed the identification on the "enum" keyword.
+;; - Fixed the font-lock on the "base" keyword
+;; 0.3.0 - Added a regex to fontify attributes. It isn't the
+;; the best method, but it handles single-like attributes
+;; well.
+;; - Got "super" not to fontify as a keyword.
+;; - Got extending classes and interfaces to fontify as something.
+;; 0.4.0 - Removed the attribute matching because it broke more than
+;; it fixed.
+;; - Corrected a bug with namespace not being properly identified
+;; and treating the class level as an inner object, which screwed
+;; up formatting.
+;; - Added "partial" to the keywords.
+;; 0.5.0 - Found bugs with compiled cc-mode and loading from init files.
+;; - Updated the eval-when-compile to code to let the mode be
+;; compiled.
+;; 0.6.0 - Added the c-filter-ops patch for 5.31.1 which made that
+;; function in cc-langs.el unavailable.
+;; - Added a csharp-lineup-region for indention #region and
+;; #endregion block differently.
+;; 0.7.0 - Added autoload so update-directory-autoloads works
+;; (Thank you, Nikolaj Schumacher)
+;; - Fontified the entire #region and #endregion lines.
+;; - Initial work to get get, set, add, remove font-locked.
+;; 0.7.1 - Added option to indent #if/endif with code
+;; - Fixed c-opt-cpp-prefix defn (it must not include the BOL
+;; char (^).
+;; - proper fontification and indent of classes that inherit
+;; (previously the colon was confusing the parser)
+;; - reclassified namespace as a block beginner
+;; - removed $ as a legal symbol char - not legal in C#.
+;; - added struct to c-class-decl-kwds so indent is correct
+;; within a struct.
+;; 0.7.2 - Added automatic codedoc insertion.
+;; 0.7.3 - Instance initializers (new Type { ... } ) and
+;; (new Type() { ...} ) are now indented properly.
+;; - proper fontification and indent of enums as brace-list-*,
+;; including special treatment for enums that explicitly
+;; inherit from an int type. Previously the colon was
+;; confusing the parser.
+;; - proper fontification of verbatim literal strings,
+;; including those that end in slash. This edge case was not
+;; handled at all before; it is now handled correctly.
+;; - code cleanup and organization; removed the linefeed.
+;; - intelligent curly-brace insertion
+;; 0.7.4 - added a C# style
+;; - using is now a keyword and gets fontified correctly
+;; - fixed a bug that had crept into the codedoc insertion
+;; 0.7.5 - now fontify namespaces in the using statements. This is
+;; done in the csharp value for c-basic-matchers-before .
+;; - also fontify the name following namespace decl.
+;; This is done in the csharp value for c-basic-matchers-after .
+;; - turn on recognition of generic types. They are now
+;; fontified correctly.
+;; - <> are now treated as syntactic parens and can be jumped
+;; over with c-forward-sexp.
+;; - Constructors are now fontified.
+;; - Field/Prop names inside object initializers are now fontified.
+;;
+
+
+;;
+
+
+(require 'cc-mode)
+
+(message (concat "Loading " load-file-name))
+
+
+;; ==================================================================
+;; c# upfront stuff
+;; ==================================================================
+
+;; This is a copy of the function in cc-mode which is used to handle
+;; the eval-when-compile which is needed during other times.
+(defun c-filter-ops (ops opgroup-filter op-filter &optional xlate)
+ ;; See cc-langs.el, a direct copy.
+ (unless (listp (car-safe ops))
+ (setq ops (list ops)))
+ (cond ((eq opgroup-filter t)
+ (setq opgroup-filter (lambda (opgroup) t)))
+ ((not (functionp opgroup-filter))
+ (setq opgroup-filter `(lambda (opgroup)
+ (memq opgroup ',opgroup-filter)))))
+ (cond ((eq op-filter t)
+ (setq op-filter (lambda (op) t)))
+ ((stringp op-filter)
+ (setq op-filter `(lambda (op)
+ (string-match ,op-filter op)))))
+ (unless xlate
+ (setq xlate 'identity))
+ (c-with-syntax-table (c-lang-const c-mode-syntax-table)
+ (delete-duplicates
+ (mapcan (lambda (opgroup)
+ (when (if (symbolp (car opgroup))
+ (when (funcall opgroup-filter (car opgroup))
+ (setq opgroup (cdr opgroup))
+ t)
+ t)
+ (mapcan (lambda (op)
+ (when (funcall op-filter op)
+ (let ((res (funcall xlate op)))
+ (if (listp res) res (list res)))))
+ opgroup)))
+ ops)
+ :test 'equal)))
+
+
+
+;; These are only required at compile time to get the sources for the
+;; language constants. (The cc-fonts require and the font-lock
+;; related constants could additionally be put inside an
+;; (eval-after-load "font-lock" ...) but then some trickery is
+;; necessary to get them compiled.)
+(eval-when-compile
+ (let ((load-path
+ (if (and (boundp 'byte-compile-dest-file)
+ (stringp byte-compile-dest-file))
+ (cons (file-name-directory byte-compile-dest-file) load-path)
+ load-path)))
+ (load "cc-mode" nil t)
+ (load "cc-fonts" nil t)
+ (load "cc-langs" nil t)))
+
+(eval-and-compile
+ ;; Make our mode known to the language constant system. Use Java
+ ;; mode as the fallback for the constants we don't change here.
+ ;; This needs to be done also at compile time since the language
+ ;; constants are evaluated then.
+ (c-add-language 'csharp-mode 'java-mode))
+
+;; ==================================================================
+;; end of c# upfront stuff
+;; ==================================================================
+
+
+
+
+
+;; ==================================================================
+;; csharp-mode utility and feature defuns
+;; ==================================================================
+
+;; Indention: csharp-mode follows normal indention rules except for
+;; when indenting the #region and #endregion blocks. This function
+;; defines a custom indention to indent the #region blocks properly
+;;
+
+
+(defun csharp-at-vsemi-p (&optional pos)
+ "Determines if there is a virtual semicolon at POS or point.
+This is the C# version of the function.
+
+A vsemi is a cc-mode concept implying end-of-statement, without
+a semicolon or close-brace. This happens in C# with an
+attribute decorating a class, method, field, or property.
+Providing this function allows the indenting in csharp-mode
+to work properly with syntax items that follow attributes.
+
+Returns t if at the end of a attribute. Otherwise nil.
+"
+ (save-excursion
+ (let ((pos-or-point (progn (if pos (goto-char pos)) (point))))
+
+ (if (and (c-safe (backward-sexp) t)
+ (re-search-forward
+ (concat
+ "\\(\\["
+ "[ \t\n\r\f\v]*"
+ "\\("
+ "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
+ "[A-Za-z_][[:alnum:]]*"
+ "\\)"
+ "[^]]*\\]\\)"
+ )
+ (1+ pos-or-point) t))
+
+ (progn
+ (c-safe (backward-sexp))
+ (c-backward-syntactic-ws)
+ (cond
+
+ ((eq (char-before) 93) ;; close sq brace
+ (csharp-at-vsemi-p (point)))
+
+ ((or
+ (eq (char-before) 59) ;; semicolon
+ (eq (char-before) 123) ;; open curly
+ (eq (char-before) 125)) ;; close curly
+ t)
+
+ (t nil)))))))
+
+
+(defun csharp-lineup-region (langelem)
+ "Indent all #region and #endregion blocks inline with code while
+retaining normal column-zero indention for #if and the other
+processing blocks.
+
+To use this indenting just put the following in your emacs file:
+ (c-set-offset 'cpp-macro 'csharp-lineup-region)
+
+An alternative is to use `csharp-lineup-if-and-region'.
+"
+
+ (save-excursion
+ (back-to-indentation)
+ (if (re-search-forward "#\\(end\\)?region" (c-point 'eol) [0]) 0 [0])))
+
+
+
+(defun csharp-lineup-if-and-region (langelem)
+
+"Indent all #region/endregion blocks and #if/endif blocks inline
+with code while retaining normal column-zero indention for any
+other processing blocks.
+
+To use this indenting just put the following in your emacs file:
+ (c-set-offset 'cpp-macro 'csharp-lineup-if-and-region)
+
+Another option is to use `csharp-lineup-region'.
+
+"
+ (save-excursion
+ (back-to-indentation)
+ (if (re-search-forward "#\\(\\(end\\)?\\(if\\|region\\)\\|else\\)"
(c-point 'eol) [0]) 0 [0])))
+
+
+
+
+
+(defun csharp-insert-open-brace ()
+ "Intelligently insert a pair of curly braces. This fn is most
+often bound to the open-curly brace, with
+
+ (local-set-key (kbd \"{\") 'csharp-insert-open-brace)
+
+The default binding for an open curly brace in cc-modes is often
+`c-electric-brace' or `skeleton-pair-insert-maybe'. The former
+can be configured to insert newlines around braces in various
+syntactic positions. The latter inserts a pair of braces and
+then does not insert a newline, and does not indent.
+
+This fn provides another option, with some additional
+intelligence for csharp-mode. When you type an open curly, the
+appropriate pair of braces appears, with spacing and indent set
+in a context-sensitive manner.
+
+Within a string literal, you just get a pair of braces, and point
+is set between them. Following an equals sign, you get a pair of
+braces, with a semincolon appended. Otherwise, you
+get the open brace on a new line, with the closing brace on the
+line following.
+
+There may be another way to get this to happen appropriately just within emacs,
+but I could not figure out how to do it. So I wrote this alternative.
+"
+ (interactive)
+ (let
+ (tpoint
+ (in-string (string= (csharp-in-literal) "string"))
+ (preceding3
+ (save-excursion
+ (and
+ (skip-chars-backward " ")
+ (> (- (point) 2) (point-min))
+ (buffer-substring-no-properties (point) (- (point) 3)))))
+ (one-word-back
+ (save-excursion
+ (backward-word 2)
+ (thing-at-point 'word))))
+
+ (cond
+
+ ;; Case 1: inside a string literal?
+ ;; --------------------------------------------
+ ;; If so, then just insert a pair of braces and put the point
+ ;; between them. The most common case is a format string for
+ ;; String.Format() or Console.WriteLine().
+ (in-string
+ (self-insert-command 1)
+ (insert "}")
+ (backward-char))
+
+ ;; Case 2: the open brace starts an array initializer.
+ ;; --------------------------------------------
+ ;; When the last non-space was an equals sign or square brackets,
+ ;; then it's an initializer.
+ ((save-excursion
+ (and (c-safe (backward-sexp) t)
+ (looking-at "\\(\\w+\\b *=\\|[[]]+\\)")))
+ (self-insert-command 1)
+ (insert " };")
+ (backward-char 3))
+
+ ;; Case 3: the open brace starts an instance initializer
+ ;; --------------------------------------------
+ ;; If one-word-back was "new", then it's an object initializer.
+ ((string= one-word-back "new")
+ (save-excursion
+ (message "object initializer")
+ (setq tpoint (point)) ;; prepare to indent-region later
+ (newline)
+ (self-insert-command 1)
+ (newline-and-indent)
+ (newline)
+ (insert "};")
+ (c-indent-region tpoint (point))
+ (previous-line)
+ (indent-according-to-mode)
+ (end-of-line)
+ (setq tpoint (point)))
+ (goto-char tpoint))
+
+ ;; Case 4: a lambda initialier.
+ ;; --------------------------------------------
+ ;; If the open curly follows =>, then it's a lambda initializer.
+ ((string= (substring preceding3 -2) "=>")
+ (message "lambda init")
+ (self-insert-command 1)
+ (insert " }")
+ (backward-char 2))
+
+ ;; else, it's a new scope. (if, while, class, etc)
+ (t
+ (save-excursion
+ (message "new scope")
+ (set-mark (point)) ;; prepare to indent-region later
+ ;; check if the prior sexp is on the same line
+ (if (save-excursion
+ (let ((curline (line-number-at-pos))
+ (aftline (progn
+ (if (c-safe (backward-sexp) t)
+ (line-number-at-pos)
+ -1))))
+ (= curline aftline)))
+ (newline-and-indent))
+ (self-insert-command 1)
+ (c-indent-line-or-region)
+ (end-of-line)
+ (newline)
+ (insert "}")
+ ;;(c-indent-command) ;; not sure of the difference here
+ (c-indent-line-or-region)
+ (previous-line)
+ (end-of-line)
+ (newline-and-indent)
+ ;; point ends up on an empty line, within the braces, properly indented
+ (setq tpoint (point)))
+
+ (goto-char tpoint)))))
+
+
+;; ==================================================================
+;; end of csharp-mode utility and feature defuns
+;; ==================================================================
+
+
+
+
+
+
+;; ==================================================================
+;; c# values for "language constants" defined in cc-langs.el
+;; ==================================================================
+
+
+;; Java uses a series of regexes to change the font-lock for class
+;; references. The problem comes in because Java uses Pascal (leading
+;; space in names, SomeClass) for class and package names, but
+;; Camel-casing (initial lowercase, upper case in words,
+;; i.e. someVariable) for variables. The notation suggested by EMCA for C# is
+;; to use Pascal notation for everything, except inner variables. So,
+;; the Java regex and formatting produces very wrong results in C#.
+;;(error (byte-compile-dest-file))
+;;(error (c-get-current-file))
+
+
+
+(defconst csharp-enum-decl-re
+ (concat
+ "\\<enum[ \t\n\r\f\v]+"
+ "\\([[:alpha:]_][[:alnum:]_]*\\)"
+ "[ \t\n\r\f\v]*"
+ "\\(:[ \t\n\r\f\v]*"
+ "\\("
+ (c-make-keywords-re nil
+ (list "sbyte" "byte" "short" "ushort" "int" "uint" "long" "ulong"))
+ "\\)"
+ "\\)?")
+ "Regex that captures an enum declaration in C#"
+ )
+
+
+
+;; X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+
+
+
+(c-lang-defconst c-at-vsemi-p-fn
+ csharp 'csharp-at-vsemi-p)
+
+
+;; This c-opt-after-id-concat-key is a regexp that matches
+;; dot. In other words: "\\(\\.\\)"
+;; Not sure why this needs to be so complicated.
+;; This const is now internal (obsolete); need to move to
+;; c-after-id-concat-ops. I don't yet understand the meaning
+;; of that variable, so for now. . . .
+(c-lang-defconst c-opt-after-id-concat-key
+ csharp (if (c-lang-const c-opt-identifier-concat-key)
+ (c-lang-const c-symbol-start)))
+
+
+
+;; The matchers elements can be of many forms. It gets pretty
+;; complicated. do a describe-variable on font-lock-keywords to get a
+;; description. (Why on font-lock-keywords? I don't know, but that's
+;; where you get the help.)
+;;
+;; Aside from documentation, the other option of course, is to use
+;; the source code. Look in the source to see what to do. The
+;; source in cc-fonts uses a defun c-make-font-lock-search-function
+;; to produce most of the matchers. Called this way:
+;;
+;; (c-make-font-lock-search-function regexp '(A B c))
+;;
+;; The REGEXP is used in re-search-forward, and if there's a match, the
+;; A B and C are three forms that are called in a weird combination.
+;;
+;; Anyway the c-make-font-lock-search-function works for a single regex,
+;; but more complicated scenarios such as those intended to match and
+;; fontify object initializers, call for a hand-crafted lambda.
+;;
+;; The object initializer is special because, matching on it must
+;; allow nesting.
+;;
+;; In c#, the object initializer block is used directly after a
+;; constructor, like this:
+;;
+;; new MyType {
+;; Prop1 = "foo"
+;; }
+;;
+;; sharp-mode needs to fontify the properties in the
+;; initializer block in font-lock-variable-name-face. The key thing is
+;; to set the text property on the open curly, using type c-type and
+;; value c-decl-id-start. This apparently allows parse-partial-sexp to
+;; do the right thing, later.
+;;
+;; This simple case is easy to handle in a regex, using the basic
+;; c-make-font-lock-search-function form. But the general syntax for a
+;; constructor + object initializer in C# is more complex:
+;;
+;; new MyType(..arglist..) {
+;; Prop1 = "foo"
+;; }
+;;
+;; A simple regex match won't satisfy here, because the ..arglist.. can
+;; be anything, including calls to other constructors, potentially with
+;; object initializer blocks. This may nest arbitrarily deeply, and the
+;; regex in emacs doesn't support balanced matching. Therefore there's
+;; no way to match on the "outside" pair of parens, to find the relevant
+;; open curly. What's necessary is to do the match on "new MyType" then
+;; skip over the sexp defined by the parens, then set the text property on
+;; the appropriate open-curly.
+;;
+;; To make that happen I needed insight into what the matcher really
+;; ought to be doin. The output of c-make-font-lock-search-function
+;; before byte-compiling, is:
+;;
+;; (lambda (limit)
+;; (let ((parse-sexp-lookup-properties
+;; (cc-eval-when-compile
+;; (boundp 'parse-sexp-lookup-properties))))
+;; (while (re-search-forward REGEX limit t)
+;; (unless
+;; (progn
+;; (goto-char (match-beginning 0))
+;; (c-skip-comments-and-strings limit))
+;; (goto-char (match-end 0))
+;; (progn
+;; B
+;; (save-match-data A)
+;; C ))))
+;; nil)
+;;
+;; csharp-mode uses this hand-crafted form of a matcher to handle the
+;; general case for constructor + object initializer, within
+;; `c-basic-matchers-after' .
+;;
+
+
+
+
+;; (defun c-make-font-lock-search-function (regexp &rest highlights)
+;; ;; This function makes a byte compiled function that works much like
+;; ;; a matcher element in `font-lock-keywords'. It cuts out a little
+;; ;; bit of the overhead compared to a real matcher. The main reason
+;; ;; is however to pass the real search limit to the anchored
+;; ;; matcher(s), since most (if not all) font-lock implementations
+;; ;; arbitrarily limits anchored matchers to the same line, and also
+;; ;; to insulate against various other irritating differences between
+;; ;; the different (X)Emacs font-lock packages.
+;; ;;
+;; ;; REGEXP is the matcher, which must be a regexp. Only matches
+;; ;; where the beginning is outside any comment or string literal are
+;; ;; significant.
+;; ;;
+;; ;; HIGHLIGHTS is a list of highlight specs, just like in
+;; ;; `font-lock-keywords', with these limitations: The face is always
+;; ;; overridden (no big disadvantage, since hits in comments etc are
+;; ;; filtered anyway), there is no "laxmatch", and an anchored matcher
+;; ;; is always a form which must do all the fontification directly.
+;; ;; `limit' is a variable bound to the real limit in the context of
+;; ;; the anchored matcher forms.
+;; ;;
+;; ;; This function does not do any hidden buffer changes, but the
+;; ;; generated functions will. (They are however used in places
+;; ;; covered by the font-lock context.)
+;;
+;; ;; Note: Replace `byte-compile' with `eval' to debug the generated
+;; ;; lambda easier.
+;; (byte-compile
+;; `(lambda (limit)
+;; (let (;; The font-lock package in Emacs is known to clobber
+;; ;; `parse-sexp-lookup-properties' (when it exists).
+;; (parse-sexp-lookup-properties
+;; (cc-eval-when-compile
+;; (boundp 'parse-sexp-lookup-properties))))
+;; (while (re-search-forward ,regexp limit t)
+;; (unless (progn
+;; (goto-char (match-beginning 0))
+;; (c-skip-comments-and-strings limit))
+;; (goto-char (match-end 0))
+;; ,@(mapcar
+;; (lambda (highlight)
+;; (if (integerp (car highlight))
+;; (progn
+;; (unless (eq (nth 2 highlight) t)
+;; (error
+;; "The override flag must currently be t in %s"
+;; highlight))
+;; (when (nth 3 highlight)
+;; (error
+;; "The laxmatch flag may currently not be set in
%s"
+;; highlight))
+;; `(save-match-data
+;; (c-put-font-lock-face
+;; (match-beginning ,(car highlight))
+;; (match-end ,(car highlight))
+;; ,(elt highlight 1))))
+;; (when (nth 3 highlight)
+;; (error "Match highlights currently not supported in
%s"
+;; highlight))
+;; `(progn
+;; ,(nth 1 highlight)
+;; (save-match-data ,(car highlight))
+;; ,(nth 2 highlight))))
+;; highlights))))
+;; nil))
+;; )
+
+
+(c-lang-defconst c-basic-matchers-before
+ csharp `(
+ ;;;; Font-lock the attributes by searching for the
+ ;;;; appropriate regex and marking it as TODO.
+ ;;,`(,(concat "\\(" csharp-attribute-regex "\\)")
+ ;; 0 font-lock-function-name-face)
+
+ ;; Put a warning face on the opener of unclosed strings that
+ ;; can't span lines. Later font
+ ;; lock packages have a `font-lock-syntactic-face-function' for
+ ;; this, but it doesn't give the control we want since any
+ ;; fontification done inside the function will be
+ ;; unconditionally overridden.
+ ,(c-make-font-lock-search-function
+ ;; Match a char before the string starter to make
+ ;; `c-skip-comments-and-strings' work correctly.
+ (concat ".\\(" c-string-limit-regexp "\\)")
+ '((c-font-lock-invalid-string)))
+
+
+ ;; Fontify 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)))))
+
+
+ ;; Fontify the namespaces that follow using statements.
+ ;; This regex handles the optional alias, but does not fontify it.
+
,`("\\<\\(using\\)\s+\\(?:[A-Za-z_][[:alnum:]]*\s*=\s*\\)?\\(\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*[A-Za-z_][[:alnum:]]*\\)\s*;"
+ 2 font-lock-constant-face)
+
+
+ ;; Fontify all keywords except the primitive types.
+ ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp))
+ 1 font-lock-keyword-face)
+
+
+ ;; Fontify leading identifiers in fully qualified names like
+ ;; "Foo.Bar".
+ ,@(when (c-lang-const c-opt-identifier-concat-key)
+ `((,(byte-compile
+ `(lambda (limit)
+ (while (re-search-forward
+ ,(concat "\\(\\<" ; 1
+ "\\(" (c-lang-const c-symbol-key)
+ "\\)" ; 2
+ "[ \t\n\r\f\v]*"
+ (c-lang-const
+ c-opt-identifier-concat-key)
+ "[ \t\n\r\f\v]+"
+ "\\)"
+ "\\("
+ (c-lang-const
+ c-opt-after-id-concat-key)
+ "\\)")
+ limit t)
+ (unless (progn
+ (goto-char (match-beginning 0))
+ (c-skip-comments-and-strings limit))
+ (or (get-text-property (match-beginning 2) 'face)
+ (c-put-font-lock-face (match-beginning 2)
+ (match-end 2)
+ c-reference-face-name))
+ (goto-char (match-end 1)))))))))
+
+ ))
+
+
+
+(c-lang-defconst c-basic-matchers-after
+ csharp `(
+
+ ;; option 1:
+ ;; ,@(when t
+ ;; `((,(byte-compile
+ ;; `(lambda (limit) ...
+
+ ;; option 2:
+ ;; ,`((lambda (limit) ...
+
+
+ ;; Case 1: invocation of constructor + maybe an object initializer
+ ,@(when t
+ `((,(byte-compile
+ `(lambda (limit)
+ (let ((parse-sexp-lookup-properties
+ (cc-eval-when-compile
+ (boundp 'parse-sexp-lookup-properties))))
+
+ (while (re-search-forward
+ ,(concat "\\<new"
+ "[ \t\n\r\f\v]+"
+ "\\(\\(?:"
+ (c-lang-const c-symbol-key)
+ "\\.\\)*"
+ (c-lang-const c-symbol-key)
+ "\\)"
+ )
+ limit t)
+ (unless
+ (progn
+ (goto-char (match-beginning 0))
+ (c-skip-comments-and-strings limit))
+
+ (csharp-log 3 "ctor candidate at %d"
(match-beginning 1))
+
+ (save-match-data
+ ;; next thing could be: [] () <> or {} or
nothing (semicolon, comma).
+
+ ;; fontify the typename
+ (c-put-font-lock-face (match-beginning 1)
+ (match-end 1)
+ 'font-lock-type-face)
+
+ (goto-char (match-end 0))
+ (c-forward-syntactic-ws)
+ (if (eq (char-after) ?<) ;; ctor for generic
type
+ (progn
+ (csharp-log 3 " - generic ctor")
+ ;; skip over <> safely
+ (c-safe (c-forward-sexp 1) t)
+ (c-forward-syntactic-ws)))
+
+ ;; now, could be [] or (..) or {..} or
semicolon.
+
+ (csharp-log 3 " - looking for sexp")
+
+ (if (or
+ (eq (char-after) ?{) ;; open curly
+ (and (eq (char-after) 91) ;; open square
+ (while (eq (char-after) 91)
+ (c-safe (c-forward-sexp 1)))
+ (eq (char-before) 93)) ;; close
square
+ (and (eq (char-after) 40) ;; open paren
+ (c-safe (c-forward-sexp 1) t)))
+
+ (progn
+ ;; at this point we've jumped over any
intervening s-exp
+ (c-forward-syntactic-ws)
+ (csharp-log 3 " - after fwd-syn-ws
point(%d)" (point))
+ (csharp-log 3 " - next char: %c"
(char-after))
+ (if (eq (char-after) ?{)
+ (let ((start (point))
+ (end (if (c-safe
(c-forward-sexp 1) t)
+ (point) 0)))
+ (csharp-log 3 " - put
c-decl-id-start on the open-curly at %d" start)
+ (c-put-char-property start
+ 'c-type
+
'c-decl-id-start)
+ (goto-char start)
+ (if (> end start)
+ (progn
+ (forward-char 1) ;; step
over open curly
+ (c-forward-syntactic-ws)
+ (while (> end (point))
+ ;; now, try to
fontify/assign variables to any properties inside the curlies
+ (csharp-log 3 " - inside
open curly point(%d)" (point))
+ (csharp-log 3 " - next
char: %c" (char-after))
+ ;; fontify each property
assignment
+ (if (re-search-forward
+ (concat "\\("
(c-lang-const c-symbol-key) "\\)\s*=")
+ end t)
+ (progn
+ (csharp-log 3 " -
found variable %d-%d"
+
(match-beginning 1)
+
(match-end 1))
+
(c-put-font-lock-face (match-beginning 1)
+
(match-end 1)
+
'font-lock-variable-name-face)
+ (goto-char
(match-end 0))
+
(c-forward-syntactic-ws)
+ ;; advance to the
next assignment, if possible
+ (if (eq (char-after)
?@)
+ (forward-char 1))
+
+ (if (c-safe
(c-forward-sexp 1) t)
+ (progn
+ (forward-char
1)
+
(c-forward-syntactic-ws))))
+
+ ;; else
+ (csharp-log 3 " - no
more assgnmts found")
+ (goto-char end)))))
+ )))))
+
+ (goto-char (match-end 0))
+ )))
+ nil))
+ )))
+
+
+ ;; Case 2: declaration of enum with or without an explicit base type
+ ,@(when t
+ `((,(byte-compile
+ `(lambda (limit)
+ (let ((parse-sexp-lookup-properties
+ (cc-eval-when-compile
+ (boundp 'parse-sexp-lookup-properties))))
+ (while (re-search-forward
+ ,(concat csharp-enum-decl-re
+ "[ \t\n\r\f\v]*"
+ "{")
+ limit t)
+
+ (csharp-log 3 "enum candidate at %d"
(match-beginning 0))
+
+ (unless
+ (progn
+ (goto-char (match-beginning 0))
+ (c-skip-comments-and-strings limit))
+ (progn
+ (save-match-data
+ (goto-char (match-end 0))
+ (c-put-char-property (1- (point))
+ 'c-type
+ 'c-decl-id-start)
+ (c-forward-syntactic-ws))
+ (save-match-data
+ (c-font-lock-declarators limit t nil))
+ (goto-char (match-end 0))
+ )
+ )))
+ nil))
+ )))
+
+
+ ;; Case 3: declaration of constructor
+ ,@(when t
+ `((,(byte-compile
+ `(lambda (limit)
+ (let ((parse-sexp-lookup-properties
+ (cc-eval-when-compile
+ (boundp 'parse-sexp-lookup-properties)))
+ (found-it nil))
+ (while (re-search-forward
+ ,(concat
+ "^[ \t\n\r\f\v]*"
+
"\\(\\<\\(public\\|private\\|protected\\)\\)?[ \t\n\r\f\v]+"
+ "\\(@?[[:alpha:]_][[:alnum:]_]*\\)" ;; name
of constructor
+ "[ \t\n\r\f\v]*"
+ "\\("
+ "("
+ "\\)")
+ limit t)
+ (unless
+ (progn
+ (goto-char (match-beginning 0))
+ (c-skip-comments-and-strings limit))
+
+ (goto-char (match-end 0))
+
+ (csharp-log 3 "ctor decl candidate ending at %d"
(point))
+
+ (backward-char 1) ;; just left of the open paren
+ (save-match-data
+ ;; Jump over the parens, safely.
+ ;; If it's an unbalanced paren, no problem,
+ ;; do nothing.
+ (if (c-safe (c-forward-sexp 1) t)
+ (progn
+ (c-forward-syntactic-ws)
+ (cond
+
+ ;; invokes base or this constructor.
+ ((re-search-forward
+ ,(concat
+ "\\(:[
\t\n\r\f\v]*\\(base\\|this\\)\\)"
+ "[ \t\n\r\f\v]*"
+ "("
+ )
+ limit t)
+ (csharp-log 3 " - ctor with
dependency?")
+
+ (goto-char (match-end 0))
+ (backward-char 1) ;; just left of the
open paren
+ (csharp-log 3 " - before paren at %d"
(point))
+
+ (if (c-safe (c-forward-sexp 1) t)
+ (progn
+ (c-forward-syntactic-ws)
+ (csharp-log 3 " - skipped over
paren pair %d" (point))
+ (if (eq (char-after) ?{)
+ (setq found-it t)))))
+
+ ;; open curly. no depedency on other
ctor.
+ ((eq (char-after) ?{)
+ (csharp-log 3 " - ctor with no
dependency? at %d" (point))
+ (setq found-it t)))
+
+ )))
+
+ (if found-it
+ ;; fontify the constructor symbol
+ (c-put-font-lock-face (match-beginning 3)
+ (match-end 3)
+
'font-lock-function-name-face))
+ (goto-char (match-end 0))
+ )
+ ))
+ nil))
+ )))
+
+
+ ;; Case 4: using clause. Without this, using (..) gets fontified as
a fn.
+ ,@(when t
+ `((,(byte-compile
+ `(lambda (limit)
+ (let ((parse-sexp-lookup-properties
+ (cc-eval-when-compile
+ (boundp 'parse-sexp-lookup-properties))))
+ (while (re-search-forward
+ ,(concat "\\<\\(using\\)"
+ "[ \t\n\r\f\v]*"
+ "(")
+ limit t)
+
+ (csharp-log 3 "using clause at %d" (match-beginning
0))
+
+ (unless
+ (progn
+ (goto-char (match-beginning 0))
+ (c-skip-comments-and-strings limit))
+
+ (save-match-data
+ (c-put-font-lock-face (match-beginning 1)
+ (match-end 1)
+ 'font-lock-keyword-face)
+ (goto-char (match-end 0))))))
+ nil))
+ )))
+
+ ;; Case 5: attributes
+ ,`((lambda (limit)
+ (let ((parse-sexp-lookup-properties
+ (cc-eval-when-compile
+ (boundp 'parse-sexp-lookup-properties))))
+
+ (while (re-search-forward
+ ,(concat "[ \t\n\r\f\v]+"
+ "\\(\\["
+ "[ \t\n\r\f\v]*"
+ "\\(?:\\(?:return\\|assembly\\)[ \t]*:[
\t]*\\)?"
+ "\\("
+ "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
+ "[A-Za-z_][[:alnum:]]*"
+ "\\)"
+ "[^]]*\\]\\)"
+ )
+ limit t)
+
+ (csharp-log 3 "attribute? - %d limit(%d)" (match-beginning
1)
+ limit)
+
+ (unless
+ (progn
+ (goto-char (match-beginning 1))
+ (c-skip-comments-and-strings limit))
+
+ (let ((b2 (match-beginning 2))
+ (e2 (match-end 2))
+ (is-attr nil))
+ (csharp-log 3 " - type match: %d - %d"
+ b2 e2)
+ (save-match-data
+ (c-backward-syntactic-ws)
+ (setq is-attr (or
+ (eq (char-before) 59) ;; semicolon
+ (eq (char-before) 93) ;; close square
brace
+ (eq (char-before) 123) ;; open curly
+ (eq (char-before) 125) ;; close curly
+ (save-excursion
+ (c-beginning-of-statement-1)
+ (looking-at
+
"#\\(pragma\\|endregion\\|region\\|if\\|else\\|endif\\)"))
+ )))
+
+ (if is-attr
+ (progn
+ (csharp-log 3 " - attribute seems likely. type:
%d - %d"
+ b2 e2)
+ (c-put-font-lock-face b2 e2
'font-lock-type-face)))))
+ (goto-char (match-end 0))
+ ))
+ nil))
+
+
+;; ;; Case 5: #if
+;; ,@(when t
+;; `((,(byte-compile
+;; `(lambda (limit)
+;; (let ((parse-sexp-lookup-properties
+;; (cc-eval-when-compile
+;; (boundp 'parse-sexp-lookup-properties))))
+;; (while (re-search-forward
+;; "\\<\\(#if\\)[
\t\n\r\f\v]+\\([A-Za-z_][[:alnum:]]*\\)"
+;; limit t)
+;;
+;; (csharp-log 3 "#if directive - %d"
(match-beginning 1))
+;;
+;; (unless
+;; (progn
+;; (goto-char (match-beginning 0))
+;; (c-skip-comments-and-strings limit))
+;;
+;; (save-match-data
+;; (c-put-font-lock-face (match-beginning 2)
+;; (match-end 2)
+;;
'font-lock-variable-name-face)
+;; (goto-char (match-end 0))))))
+;; nil))
+;; )))
+
+
+ ;; ,`(,(c-make-font-lock-search-function
+ ;; (concat "\\<new"
+ ;; "[ \t\n\r\f\v]+"
+ ;; "\\(\\(?:"
+ ;; (c-lang-const c-symbol-key)
+ ;; "\\.\\)*"
+ ;; (c-lang-const c-symbol-key)
+ ;; "\\)"
+ ;; "[ \t\n\r\f\v]*"
+ ;; "\\(?:"
+ ;; "( *)[ \t\n\r\f\v]*" ;; optional ()
+ ;; "\\)?"
+ ;; "{")
+ ;; '((c-font-lock-declarators limit t nil)
+ ;; (save-match-data
+ ;; (goto-char (match-end 0))
+ ;; (c-put-char-property (1- (point)) 'c-type
+ ;; 'c-decl-id-start)
+ ;; (c-forward-syntactic-ws))
+ ;; (goto-char (match-end 0)))))
+
+
+
+
+ ;; Fontify labels after goto etc.
+ ,@(when (c-lang-const c-before-label-kwds)
+ `( ;; (Got three different interpretation levels here,
+ ;; which makes it a bit complicated: 1) The backquote
+ ;; stuff is expanded when compiled or loaded, 2) the
+ ;; eval form is evaluated at font-lock setup (to
+ ;; substitute c-label-face-name correctly), and 3) the
+ ;; resulting structure is interpreted during
+ ;; fontification.)
+ (eval
+ . ,(let* ((c-before-label-re
+ (c-make-keywords-re nil
+ (c-lang-const c-before-label-kwds))))
+ `(list
+ ,(concat "\\<\\(" c-before-label-re "\\)\\>"
+ "\\s *"
+ "\\(" ; identifier-offset
+ (c-lang-const c-symbol-key)
+ "\\)")
+ (list ,(+ (regexp-opt-depth c-before-label-re) 2)
+ c-label-face-name nil t))))))
+
+
+
+ ;; Fontify the clauses after various keywords.
+ ,@(when (or (c-lang-const c-type-list-kwds)
+ (c-lang-const c-ref-list-kwds)
+ (c-lang-const c-colon-type-list-kwds)
+ (c-lang-const c-paren-type-kwds))
+ `((,(c-make-font-lock-search-function
+ (concat "\\<\\("
+ (c-make-keywords-re nil
+ (append (c-lang-const c-type-list-kwds)
+ (c-lang-const c-ref-list-kwds)
+ (c-lang-const c-colon-type-list-kwds)
+ (c-lang-const c-paren-type-kwds)))
+ "\\)\\>")
+ '((c-fontify-types-and-refs ((c-promote-possible-types t))
+ (c-forward-keyword-clause 1)
+ (if (> (point) limit) (goto-char limit))))))))
+
+
+ ;; Fontify the name that follows each namespace declaration
+ ;; this needs to be done in the matchers-after because
+ ;; otherwise the namespace names get the font-lock-type-face,
+ ;; due to the energetic efforts of c-forward-type.
+ ,`("\\<\\(namespace\\)[
\t\n\r\f\v]+\\(\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*[A-Za-z_][[:alnum:]]*\\)"
+ 2 font-lock-constant-face t)
+
+
+ ))
+
+
+;; C# does generics. Setting this to t tells the parser to put
+;; parenthesis syntax on angle braces that surround a comma-separated
+;; list.
+(c-lang-defconst c-recognize-<>-arglists
+ csharp t)
+
+
+
+(c-lang-defconst c-identifier-key
+ csharp (concat "\\([[:alpha:]_][[:alnum:]_]*\\)" ; 1
+ "\\("
+ "[ \t\n\r\f\v]*"
+ "\\(\\.\\)" ;;(c-lang-const
c-opt-identifier-concat-key)
+ "[ \t\n\r\f\v]*"
+ "\\(\\([[:alpha:]_][[:alnum:]_]*\\)\\)"
+ "\\)*"))
+
+;; C# has a few rules that are slightly different than Java for
+;; operators. This also removed the Java's "super" and replaces it
+;; with the C#'s "base".
+(c-lang-defconst c-operators
+ csharp `((prefix "base")))
+
+
+;; C# uses CPP-like prefixes to mark #define, #region/endregion,
+;; #if/else/endif, and #pragma. This regexp matches the prefix,
+;; not including the beginning-of-line (BOL), and not including
+;; the term after the prefix (define, pragma, etc). This regexp says
+;; whitespace, followed by the prefix, followed by maybe more whitespace.
+
+(c-lang-defconst c-opt-cpp-prefix
+ csharp "\\s *#\\s *")
+
+
+;; there are no message directives in C#
+(c-lang-defconst c-cpp-message-directives
+ csharp nil)
+
+(c-lang-defconst c-cpp-expr-directives
+ csharp '("if"))
+
+(c-lang-defconst c-opt-cpp-macro-define
+ csharp "define")
+
+;; $ is not a legal char in an identifier in C#. So we need to
+;; create a csharp-specific definition of this constant.
+(c-lang-defconst c-symbol-chars
+ csharp (concat c-alnum "_"))
+
+
+(c-lang-defconst c-colon-type-list-kwds
+ csharp '("class"))
+
+(c-lang-defconst c-block-prefix-disallowed-chars
+
+ ;; Allow ':' for inherit list starters.
+ csharp (set-difference (c-lang-const c-block-prefix-disallowed-chars)
+ '(?: ?,)))
+
+
+(c-lang-defconst c-assignment-operators
+ csharp '("=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|="))
+
+(c-lang-defconst c-primitive-type-kwds
+ ;; ECMA-344, S8
+ csharp '("object" "string" "sbyte" "short" "int" "long" "byte"
+ "ushort" "uint" "ulong" "float" "double" "bool" "char"
+ "decimal" "void"))
+
+;; The keywords that define that the following is a type, such as a
+;; class definition.
+(c-lang-defconst c-type-prefix-kwds
+ ;; ECMA-344, S?
+ csharp '("class" "interface" "struct")) ;; no enum here.
+ ;; we want enum to be a brace list.
+
+
+;; Type modifier keywords. They appear anywhere in types, but modify
+;; instead of create one.
+(c-lang-defconst c-type-modifier-kwds
+ ;; EMCA-344, S?
+ csharp '("readonly" "const"))
+
+
+;; Tue, 20 Apr 2010 16:02
+;; need to verify that this works for lambdas...
+(c-lang-defconst c-special-brace-lists
+ csharp '((?{ . ?}) ))
+
+
+
+;; dinoch
+;; Thu, 22 Apr 2010 18:54
+;;
+;; No idea why this isn't getting set properly in the first place.
+;; In cc-langs.el, it is set to the union of a bunch of things, none
+;; of which include "new", or "enum".
+;;
+;; But somehow both of those show up in the resulting derived regexp.
+;; This breaks indentation of instance initializers, such as
+;;
+;; var x = new Foo { ... };
+;;
+;; Based on my inspection, the existing c-lang-defconst should work!
+;; I don't know how to fix this c-lang-defconst, so I am re-setting this
+;; variable here, to provide the regex explicitly.
+;;
+(c-lang-defconst c-decl-block-key
+
+ csharp
'"\\(namespace\\)\\([^[:alnum:]_]\\|$\\)\\|\\(class\\|interface\\|struct\\)\\([^[:alnum:]_]\\|$\\)"
+ )
+
+
+
+;; Thu, 22 Apr 2010 14:29
+;; I want this to handle var x = new Foo[] { ... };
+;; not sure if necessary.
+(c-lang-defconst c-inexpr-brace-list-kwds
+ csharp '("new"))
+
+
+;; ;;(c-lang-defconst c-inexpr-class-kwds
+;; ;; csharp '("new"))
+
+
+
+(c-lang-defconst c-class-decl-kwds
+ ;; EMCA-344, S?
+ csharp '("class" "interface" "struct" )) ;; no "enum"!!
+
+
+;; The various modifiers used for class and method descriptions.
+(c-lang-defconst c-modifier-kwds
+ csharp '("public" "partial" "private" "const" "abstract"
+ "protected" "ref" "out" "static" "virtual"
+ "override" "params" "internal"))
+
+
+;; Thu, 22 Apr 2010 23:02
+;; Based on inspection of the cc-mode code, the c-protection-kwds
+;; c-lang-const is used only for objective-c. So the value is
+;; irrelevant for csharp.
+(c-lang-defconst c-protection-kwds
+ csharp nil
+ ;; csharp '("private" "protected" "public" "internal")
+)
+
+
+;; Define the keywords that can have something following after them.
+(c-lang-defconst c-type-list-kwds
+ csharp '("struct" "class" "interface" "is" "as"
+ "delegate" "event" "set" "get" "add" "remove"))
+
+
+;; This allows the classes after the : in the class declartion to be
+;; fontified.
+(c-lang-defconst c-typeless-decl-kwds
+ csharp '(":"))
+
+;; Sets up the enum to handle the list properly, and also the new
+;; keyword to handle object initializers. This requires a modified
+;; c-basic-matchers-after (see above) in order to correctly fontify C#
+;; 3.0 object initializers.
+(c-lang-defconst c-brace-list-decl-kwds
+ csharp '("enum" "new"))
+
+
+;; Statement keywords followed directly by a substatement.
+;; catch is not one of them.
+(c-lang-defconst c-block-stmt-1-kwds
+ csharp '("do" "try" "finally"))
+
+
+;; Statement keywords followed by a paren sexp and then by a substatement.
+(c-lang-defconst c-block-stmt-2-kwds
+ csharp '("for" "if" "switch" "while" "catch" "foreach" "using"
+ "checked" "unchecked" "lock"))
+
+
+;; Statements that break out of braces
+(c-lang-defconst c-simple-stmt-kwds
+ csharp '("return" "continue" "break" "throw" "goto" ))
+
+;; Statements that allow a label
+;; TODO?
+(c-lang-defconst c-before-label-kwds
+ csharp nil)
+
+;; Constant keywords
+(c-lang-defconst c-constant-kwds
+ csharp '("true" "false" "null"))
+
+;; Keywords that start "primary expressions."
+(c-lang-defconst c-primary-expr-kwds
+ csharp '("this" "base"))
+
+;; Treat namespace as an outer block so class indenting
+;; works properly.
+(c-lang-defconst c-other-block-decl-kwds
+ csharp '("namespace"))
+
+(c-lang-defconst c-other-kwds
+ csharp '("in" "sizeof" "typeof" "is" "as" "yield"
+ "where" "select" "from"))
+
+(c-lang-defconst c-overloadable-operators
+ ;; EMCA-344, S14.2.1
+ csharp '("+" "-" "*" "/" "%" "&" "|" "^"
+ "<<" ">>" "==" "!=" ">" "<" ">=" "<="))
+
+
+;; This c-cpp-matchers stuff is used for fontification.
+;; see cc-font.el
+;;
+
+;; There's no preprocessor in C#, but there are still compiler
+;; directives to fontify: "#pragma", #region/endregion, #define, #undef,
+;; #if/else/endif. (The definitions for the extra keywords above are
+;; enough to incorporate them into the fontification regexps for types
+;; and keywords, so no additional font-lock patterns are required for
+;; keywords.)
+
+(c-lang-defconst c-cpp-matchers
+ csharp (cons
+ ;; Use the eval form for `font-lock-keywords' to be able to use
+ ;; the `c-preprocessor-face-name' variable that maps to a
+ ;; suitable face depending on the (X)Emacs version.
+ '(eval . (list "^\\s *\\(#pragma\\|undef\\|define\\)\\>\\(.*\\)"
+ (list 1 c-preprocessor-face-name)
+ '(2 font-lock-string-face)))
+ ;; There are some other things in `c-cpp-matchers' besides the
+ ;; preprocessor support, so include it.
+ (c-lang-const c-cpp-matchers)))
+
+(defcustom csharp-font-lock-extra-types nil
+ "*List of extra types (aside from the type keywords) to recognize in C# mode.
+Each list item should be a regexp matching a single identifier."
+ :type 'list :group 'csharp)
+
+(defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp)
+ "Minimal highlighting for C# mode.")
+
+(defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp)
+ "Fast normal highlighting for C# mode.")
+
+(defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp)
+ "Accurate normal highlighting for C# mode.")
+
+(defvar csharp-font-lock-keywords csharp-font-lock-keywords-3
+ "Default expressions to highlight in C# mode.")
+
+(defvar csharp-mode-syntax-table nil
+ "Syntax table used in csharp-mode buffers.")
+(or csharp-mode-syntax-table
+ (setq csharp-mode-syntax-table
+ (funcall (c-lang-const c-make-mode-syntax-table csharp))))
+
+(defvar csharp-mode-abbrev-table nil
+ "Abbreviation table used in csharp-mode buffers.")
+(c-define-abbrev-table 'csharp-mode-abbrev-table
+ ;; Keywords that if they occur first on a line might alter the
+ ;; syntactic context, and which therefore should trig reindentation
+ ;; when they are completed.
+ '(("else" "else" c-electric-continued-statement 0)
+ ("while" "while" c-electric-continued-statement 0)
+ ("catch" "catch" c-electric-continued-statement 0)
+ ("finally" "finally" c-electric-continued-statement 0)))
+
+(defvar csharp-mode-map (let ((map (c-make-inherited-keymap)))
+ ;; Add bindings which are only useful for C#
+ map)
+ "Keymap used in csharp-mode buffers.")
+
+
+;; TODO
+;; Defines our constant for finding attributes.
+;;(defconst csharp-attribute-regex "\\[\\([XmlType]+\\)(")
+;;(defconst csharp-attribute-regex "\\[\\(.\\)")
+;; This doesn't work because the string regex happens before this point
+;; and getting the font-locking to work before and after is fairly difficult
+;;(defconst csharp-attribute-regex
+;; (concat
+;; "\\[[a-zA-Z][ \ta-zA-Z0-9.]+"
+;; "\\((.*\\)?"
+;;))
+
+
+;; ==================================================================
+;; end of c# values for "language constants" defined in cc-langs.el
+;; ==================================================================
+
+
+
+
+;; ==================================================================
+;; C# code-doc insertion magic
+;; ==================================================================
+;;
+;; In Visual Studio, if you type three slashes, it immediately expands into
+;; an inline code-documentation fragment. The following method does the
+;; same thing.
+;;
+;; This is the kind of thing that could be handled by YASnippet or
+;; another similarly flexible snippet framework. But I don't want to
+;; introduce a dependency on yasnippet to csharp-mode. So the capability
+;; must live within csharp-mode itself.
+
+(defun csharp-maybe-insert-codedoc (arg)
+
+ "Insert an xml code documentation template as appropriate, when
+typing slashes. This fn gets bound to / (the slash key), in
+csharp-mode. If the slash being inserted is not the third
+consecutive slash, the slash is inserted as normal. If it is the
+third consecutive slash, then a xml code documentation template
+may be inserted in some cases. For example,
+
+ a <summary> template is inserted if the prior line is empty,
+ or contains only an open curly brace;
+ a <remarks> template is inserted if the prior word
+ closes the <summary> element;
+ a <returns> template is inserted if the prior word
+ closes the <remarks> element;
+ an <example> template is inserted if the prior word closes
+ the <returns> element;
+ a <para> template is inserted if the prior word closes
+ a <para> element.
+
+In all other cases the slash is inserted as normal.
+
+If you want the default cc-mode behavior, which implies no automatic
+insertion of xml code documentation templates, then use this in
+your `csharp-mode-hook' function:
+
+ (local-set-key (kbd \"/\") 'c-electric-slash)
+
+ "
+ (interactive "*p")
+ ;;(message "csharp-maybe-insert-codedoc")
+ (let (
+ (cur-point (point))
+ (char last-command-char)
+ (cb0 (char-before (- (point) 0)))
+ (cb1 (char-before (- (point) 1)))
+ is-first-non-whitespace
+ did-auto-insert
+ )
+
+ ;; check if two prior chars were slash
+ (if (and
+ (= char ?/)
+ cb0 (= ?/ cb0)
+ cb1 (= ?/ cb1)
+ )
+
+ (progn
+ ;;(message "yes - this is the third consecutive slash")
+ (setq is-first-non-whitespace
+ (save-excursion
+ (back-to-indentation)
+ (= cur-point (+ (point) 2))))
+
+ (if is-first-non-whitespace
+ ;; This is a 3-slash sequence. It is the first non-whitespace
text
+ ;; on the line. Now we need to examine the surrounding context
+ ;; in order to determine which xml cod doc template to insert.
+ (let (word-back char0 char1
+ word-fore char-0 char-1
+ text-to-insert ;; text to insert in lieu of slash
+ fn-to-call ;; func to call after inserting text
+ (preceding-line-is-empty (or
+ (= (line-number-at-pos) 1)
+ (save-excursion
+ (previous-line)
+ (beginning-of-line)
+ (looking-at "[ \t]*$\\|[ \t]*{[
\t]*$"))))
+ (flavor 0) ;; used only for diagnostic purposes
+ )
+
+ ;;(message "starting a 3-slash comment")
+ ;; get the prior word, and the 2 chars preceding it.
+ (backward-word)
+
+ (setq word-back (thing-at-point 'word)
+ char0 (char-before (- (point) 0))
+ char1 (char-before (- (point) 1)))
+
+ ;; restore prior position
+ (goto-char cur-point)
+
+ ;; get the following word, and the 2 chars preceding it.
+ (forward-word)
+ (backward-word)
+ (setq word-fore (thing-at-point 'word)
+ char-0 (char-before (- (point) 0))
+ char-1 (char-before (- (point) 1)))
+
+ ;; restore prior position again
+ (goto-char cur-point)
+
+ (cond
+ ;; The preceding line is empty, or all whitespace, or
+ ;; contains only an open-curly. In this case, insert a
+ ;; summary element pair.
+ (preceding-line-is-empty
+ (setq text-to-insert "/ <summary>\n/// \n/// </summary>"
+ flavor 1) )
+
+ ;; The preceding word closed a summary element. In this case,
+ ;; if the forward word does not open a remarks element, then
+ ;; insert a remarks element.
+ ((and (string-equal word-back "summary") (eq char0 ?/) (eq
char1 ?<))
+ (if (not (and (string-equal word-fore "remarks") (eq char-0
?<)))
+ (setq text-to-insert "/ <remarks>\n/// <para>\n///
\n/// </para>\n/// </remarks>"
+ flavor 2)))
+
+ ;; The preceding word closed the remarks section. In this
case,
+ ;; insert an example element.
+ ((and (string-equal word-back "remarks") (eq char0 ?/) (eq
char1 ?<))
+ (setq text-to-insert "/ <example>\n/// \n/// </example>"
+ flavor 3))
+
+ ;; The preceding word closed the example section. In this
+ ;; case, insert an returns element. This isn't always
+ ;; correct, because sometimes the xml code doc is attached to
+ ;; a class or a property, neither of which has a return
+ ;; value. A more intelligent implementation would inspect the
+ ;; syntax state and only inject a returns element if
+ ;; appropriate.
+ ((and (string-equal word-back "example") (eq char0 ?/) (eq
char1 ?<))
+ (setq text-to-insert "/ <returns></returns>"
+ fn-to-call (lambda ()
+ (backward-word)
+ (backward-char)
+ (backward-char)
+ (c-indent-line-or-region)
+ )
+ flavor 4))
+
+ ;; The preceding word opened the remarks section, or it
+ ;; closed a para section. In this case, insert a para
+ ;; element, using appropriate indentation with respect to the
+ ;; prior tag.
+ ((or
+ (and (string-equal word-back "remarks") (eq char0 ?<) (or
(eq char1 32) (eq char1 9)))
+ (and (string-equal word-back "para") (eq char0 ?/) (eq
char1 ?<)))
+
+ (let (prior-point spacer)
+ (save-excursion
+ (backward-word)
+ (backward-char)
+ (backward-char)
+ (setq prior-point (point))
+ (skip-chars-backward "\t ")
+ (setq spacer (buffer-substring (point) prior-point))
+ ;;(message (format "pt(%d) prior(%d) spacer(%s)" (point)
prior-point spacer))
+ )
+
+ (if (string-equal word-back "remarks")
+ (setq spacer (concat spacer " ")))
+
+ (setq text-to-insert (format "/%s<para>\n///%s
\n///%s</para>"
+ spacer spacer spacer)
+ flavor 6)))
+
+ ;; The preceding word opened a para element. In this case, if
+ ;; the forward word does not close the para element, then
+ ;; close the para element.
+ ;; --
+ ;; This is a nice idea but flawed. Suppose I have a para
element with some
+ ;; text in it. If I position the cursor at the first line,
then type 3 slashes,
+ ;; I get a close-element, and that would be inappropriate.
Not sure I can
+ ;; easily solve that problem, so the best thing might be to
simply punt, and
+ ;; require people to close their own elements.
+ ;;
+ ;; ( (and (string-equal word-back "para") (eq
char0 60) (or (eq char1 32) (eq char1 9)))
+ ;; (if (not (and (string-equal word-fore
"para") (eq char-0 47) (eq char-1 60) ))
+ ;; (setq text-to-insert "/ \n///
</para>\n///"
+ ;; fn-to-call (lambda ()
+ ;; (previous-line)
+ ;; (end-of-line)
+ ;; )
+ ;; flavor 7) )
+ ;; )
+
+ ;; the default case - do nothing
+ (t nil))
+
+ (if text-to-insert
+ (progn
+ ;;(message (format "inserting special text (f(%d))"
flavor))
+
+ ;; set the flag, that we actually inserted text
+ (setq did-auto-insert t)
+
+ ;; save point of beginning of insertion
+ (setq cur-point (point))
+
+ ;; actually insert the text
+ (insert text-to-insert)
+
+ ;; indent the inserted string, and re-position point,
either through
+ ;; the case-specific fn, or via the default progn.
+ (if fn-to-call
+ (funcall fn-to-call)
+
+ (let ((newline-count 0) (pos 0) ix)
+
+ ;; count the number of newlines in the inserted
string
+ (while (string-match "\n" text-to-insert pos)
+ (setq pos (match-end 0)
+ newline-count (+ newline-count 1) )
+ )
+
+ ;; indent what we just inserted
+ (c-indent-region cur-point (point) t)
+
+ ;; move up n/2 lines. This assumes that the
+ ;; inserted text is ~symmetric about the halfway
point.
+ ;; The assumption holds if the xml code doc uses a
+ ;; begin-elt and end-elt on a new line all by
themselves,
+ ;; and a blank line in between them where the point
should be.
+ ;; A more intelligent implementation would use a
specific
+ ;; marker string, like @@DOT, to note the desired
point.
+ (previous-line (/ newline-count 2))
+ (end-of-line)))))))))
+
+ (if (not did-auto-insert)
+ (self-insert-command (prefix-numeric-value arg)))))
+
+;; ==================================================================
+;; end of c# code-doc insertion magic
+;; ==================================================================
+
+
+
+
+;; ==================================================================
+;; c# fontification extensions
+;; ==================================================================
+;; Commentary:
+;;
+;; The purpose of the following code is to fix font-lock for C#,
+;; specifically for the verbatim-literal strings. C# is a cc-mode
+;; language and strings are handled mostly like other c-based
+;; languages. The one exception is the verbatim-literal string, which
+;; uses the syntax @"...".
+;;
+;; `parse-partial-sexp' treats those strings as just regular strings,
+;; with the @ a non-string character. This is fine, except when the
+;; verblit string ends in a slash, in which case, font-lock breaks from
+;; that point onward in the buffer.
+;;
+;; This is an attempt to fix that.
+;;
+;; The idea is to scan the buffer in full for verblit strings, and apply the
+;; appropriate syntax-table text properties for verblit strings. Also setting
+;; `parse-sexp-lookup-properties' to t tells `parse-partial-sexp'
+;; to use the syntax-table text properties set up by the scan as it does
+;; its parse.
+;;
+;; Also need to re-scan after any changes in the buffer, but on a more
+;; limited region.
+;;
+
+
+;; ;; I don't remember what this is supposed to do,
+;; ;; or how I figured out the value.
+;; ;;
+;; (defconst csharp-font-lock-syntactic-keywords
+;; '(("\\(@\\)\\(\"\\)[^\"]*\\(\"\\)\\(\"\\)[^\"]*\\(\"\\)[^\"]"
+;; (1 '(6)) (2 '(7)) (3 '(1)) (4 '(1)) (5 '(7))
+;; ))
+;; "Highlighting of verbatim literal strings. See also the variable
+;; `font-lock-keywords'.")
+
+
+
+;; The following fn allows this:
+;; (csharp-log 3 "scan result...'%s'" state)
+
+(defvar csharp-log-level 0
+ "The current log level for CSharp-specific operations.
+This is used in particular by the verbatim-literal
+string scanning.
+
+Most other csharp functions are not instrumented.
+0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY. ")
+
+(defun csharp-log (level text &rest args)
+ "Log a message at level LEVEL.
+If LEVEL is higher than `csharp-log-level', the message is
+ignored. Otherwise, it is printed using `message'.
+TEXT is a format control string, and the remaining arguments ARGS
+are the string substitutions (see `format')."
+ (if (<= level csharp-log-level)
+ (let* ((msg (apply 'format text args)))
+ (message "C#: %s" msg))
+ t))
+
+
+
+(defun csharp-max-beginning-of-stmt ()
+ "Return the greater of `c-beginning-of-statement-1' and
+`c-beginning-of-statement' . I don't understand why both of
+these methods are necessary or why they differ. But they do."
+
+ (let (dash
+ nodash
+ (curpos (point)))
+
+ ;; I think this may need a save-excursion...
+ ;; Calling c-beginning-of-statement-1 resets the point!
+
+ (setq dash (progn (c-beginning-of-statement-1) (point)))
+ (csharp-log 3 "max-bostmt dash(%d)" dash)
+ (goto-char curpos)
+
+ (setq nodash (progn (c-beginning-of-statement 1) (point)))
+ (csharp-log 3 "max-bostmt nodash(%d)" nodash)
+ (goto-char curpos)
+
+ (max dash nodash)))
+
+
+(defun csharp-in-literal (&optional lim detect-cpp)
+ "Return the type of literal point is in, if any.
+Basically this works like `c-in-literal' except it doesn't
+use or fill the cache (`c-in-literal-cache').
+
+The return value is `c' if in a C-style comment, `c++' if in a C++
+style comment, `string' if in a string literal, `pound' if DETECT-CPP
+is non-nil and in a preprocessor line, or nil if somewhere else.
+Optional LIM is used as the backward limit of the search. If omitted,
+or nil, `c-beginning-of-syntax' is used.
+
+Note that this function might do hidden buffer changes. See the
+comment at the start of cc-engine.el for more info."
+
+ (let ((rtn
+ (save-excursion
+ (let* ((pos (point))
+ (lim (or lim (progn
+ (c-beginning-of-syntax)
+ (point))))
+ (state (parse-partial-sexp lim pos)))
+ (csharp-log 4 "parse lim(%d) state: %s" lim (prin1-to-string
state))
+ (cond
+ ((elt state 3)
+ (csharp-log 4 "in literal string (%d)" pos)
+ 'string)
+ ((elt state 4)
+ (csharp-log 4 "in literal comment (%d)" pos)
+ (if (elt state 7) 'c++ 'c))
+ ((and detect-cpp (c-beginning-of-macro lim)) 'pound)
+ (t nil))))))
+ rtn))
+
+
+(defun csharp-set-vliteral-syntax-table-properties (beg end)
+ "Scan the buffer text between BEG and END, a verbatim literal
+string, setting and clearing syntax-table text properties where
+necessary.
+
+We need to modify the default syntax-table text property in these cases:
+ (backslash) - is not an escape inside a verbatim literal string.
+ (double-quote) - can be a literal quote, when doubled.
+
+BEG is the @ delimiter. END is the 'old' position of the ending quote.
+
+see
http://www.sunsite.ualberta.ca/Documentation/Gnu/emacs-lisp-ref-21-2.7/html_node/elisp_592.html
+for the list of syntax table numeric codes.
+
+"
+
+ (csharp-log 3 "set-vlit-syntax-table: beg(%d) end(%d)" beg end)
+
+ (if (and (> beg 0) (> end 0))
+
+ (let ((curpos beg)
+ (state 0))
+
+ (c-clear-char-properties beg end 'syntax-table)
+
+ (while (<= curpos end)
+
+ (cond
+ ((= state 0)
+ (if (= (char-after curpos) ?@)
+ (progn
+ (c-put-char-property curpos 'syntax-table '(6)) ; (6) =
expression prefix, (3) = symbol
+ ;;(message (format "set-s-t: prefix pos(%d) chr(%c)" beg
(char-after beg)))
+ )
+ )
+ (setq state (+ 1 state)))
+
+ ((= state 1)
+ (if (= (char-after curpos) ?\")
+ (progn
+ (c-put-char-property curpos 'syntax-table '(7)) ; (7) =
string quote
+ ;;(message (format "set-s-t: open quote pos(%d) chr(%c)"
+ ;; curpos (char-after curpos)))
+ ))
+ (setq state (+ 1 state)))
+
+ ((= state 2)
+ (cond
+ ;; handle backslash inside the string
+ ((= (char-after curpos) ?\\)
+ (c-put-char-property curpos 'syntax-table '(2)) ; (1) =
punctuation, (2) = word
+ ;;(message (format "set-s-t: backslash word pos(%d) chr(%c)"
curpos (char-after curpos)))
+ )
+
+ ;; doubled double-quote
+ ((and
+ (= (char-after curpos) ?\")
+ (= (char-after (+ 1 curpos)) ?\"))
+ (c-put-char-property curpos 'syntax-table '(2)) ; (1) =
punctuation, (2) = word
+ (c-put-char-property (+ 1 curpos) 'syntax-table '(2)) ; (1) =
punctuation
+ ;;(message (format "set-s-t: double doublequote pos(%d) chr(%c)"
curpos (char-after curpos)))
+ (setq curpos (+ curpos 1))
+ )
+
+ ;; a single double-quote, which should be a string terminator
+ ((= (char-after curpos) ?\")
+ (c-put-char-property curpos 'syntax-table '(7)) ; (7) = string
quote
+ ;;(message (format "set-s-t: close quote pos(%d) chr(%c)" curpos
(char-after curpos)))
+ ;;go no further
+ (setq state (+ 1 state)))
+
+ ;; everything else
+ (t
+ ;;(message (format "set-s-t: none pos(%d) chr(%c)" curpos
(char-after curpos)))
+ nil))))
+ ;; next char
+ (setq curpos (+ curpos 1))))))
+
+
+
+(defun csharp-end-of-verbatim-literal-string (&optional lim)
+ "Moves to and returns the position of the end quote of the verbatim literal
+string. When calling, point should be on the @ of the verblit string.
+If it is not, then no movement is performed and `point' is returned.
+
+This function ignores text properties. In fact it is the
+underlying scanner used to set the text properties in a C# buffer.
+"
+
+ (csharp-log 3 "end-of-vlit-string: point(%d) c(%c)" (point) (char-after))
+
+ (let (curpos
+ (max (or lim (point-max))))
+
+ (if (not (looking-at "@\""))
+ (point)
+ (forward-char 2) ;; pass up the @ sign and first quote
+ (setq curpos (point))
+
+ ;; Within a verbatim literal string, a doubled double-quote
+ ;; escapes the double-quote."
+ (while (and ;; process characters...
+ (or ;; while...
+ (not (eq (char-after curpos) ?\")) ;; it's not a quote
+ (eq (char-after (+ curpos 1)) ?\")) ;; or, its a double (double)
quote
+ (< curpos max)) ;; and we're not done yet
+
+ (cond
+ ((and (eq (char-after curpos) ?\") ;; it's a double-quote.
+ (eq (char-after (+ curpos 1)) ?\"))
+ (setq curpos (+ 2 curpos))) ;; Skip 2
+ (t ;; anything else
+ (setq curpos (+ 1 curpos))))) ;; skip fwd 1
+ curpos)))
+
+
+
+
+(defun csharp-scan-for-verbatim-literals-and-set-props (&optional beg end)
+
+"Scans the buffer, between BEG and END, for verbatim literal
+strings, and sets override text properties on each string to
+allow proper syntax highlighting, indenting, and cursor movement.
+
+BEG and END define the limits of the scan. When nil, they
+default to `point-min' and `point-max' respectively.
+
+Setting text properties generally causes the buffer to be marked
+as modified, but this fn suppresses that via the
+`c-buffer-save-state' macro, for any changes in text properties
+that it makes. This fn also ignores the read-only setting on a
+buffer, using the same macro.
+
+This fn is called when a csharp-mode buffer is loaded, with BEG
+and END set to nil, to do a full scan. It is also called on
+every buffer change, with the BEG and END set to the values for
+the change.
+
+The return value is nil if the buffer was not a csharp-mode
+buffer. Otherwise it is the last cursor position examined by the
+scan.
+"
+
+ (if (not (c-major-mode-is 'csharp-mode)) ;; don't scan if not csharp mode
+ nil
+ (save-excursion
+ (c-save-buffer-state
+ ((curpos (or beg (point-min)))
+ (lastpos (or end (point-max)))
+ (state 0) (start 0) (cycle 0)
+ literal eos limits)
+
+ (csharp-log 3 "scan")
+ (goto-char curpos)
+
+ (while (and (< curpos lastpos) (< cycle 10000))
+ (cond
+
+ ;; Case 1: current char is a @ sign
+ ;; --------------------------------------------
+ ;; Check to see if it demarks the beginning of a verblit
+ ;; string.
+ ((= ?@ (char-after curpos))
+
+ ;; are we in a comment? a string? Maybe the @ is a prefix
+ ;; to allow the use of a reserved word as a symbol. Let's find out.
+
+ ;; not sure why I need both of the following.
+ (syntax-ppss-flush-cache 1)
+ (parse-partial-sexp 1 curpos)
+ (goto-char curpos)
+ (setq literal (csharp-in-literal))
+ (cond
+
+ ;; Case 1.A: it's a @ within a string.
+ ;; --------------------------------------------
+ ;; This should never happen, because this scanner hops over
strings.
+ ;; But it might happen if the scan starts at an odd place.
+ ((eq literal 'string) nil)
+
+ ;; Case 1.B: The @ is within a comment. Hop over it.
+ ((and (memq literal '(c c++))
+ ;; This is a kludge for XEmacs where we use
+ ;; `buffer-syntactic-context', which doesn't correctly
+ ;; recognize "\*/" to end a block comment.
+ ;; `parse-partial-sexp' which is used by
+ ;; `c-literal-limits' will however do that in most
+ ;; versions, which results in that we get nil from
+ ;; `c-literal-limits' even when `c-in-literal' claims
+ ;; we're inside a comment.
+ ;;(setq limits (c-literal-limits start)))
+ (setq limits (c-literal-limits)))
+
+ ;; advance to the end of the comment
+ (if limits
+ (progn
+ (csharp-log 4 "scan: jump end comment A (%d)" (cdr limits))
+ (setq curpos (cdr limits)))))
+
+
+ ;; Case 1.B: curpos is at least 2 chars before the last
+ ;; position to examine, and, the following char is a
+ ;; double-quote (ASCII 34).
+ ;; --------------------------------------------
+ ;; This looks like the beginning of a verbatim string
+ ;; literal.
+ ((and (< (+ 2 curpos) lastpos)
+ (= ?\" (char-after (+ 1 curpos))))
+
+ (setq eos (csharp-end-of-verbatim-literal-string))
+ ;; set override syntax properties on the verblit string
+ (csharp-set-vliteral-syntax-table-properties curpos eos)
+
+ (csharp-log 4 "scan: jump end verblit string (%d)" eos)
+ (setq curpos eos))))
+
+
+ ;; Case 2: current char is a double-quote.
+ ;; --------------------------------------------
+ ;; If this is a string, we hop over it, on the assumption that
+ ;; this scanner need not bother with regular literal strings, which
+ ;; get the proper syntax with the generic approach.
+ ;; If in a comment, hop over the comment.
+ ((= ?\" (char-after curpos))
+ (goto-char curpos)
+ (setq literal (c-in-literal))
+ (cond
+
+ ;; Case 2.A: a quote within a string
+ ;; --------------------------------------------
+ ;; This shouldn't happen, because we hop over strings.
+ ;; But it might.
+ ((eq literal 'string) nil)
+
+ ;; Case 2.B: a quote within a comment
+ ;; --------------------------------------------
+ ((and (memq literal '(c c++))
+ ;; This is a kludge for XEmacs where we use
+ ;; `buffer-syntactic-context', which doesn't correctly
+ ;; recognize "\*/" to end a block comment.
+ ;; `parse-partial-sexp' which is used by
+ ;; `c-literal-limits' will however do that in most
+ ;; versions, which results in that we get nil from
+ ;; `c-literal-limits' even when `c-in-literal' claims
+ ;; we're inside a comment.
+ ;;(setq limits (c-literal-limits start)))
+ (setq limits (c-literal-limits)))
+
+ ;; advance to the end of the comment
+ (if limits
+ (progn
+ (setq curpos (cdr limits))
+ (csharp-log 3 "scan: jump end comment B (%s)" curpos))))
+
+
+ ;; Case 2.C: Not in a comment, and not in a string.
+ ;; --------------------------------------------
+ ;; This is the beginning of a literal (but not verbatim) string.
+ (t
+ (forward-char 1) ;; pass up the quote
+ (if (consp (setq limits (c-literal-limits)))
+ (progn
+ (csharp-log 4 "scan: jump end literal (%d)" (cdr limits))
+ (setq curpos (cdr limits))))))))
+
+ (setq cycle (+ 1 cycle))
+ (setq curpos (+ 1 curpos))
+ (c-safe (goto-char curpos)))))))
+
+
+(defun csharp-before-font-lock (beg end old-len)
+ "Adjust`syntax-table' properties on the region affected by the change
+in a csharp-mode buffer.
+
+This function is the C# value for `c-before-font-lock-function'.
+It intended to be called only by the cc-mode runtime.
+
+It prepares the buffer for font locking, hence must get called
+before `font-lock-after-change-function'.
+
+It does hidden buffer changes.
+
+BEG, END and OLD-LEN have the same meaning here as for any
+after-change function.
+
+Point is undefined both before and after this function call.
+The return value is meaningless, and is ignored by cc-mode.
+"
+ (let ((start-scan (progn
+ (c-beginning-of-statement 1)
+ (point))))
+ (csharp-scan-for-verbatim-literals-and-set-props start-scan end)))
+
+
+
+(c-lang-defconst c-before-font-lock-function
+ csharp 'csharp-before-font-lock)
+
+;; ==================================================================
+;; end of c# fontification extensions
+;; ==================================================================
+
+
+
+
+
+;; ==================================================================
+;; C#-specific optimizations of cc-mode funcs
+;; ==================================================================
+
+
+;; There's never a need to check for C-style macro definitions in
+;; a C# buffer.
+(defadvice c-beginning-of-macro (around
+ csharp-mode-advice-1
+ compile activate)
+ (if (c-major-mode-is 'csharp-mode)
+ nil
+ ad-do-it)
+ )
+
+
+;; There's never a need to move over an Obj-C directive in csharp mode
+(defadvice c-forward-objc-directive (around
+ csharp-mode-advice-2
+ compile activate)
+ (if (c-major-mode-is 'csharp-mode)
+ nil
+ ad-do-it)
+ )
+
+;; ==================================================================
+;; end of C#-specific optimizations of cc-mode funcs
+;; ==================================================================
+
+
+
+
+
+
+
+
+;; ==================================================================
+;; c# - monkey-patching of basic parsing logic
+;; ==================================================================
+;;
+;; Here, the model redefines two defuns to add special cases for csharp
+;; mode. These primarily deal with indentation of instance
+;; initializers, which are somewhat unique to C#. I couldn't figure out
+;; how to get cc-mode to do what C# needs, without modifying these
+;; defuns.
+;;
+
+(defun c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end)
+ ;; Return non-nil if we're looking at the beginning of a block
+ ;; inside an expression. The value returned is actually a cons of
+ ;; either 'inlambda, 'inexpr-statement or 'inexpr-class and the
+ ;; position of the beginning of the construct.
+ ;;
+ ;; LIM limits the backward search. CONTAINING-SEXP is the start
+ ;; position of the closest containing list. If it's nil, the
+ ;; containing paren isn't used to decide whether we're inside an
+ ;; expression or not. If both LIM and CONTAINING-SEXP are used, LIM
+ ;; needs to be farther back.
+ ;;
+ ;; If CHECK-AT-END is non-nil then extra checks at the end of the
+ ;; brace block might be done. It should only be used when the
+ ;; construct can be assumed to be complete, i.e. when the original
+ ;; starting position was further down than that.
+ ;;
+ ;; This function might do hidden buffer changes.
+
+ (save-excursion
+ (let ((res 'maybe) passed-paren
+ (closest-lim (or containing-sexp lim (point-min)))
+ ;; Look at the character after point only as a last resort
+ ;; when we can't disambiguate.
+ (block-follows (and (eq (char-after) ?{) (point))))
+
+ (while (and (eq res 'maybe)
+ (progn (c-backward-syntactic-ws)
+ (> (point) closest-lim))
+ (not (bobp))
+ (progn (backward-char)
+ (looking-at "[\]\).]\\|\\w\\|\\s_"))
+ (c-safe (forward-char)
+ (goto-char (scan-sexps (point) -1))))
+
+ (setq res
+ (if (looking-at c-keywords-regexp)
+ (let ((kw-sym (c-keyword-sym (match-string 1))))
+ (cond
+ ((and block-follows
+ (c-keyword-member kw-sym 'c-inexpr-class-kwds))
+ (and (not (eq passed-paren ?\[))
+
+ ;; dinoch Thu, 22 Apr 2010 18:20
+ ;; ============================================
+ ;; looking at new MyType() { ... }
+ ;; means this is a brace list, so, return nil,
+ ;; implying NOT looking-at-inexpr-block
+ (not
+ (and (c-major-mode-is 'csharp-mode)
+ (looking-at "new\s+\\([[:alnum:]_]+\\)\\b")))
+
+ (or (not (looking-at c-class-key))
+ ;; If the class instantiation is at the start of
+ ;; a statement, we don't consider it an
+ ;; in-expression class.
+ (let ((prev (point)))
+ (while (and
+ (= (c-backward-token-2 1 nil
closest-lim) 0)
+ (eq (char-syntax (char-after)) ?w))
+ (setq prev (point)))
+ (goto-char prev)
+ (not (c-at-statement-start-p)))
+ ;; Also, in Pike we treat it as an
+ ;; in-expression class if it's used in an
+ ;; object clone expression.
+ (save-excursion
+ (and check-at-end
+ (c-major-mode-is 'pike-mode)
+ (progn (goto-char block-follows)
+ (zerop (c-forward-token-2 1 t)))
+ (eq (char-after) ?\())))
+ (cons 'inexpr-class (point))))
+ ((c-keyword-member kw-sym 'c-inexpr-block-kwds)
+ (when (not passed-paren)
+ (cons 'inexpr-statement (point))))
+ ((c-keyword-member kw-sym 'c-lambda-kwds)
+ (when (or (not passed-paren)
+ (eq passed-paren ?\())
+ (cons 'inlambda (point))))
+ ((c-keyword-member kw-sym 'c-block-stmt-kwds)
+ nil)
+ (t
+ 'maybe)))
+
+ (if (looking-at "\\s(")
+ (if passed-paren
+ (if (and (eq passed-paren ?\[)
+ (eq (char-after) ?\[))
+ ;; Accept several square bracket sexps for
+ ;; Java array initializations.
+ 'maybe)
+ (setq passed-paren (char-after))
+ 'maybe)
+ 'maybe))))
+
+ (if (eq res 'maybe)
+ (when (and c-recognize-paren-inexpr-blocks
+ block-follows
+ containing-sexp
+ (eq (char-after containing-sexp) ?\())
+ (goto-char containing-sexp)
+ (if (or (save-excursion
+ (c-backward-syntactic-ws lim)
+ (and (> (point) (or lim (point-min)))
+ (c-on-identifier)))
+ (and c-special-brace-lists
+ (c-looking-at-special-brace-list)))
+ nil
+ (cons 'inexpr-statement (point))))
+
+ res))))
+
+
+
+
+
+(defun c-inside-bracelist-p (containing-sexp paren-state)
+ ;; return the buffer position of the beginning of the brace list
+ ;; statement if we're inside a brace list, otherwise return nil.
+ ;; CONTAINING-SEXP is the buffer pos of the innermost containing
+ ;; paren. PAREN-STATE is the remainder of the state of enclosing
+ ;; braces
+ ;;
+ ;; N.B.: This algorithm can potentially get confused by cpp macros
+ ;; placed in inconvenient locations. It's a trade-off we make for
+ ;; speed.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (or
+ ;; This will pick up brace list declarations.
+ (c-safe
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-safe (c-forward-sexp -1))
+ (let (bracepos)
+ (if (and (or (looking-at c-brace-list-key)
+
+ (progn
+ (c-safe (c-forward-sexp -1))
+ (looking-at c-brace-list-key))
+
+ ;; dinoch Thu, 22 Apr 2010 18:20
+ ;; ============================================
+ ;; looking enum Foo : int
+ ;; means this is a brace list, so, return nil,
+ ;; implying NOT looking-at-inexpr-block
+
+ (and (c-major-mode-is 'csharp-mode)
+ (progn
+ (c-safe (c-forward-sexp -1))
+ (looking-at csharp-enum-decl-re))))
+
+ (setq bracepos (c-down-list-forward (point)))
+ (not (c-crosses-statement-barrier-p (point)
+ (- bracepos 2))))
+ (point)))))
+
+ ;; this will pick up array/aggregate init lists, even if they are nested.
+ (save-excursion
+ (let ((class-key
+ ;; Pike can have class definitions anywhere, so we must
+ ;; check for the class key here.
+ (and (c-major-mode-is 'pike-mode)
+ c-decl-block-key))
+ bufpos braceassignp lim next-containing)
+ (while (and (not bufpos)
+ containing-sexp)
+ (when paren-state
+ (if (consp (car paren-state))
+ (setq lim (cdr (car paren-state))
+ paren-state (cdr paren-state))
+ (setq lim (car paren-state)))
+ (when paren-state
+ (setq next-containing (car paren-state)
+ paren-state (cdr paren-state))))
+ (goto-char containing-sexp)
+ (if (c-looking-at-inexpr-block next-containing next-containing)
+ ;; We're in an in-expression block of some kind. Do not
+ ;; check nesting. We deliberately set the limit to the
+ ;; containing sexp, so that c-looking-at-inexpr-block
+ ;; doesn't check for an identifier before it.
+ (setq containing-sexp nil)
+ ;; see if the open brace is preceded by = or [...] in
+ ;; this statement, but watch out for operator=
+ (setq braceassignp 'dontknow)
+ (c-backward-token-2 1 t lim)
+ ;; Checks to do only on the first sexp before the brace.
+ (when (and c-opt-inexpr-brace-list-key
+ (eq (char-after) ?\[))
+ ;; In Java, an initialization brace list may follow
+ ;; directly after "new Foo[]", so check for a "new"
+ ;; earlier.
+ (while (eq braceassignp 'dontknow)
+ (setq braceassignp
+ (cond ((/= (c-backward-token-2 1 t lim) 0) nil)
+ ((looking-at c-opt-inexpr-brace-list-key) t)
+ ((looking-at "\\sw\\|\\s_\\|[.[]")
+ ;; Carry on looking if this is an
+ ;; identifier (may contain "." in Java)
+ ;; or another "[]" sexp.
+ 'dontknow)
+ (t nil)))))
+ ;; Checks to do on all sexps before the brace, up to the
+ ;; beginning of the statement.
+ (while (eq braceassignp 'dontknow)
+ (cond ((eq (char-after) ?\;)
+ (setq braceassignp nil))
+ ((and class-key
+ (looking-at class-key))
+ (setq braceassignp nil))
+ ((eq (char-after) ?=)
+ ;; We've seen a =, but must check earlier tokens so
+ ;; that it isn't something that should be ignored.
+ (setq braceassignp 'maybe)
+ (while (and (eq braceassignp 'maybe)
+ (zerop (c-backward-token-2 1 t lim)))
+ (setq braceassignp
+ (cond
+ ;; Check for operator =
+ ((and c-opt-op-identifier-prefix
+ (looking-at c-opt-op-identifier-prefix))
+ nil)
+ ;; Check for `<opchar>= in Pike.
+ ((and (c-major-mode-is 'pike-mode)
+ (or (eq (char-after) ?`)
+ ;; Special case for Pikes
+ ;; `[]=, since '[' is not in
+ ;; the punctuation class.
+ (and (eq (char-after) ?\[)
+ (eq (char-before) ?`))))
+ nil)
+ ((looking-at "\\s.") 'maybe)
+ ;; make sure we're not in a C++ template
+ ;; argument assignment
+ ((and
+ (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (let ((here (point))
+ (pos< (progn
+ (skip-chars-backward "^<>")
+ (point))))
+ (and (eq (char-before) ?<)
+ (not (c-crosses-statement-barrier-p
+ pos< here))
+ (not (c-in-literal))
+ ))))
+ nil)
+ (t t))))))
+ (if (and (eq braceassignp 'dontknow)
+ (/= (c-backward-token-2 1 t lim) 0))
+ (setq braceassignp nil)))
+ (if (not braceassignp)
+ (if (eq (char-after) ?\;)
+ ;; Brace lists can't contain a semicolon, so we're done.
+ (setq containing-sexp nil)
+ ;; Go up one level.
+ (setq containing-sexp next-containing
+ lim nil
+ next-containing nil))
+ ;; we've hit the beginning of the aggregate list
+ (c-beginning-of-statement-1
+ (c-most-enclosing-brace paren-state))
+ (setq bufpos (point))))
+ )
+ bufpos))
+ ))
+
+;; ==================================================================
+;; end of monkey-patching of basic parsing logic
+;; ==================================================================
+
+
+
+
+;;(easy-menu-define csharp-menu csharp-mode-map "C# Mode Commands"
+;; ;; Can use `csharp' as the language for `c-mode-menu'
+;; ;; since its definition covers any language. In
+;; ;; this case the language is used to adapt to the
+;; ;; nonexistence of a cpp pass and thus removing some
+;; ;; irrelevant menu alternatives.
+;; (cons "C#" (c-lang-const c-mode-menu csharp)))
+
+;;; Autoload mode trigger
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode))
+
+
+
+(c-add-style "C#"
+ '("Java"
+ (c-basic-offset . 4)
+ (c-comment-only-line-offset . (0 . 0))
+ (c-offsets-alist . (
+ (access-label . -)
+ (arglist-close . c-lineup-arglist)
+ (arglist-cont . 0)
+ (arglist-cont-nonempty . c-lineup-arglist)
+ (arglist-intro . c-lineup-arglist-intro-after-paren)
+ (block-close . 0)
+ (block-open . 0)
+ (brace-entry-open . 0)
+ (brace-list-close . 0)
+ (brace-list-entry . 0)
+ (brace-list-intro . +)
+ (brace-list-open . +)
+ (c . c-lineup-C-comments)
+ (case-label . +)
+ (catch-clause . 0)
+ (class-close . 0)
+ (class-open . 0)
+ (comment-intro . c-lineup-comment)
+ (cpp-macro . 0)
+ (cpp-macro-cont . c-lineup-dont-change)
+ (defun-block-intro . +)
+ (defun-close . 0)
+ (defun-open . 0)
+ (do-while-closure . 0)
+ (else-clause . 0)
+ (extern-lang-close . 0)
+ (extern-lang-open . 0)
+ (friend . 0)
+ (func-decl-cont . +)
+ (inclass . +)
+ (inexpr-class . +)
+ (inexpr-statement . 0)
+ (inextern-lang . +)
+ (inher-cont . c-lineup-multi-inher)
+ (inher-intro . +)
+ (inlambda . c-lineup-inexpr-block)
+ (inline-close . 0)
+ (inline-open . 0)
+ (innamespace . +)
+ (knr-argdecl . 0)
+ (knr-argdecl-intro . 5)
+ (label . 0)
+ (lambda-intro-cont . +)
+ (member-init-cont . c-lineup-multi-inher)
+ (member-init-intro . +)
+ (namespace-close . 0)
+ (namespace-open . 0)
+ (statement . 0)
+ (statement-block-intro . +)
+ (statement-case-intro . +)
+ (statement-case-open . +)
+ (statement-cont . +)
+ (stream-op . c-lineup-streamop)
+ (string . c-lineup-dont-change)
+ (substatement . +)
+ (substatement-open . 0)
+ (template-args-cont c-lineup-template-args +)
+ (topmost-intro . 0)
+ (topmost-intro-cont . +)
+ ))
+ ))
+
+
+
+
+;; Custom variables
+;;;###autoload
+(defcustom csharp-mode-hook nil
+ "*Hook called by `csharp-mode'."
+ :type 'hook
+ :group 'c)
+
+
+
+;;; The entry point into the mode
+;;;###autoload
+(defun csharp-mode ()
+ "Major mode for editing C# code. This mode is derived from CC Mode to
+support C#.
+
+The hook `c-mode-common-hook' is run with no args at mode
+initialization, then `csharp-mode-hook'.
+
+This mode will automatically add a regexp to the
`compilation-error-regexp-alist'
+for Csc.exe error and warning messages.
+
+Key bindings:
+\\{csharp-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (make-local-variable 'beginning-of-defun-function)
+ (make-local-variable 'end-of-defun-function)
+ (c-initialize-cc-mode t)
+ (set-syntax-table csharp-mode-syntax-table)
+
+ ;; define underscore as part of a word in the Csharp syntax table
+ (modify-syntax-entry ?_ "w" csharp-mode-syntax-table)
+
+ ;; define @ as an expression prefix in Csharp syntax table
+ (modify-syntax-entry ?@ "'" csharp-mode-syntax-table)
+
+ (setq major-mode 'csharp-mode
+ mode-name "C#"
+ local-abbrev-table csharp-mode-abbrev-table
+ abbrev-mode t)
+ (use-local-map csharp-mode-map)
+
+ ;; `c-init-language-vars' is a macro that is expanded at compile
+ ;; time to a large `setq' with all the language variables and their
+ ;; customized values for our language.
+ (c-init-language-vars csharp-mode)
+
+
+ ;; `c-common-init' initializes most of the components of a CC Mode
+ ;; buffer, including setup of the mode menu, font-lock, etc.
+ ;; There's also a lower level routine `c-basic-common-init' that
+ ;; only makes the necessary initialization to get the syntactic
+ ;; analysis and similar things working.
+ (c-common-init 'csharp-mode)
+
+ ;; csc.exe, the C# Compiler, produces errors like this:
+ ;; file.cs(6,18): error CS1006: Name of constructor must match name of class
+ (if (boundp 'compilation-error-regexp-alist-alist)
+ (progn
+ (add-to-list
+ 'compilation-error-regexp-alist-alist
+ '(ms-csharp "^[
\t]*\\([A-Za-z0-9_][^(]*\\.cs\\)(\\([0-9]+\\)[,]\\([0-9]+\\)) ?:
\\(error\\|warning\\) CS[0-9]+:" 1 2 3))
+ (add-to-list
+ 'compilation-error-regexp-alist
+ 'ms-csharp)))
+
+
+ ;; to allow next-error to work with csc.exe:
+ (setq compilation-scroll-output t)
+
+ ;; allow fill-paragraph to work on xml code doc
+ (set (make-local-variable 'paragraph-separate)
+ "[ \t]*\\(//+\\|\\**\\)\\([ \t]+\\|[ \t]+<.+?>\\)$\\|^\f")
+
+
+ (c-run-mode-hooks 'c-mode-common-hook 'csharp-mode-hook)
+
+
+ ;; Need the following for parse-partial-sexp to work properly with
+ ;; verbatim literal strings Setting this var to non-nil tells
+ ;; `parse-partial-sexp' to pay attention to the syntax text
+ ;; properties on the text in the buffer. If csharp-mode attaches
+ ;; text syntax to @"..." then, `parse-partial-sexp' will treat those
+ ;; strings accordingly.
+ (set (make-local-variable 'parse-sexp-lookup-properties)
+ t)
+
+ ;; scan the entire buffer for verblit strings
+ (csharp-scan-for-verbatim-literals-and-set-props nil nil)
+
+ (local-set-key (kbd "/") 'csharp-maybe-insert-codedoc)
+ (local-set-key (kbd "{") 'csharp-insert-open-brace)
+
+ (c-update-modeline))
+
+
+
+(message (concat "Done loading " load-file-name))
+
+
+(provide 'csharp-mode)
+
+;;; csharp-mode.el ends here
- [elpa] branch externals/csharp-mode created (now dd30649), ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode d700d31 001/459: Initial directory structure., ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 084192f 002/459: initial import,
ELPA Syncer <=
- [elpa] externals/csharp-mode 2a904cb 005/459: First checkin of TFS.el - providing the ability to perform checkin/checkout to MS TFS from within emacs., ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 497a70e 009/459: Simplify csharp-mode; eliminate flymake-for-csharp.el (unnecessary), ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode a6f4b55 012/459: fix doc to remove mention of defunct flymake-for-csharp.el, ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 6b688a6 014/459: update makefile, ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode fc60bff 019/459: Fix for breakage in Emacs 24.4, ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 13984a8 004/459: First checkin of flymake-for-csharp.el, ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 3414c63 006/459: First check in of Cscomp - C# code completion., ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 756f086 003/459: Few updates to csharp-mode. First checkin of aspx-mode.el, for ASPX files., ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode 03ed8fb 016/459: v0.8.4 - fixes bug with yasnippet integration, ELPA Syncer, 2021/08/22
- [elpa] externals/csharp-mode afe5315 022/459: Add GPL v2 license as found in the original project on Google Code., ELPA Syncer, 2021/08/22