diff --git a/csharp-mode.el b/csharp-mode.el index 2ba3339..7998866 100644 --- a/csharp-mode.el +++ b/csharp-mode.el @@ -56,31 +56,6 @@ ;; the buffer. ;; - -;; Installation instructions -;; -------------------------------- -;; -;; Put csharp-mode.el somewhere in your load path, optionally byte-compile -;; it, and add the following to your .emacs file: -;; -;; (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t) -;; (setq auto-mode-alist -;; (append '(("\\.cs$" . csharp-mode)) auto-mode-alist)) -;; -;; -;; Optionally, define and register a mode-hook function. To do so, use -;; something like this in your .emacs file: -;; -;; (defun my-csharp-mode-fn () -;; "function that runs when csharp-mode is initialized for a buffer." -;; (turn-on-auto-revert-mode) -;; (setq indent-tabs-mode nil) -;; ...insert more code here... -;; ...including any custom key bindings you might want ... -;; ) -;; (add-hook 'csharp-mode-hook 'my-csharp-mode-fn t) -;; -;; ;; General ;; ---------------------------- ;; @@ -140,14 +115,6 @@ ;; Get csharp-mode.el accepted as part of the emacs standard distribution. ;; Must contact monnier at iro.umontreal.ca to make this happen. ;; -;; Add refactoring capabilities? -;; - extract as method - extract a block of code into a method -;; - extract as Func<> - extract a block of code into an Action -;; -;; More code-gen power: -;; - interface implementation - I think would require csharp-shell -;; -;; ;; Acknowledgements: ;; ;; Thanks to Alan Mackenzie and Stefan Monnier for answering questions @@ -306,1503 +273,24 @@ ;;; Code: (require 'cc-mode) -(require 'cc-fonts) -(require 'cl-lib) - -;; prevent warnings like -;; csharp-mode.el:4134:21:Warning: reference to free variable -;; `compilation-error-regexp-alist-alist' -(require 'compile) - -;; Work around emacs bug#23053 -(eval-when-compile - (require 'cc-langs)) - -;; Work around emacs bug#18845 -(eval-when-compile - (when (and (= emacs-major-version 24) (>= emacs-minor-version 4)) - (require 'cl))) (require 'imenu) -;; ================================================================== -;; 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. -;; -;; NB: I think this is needed to satisfy requirements when this module -;; calls `c-lang-defconst'. (DPC) - -;; (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))) - - (defgroup csharp nil "Major mode for editing C# code." :group 'prog-mode) - ;; Custom variables -;; ensure all are defined before using ...; (defcustom csharp-mode-hook nil "*Hook called by `csharp-mode'." :type 'hook :group 'csharp) -;; The following fn allows this: -;; (csharp-log 3 "scan result...'%s'" state) - -(defcustom csharp-log-level 0 - "The current log level for CSharp-mode-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." - :type 'integer - :group 'csharp) - - (defcustom csharp-want-imenu t "*Whether to generate a buffer index via imenu for C# buffers." :type 'boolean :group 'csharp) - - - - -;; These are only required at compile time to get the sources for the -;; language constants. (The load of cc-fonts 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 - ;; ================================================================== - ;; constants used in this module - ;; ================================================================== - - (defconst csharp-type-initializer-statement-re - (concat - "\\\\.]*\\)") - "Regexp that captures a type-initializer statement in C#") - - (defconst csharp-enum-decl-re - (concat - "\\]+>[ \t\n\f\v\r]*{?\\)?" - ;; optional array-specifier - "\\(?:\\[\\]\\)?" - ;; spacing - "[\ t\n\f\v\r]*") nil) - (looking-at "[ \t\n\f\v\r]*{")) - t) - - ;; put a vsemi after an attribute, as with - ;; [XmlElement] - ;; Except when the attribute is used within a line of code, as - ;; specifying something for a parameter. - ((c-safe (backward-sexp) t) - (cond - ((re-search-forward - (concat - "\\(\\[" - "[ \t\n\r\f\v]*" - "\\(" - "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*" - "[A-Za-z_][[:alnum:]]*" - "\\)" - "[^]]*\\]\\)" - ) - (1+ pos-or-point) t) - - (c-safe (backward-sexp)) - (c-backward-syntactic-ws) - (cond - - ((eq (char-before) 93) ;; close sq brace (a previous attribute) - (csharp--at-vsemi-p (point))) ;; recurse - - ((or - (eq (char-before) 59) ;; semicolon - (eq (char-before) 123) ;; open curly - (eq (char-before) 125)) ;; close curly - t) - - ;; attr is used within a line of code - (t nil))) - - (t nil))) - - (t nil)) - ))) - -(defun csharp--at-lambda-header () - "Determines if there is lambda header at point" - (or (looking-at "([[:alnum:][:space:]_,]*)[ \t\n]*=>[ \t\n]*{") - (looking-at "[[:alnum:]_]+[ \t\n]*=>[ \t\n]*{"))) - -;; ================================================================== -;; end of csharp-mode utility and feature defuns -;; ================================================================== - - - -;; ================================================================== -;; c# values for "language constants" defined in cc-langs.el -;; ================================================================== - -(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))) - -(c-lang-defconst c-opt-after-id-concat-key - csharp "[[:alpha:]_]" ) - - - - -;; 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 the provided documentation, the other option of course, is -;; to look in the source code as an example for 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, then -;; A is called within a save-match-data. If B and C are non-nil, they -;; are called as pre and post blocks, respecitvely. -;; -;; 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" -;; } -;; -;; csharp-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, it's good to have insight into what the matcher -;; really does. 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 "\\)") - '((if (fboundp 'c-font-lock-invalid-string) - (c-font-lock-invalid-string) - (csharp-mode-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, as well. - ,`(,(concat - "\\<\\(using\\)[ \t\n\f\v\r]+" - "\\(?:" - "\\([A-Za-z0-9_]+\\)" - "[ \t\n\f\v\r]*=" - "[ \t\n\f\v\r]*" - "\\)?" - "\\(\\(?:[A-Za-z0-9_]+\\.\\)*[A-Za-z0-9_]+\\)" - "[ \t\n\f\v\r]*;") - (2 font-lock-constant-face t t) - (3 font-lock-constant-face)) - - - ;; Fontify all keywords except the primitive types. - ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp)) - 1 font-lock-keyword-face) - )) - - - -(c-lang-defconst c-basic-matchers-after - csharp `( - - ;; option 1: - ;; ,@(when condition - ;; `((,(byte-compile - ;; `(lambda (limit) ... - ;; - ;; option 2: - ;; ,`((lambda (limit) ... - ;; - ;; I don't know how to avoid the (when condition ...) in the - ;; byte-compiled version. - ;; - ;; 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+ - - ;; Case 1: invocation of constructor + maybe an object - ;; initializer. Some possible examples that satisfy: - ;; - ;; new Foo (); - ;; - ;; new Foo () { }; - ;; - ;; new Foo { }; - ;; - ;; new Foo { Prop1= 7 }; - ;; - ;; new Foo { - ;; Prop1= 7 - ;; }; - ;; - ;; new Foo { - ;; Prop1= 7, - ;; Prop2= "Fred" - ;; }; - ;; - ;; new Foo { - ;; Prop1= new Bar() - ;; }; - ;; - ;; new Foo { - ;; Prop1= new Bar { PropA = 5.6F } - ;; }; - ;; - ,@(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 "\\ 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 limit) - (if (eq (char-after) ?<) ;; ctor for generic type - (progn - (csharp-log 3 " - this is a generic type") - ;; 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 - ;; is square parenthesis block? - start - (let* ((start (point)) ;; used to hold our position, so that we know that - (end)) ;; our code isn't stuck trying to look for a non-existent sexp. - (and (eq (char-after) 91) ;; open square - (while (and (eq (char-after) 91) - (not (eq start end))) - (c-safe (c-forward-sexp 1)) - (setq end (point))) - (eq (char-before) 93))) - ;; is square parenthesis block? - end - (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, - ;; like sq brackets or parens. - (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 " - open curly gets c-decl-id-start %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. - ;; - ;; Examples: - ;; - ;; public enum Foo { ... } - ;; - ;; public enum Foo : uint { ... } - ;; - ,@(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? 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 - (with-no-warnings - (condition-case nil - (c-font-lock-declarators limit t nil) - (wrong-number-of-arguments - (c-font-lock-declarators limit t nil nil))))) - (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 p(%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 - "#\\s *\\(pragma\\|endregion\\|region\\|if\\|else\\|endif\\)")) - ))) - - (if is-attr - (progn - (if (<= 3 csharp-log-level) - (csharp-log 3 " - attribute: '%s'" - (buffer-substring-no-properties b2 e2))) - (c-put-font-lock-face b2 e2 'font-lock-type-face))))) - (goto-char (match-end 0)) - )) - nil)) - - ;; 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-z0-9_]+\\.\\)*[A-Za-z0-9_]+\\)" - 2 font-lock-constant-face t) - - - ;; Highlight function-invocation. - ;; (this may in the future use font-lock-function-call-face, if standardized) - ,`(,"\\.\\([A-Za-z0-9_]+\\)(" - 1 font-lock-function-name-face t) - - - )) - -;; verbatim string literals can be multiline -(c-lang-defconst c-multiline-string-start-char - csharp ?@) - -(defun csharp-mode-syntax-propertize-function (beg end) - "Apply syntax table properties to special constructs in region BEG to END. -Currently handled: - -- Fontify verbatim literal strings correctly -- Highlight text after #region or #pragma as comment" - (save-excursion - (goto-char beg) - (while (search-forward "@\"" end t) - (let ((in-comment-or-string-p (save-excursion - (goto-char (match-beginning 0)) - (or (nth 3 (syntax-ppss)) - (nth 4 (syntax-ppss)))))) - (when (not in-comment-or-string-p) - (let (done) - (while (and (not done) (< (point) end)) - (skip-chars-forward "^\"\\\\" end) - (cond - ((= (following-char) ?\\) - (put-text-property (point) (1+ (point)) - 'syntax-table (string-to-syntax ".")) - (forward-char 1)) - ((= (following-char) ?\") - (forward-char 1) - (if (= (following-char) ?\") - (progn - (put-text-property (1- (point)) (1+ (point)) - 'syntax-table (string-to-syntax "/")) - (forward-char 1)) - (setq done t))))))))) - - (goto-char beg) - (while (re-search-forward "^\\s *#\\s *\\(region\\|pragma\\)\\s " end t) - (when (looking-at "\\s *\\S ") - ;; mark the whitespace separating the directive from the comment - ;; text as comment starter to allow correct word movement - (put-text-property (1- (point)) (point) - 'syntax-table (string-to-syntax "< b")))))) - -;; 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, region, 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-identifier-syntax-modifications by default defines $ as a word -;; syntax, which is not legal in C#. So, define our own lang-specific -;; value. -(c-lang-defconst c-identifier-syntax-modifications - csharp '((?_ . "w"))) - - - -(c-lang-defconst c-colon-type-list-kwds - csharp '("class" "struct" "interface")) - -(c-lang-defconst c-block-prefix-disallowed-chars - - ;; Allow ':' for inherit list starters. - csharp (cl-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" "volatile" "new")) - - -;; 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? - ;; don't include enum here, because we want it to be fontified as a brace - ;; list, with commas delimiting the values. see c-brace-list-decl-kwds - ;; below. - 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" "sealed" - "protected" "ref" "out" "static" "virtual" - "implicit" "explicit" "fixed" - "override" "params" "internal" "async" "extern" "unsafe")) - - -;; 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") - ) - -(c-lang-defconst c-opt-op-identifier-prefix - "Regexp matching the token before the ones in -`c-overloadable-operators' when operators are specified in their \"identifier form\". - -This regexp is assumed to not match any non-operator identifier." - csharp (c-make-keywords-re t '("operator"))) - -;; Define the keywords that can have something following after them. -(c-lang-defconst c-type-list-kwds - csharp '("struct" "class" "interface" "is" "as" "operator" - "delegate" "event" "set" "get" "add" "remove")) - -;; Handle typeless variable declaration -(c-lang-defconst c-typeless-decl-kwds - csharp '("var")) - -;; 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, because catch has a paren (typically). -(c-lang-defconst c-block-stmt-1-kwds - csharp '("do" "else" "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" - "fixed" - "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" "value")) - -;; Keywords that start "primary expressions." -(c-lang-defconst c-primary-expr-kwds - csharp '("this" "base" "operator")) - -;; 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-ref-list-kwds - csharp nil) - -(c-lang-defconst c-other-decl-kwds - csharp nil) - -(c-lang-defconst c-other-kwds - csharp '("sizeof" "typeof" "is" "as" "yield" - "where" "select" "in" "from" "let" "orderby" "ascending" "descending" - "await" "async")) - -(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 *#\\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))) - - -;; allow strings as switch-case values by leaving out string -;; delimiters in this definition -(c-lang-defconst c-nonlabel-token-key - csharp (c-make-keywords-re t - (cl-set-difference (c-lang-const c-keywords) - (append (c-lang-const c-label-kwds) - (c-lang-const c-protection-kwds)) - :test 'string-equal))) - -(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 -;; ================================================================== - - -;; ======================================================================== -;; moving - -;; alist of regexps for various structures in a csharp source file. -(defconst csharp--regexp-alist - (list - `(func-start - ,(concat - "^[ \t\n\r\f\v]*" ;; leading whitespace - "\\(" - "public\\(?: static\\)?\\|" ;; 1. access modifier - "private\\(?: static\\)?\\|" - "protected\\(?: internal\\)?\\(?: static\\)?\\|" - "static\\|" - "\\)" - "[ \t\n\r\f\v]+" - "\\(?:override[ \t\n\r\f\v]+\\)?" ;; optional - "\\([[:alpha:]_][^\t\(\n]+\\)" ;; 2. return type - possibly generic - "[ \t\n\r\f\v]+" - "\\(" ;; 3. begin name of func - "\\(?:[A-Za-z_][[:alnum:]_]*\\.\\)*" ;; possible prefix interface - "[[:alpha:]_][[:alnum:]_]*" ;; actual func name - "\\(?:<\\(?:[[:alpha:]][[:alnum:]]*\\)\\(?:[, ]+[[:alpha:]][[:alnum:]]*\\)*>\\)?" ;; (with optional generic type parameter(s) - "\\)" ;; 3. end of name of func - "[ \t\n\r\f\v]*" - "\\(\([^\)]*\)\\)" ;; 4. params w/parens - "\\(?:[ \t]*/[/*].*\\)?" ;; optional comment at end of line - "[ \t\n\r\f\v]*" - )) - - `(class-start - ,(concat - "^[ \t]*" ;; leading whitespace - "\\(" - "public\\(?: \\(?:static\\|sealed\\)\\)?[ \t]+\\|" ;; access modifiers - "internal\\(?: \\(?:static\\|sealed\\)\\)?[ \t]+\\|" - "static\\(?: internal\\)?[ \t]+\\|" - "sealed\\(?: internal\\)?[ \t]+\\|" - "static[ \t]+\\|" - "sealed[ \t]+\\|" - "\\)" - "\\(\\(?:partial[ \t]+\\)?class\\|struct\\)" ;; class/struct keyword - "[ \t]+" - "\\([[:alpha:]_][[:alnum:]]*\\)" ;; type name - "\\(" - "[ \t\n]*:[ \t\n]*" ;; colon - "\\([[:alpha:]_][^\t\(\n]+\\)" ;; base / intf - poss generic - "\\(" - "[ \t\n]*,[ \t\n]*" - "\\([[:alpha:]_][^\t\(\n]+\\)" ;; addl interface - poss generic - "\\)*" - "\\)?" ;; possibly - "[ \t\n\r\f\v]*" - )) - - `(namespace-start - ,(concat - "^[ \t\f\v]*" ;; leading whitespace - "\\(namespace\\)" - "[ \t\n\r\f\v]+" - "\\(" - "\\(?:[A-Za-z_][[:alnum:]_]*\\.\\)*" ;; name of namespace - "[A-Za-z_][[:alnum:]]*" - "\\)" - "[ \t\n\r\f\v]*" - )) - - )) - - -(defun csharp--regexp (symbol) - "Retrieve a regexp from `csharp--regexp-alist' corresponding to SYMBOL." - (let ((elt (assoc symbol csharp--regexp-alist))) - (if elt (cadr elt) nil))) - - -(defun csharp-move-back-to-beginning-of-block () - "Move to the previous open curly." - (interactive) - (re-search-backward "{" (point-min) t)) - - -(defun csharp--move-back-to-beginning-of-something (must-match &optional must-not-match) - "Move back to the open-curly that begin *something*. -*something* is defined by MUST-MATCH, a regexp which must match -immediately preceding the curly. If MUST-NOT-MATCH is non-nil, -it is treated as a regexp that must not match immediately -preceding the curly. - -This is a helper fn for `csharp-move-back-to-beginning-of-defun' and -`csharp-move-back-to-beginning-of-class'" - (interactive) - (let (done - (found (point)) - (need-to-backup (not (looking-at "{")))) - (while (not done) - (if need-to-backup - (setq found (csharp-move-back-to-beginning-of-block))) - (if found - (setq done (and (looking-back must-match nil) - (or (not must-not-match) - (not (looking-back must-not-match nil)))) - need-to-backup t) - (setq done t))) - found)) - - - -(defun csharp-move-back-to-beginning-of-defun () - "Move back to the open-curly that start the enclosing method. -If point is outside a method, then move back to the -beginning of the prior method. - -See also, `csharp-move-fwd-to-end-of-defun'." - (interactive) - (cond - - ((bobp) nil) - - (t - (let (found) - (save-excursion - ;; handle the case where we're at the top of a fn now. - ;; if the user is asking to move back, then obviously - ;; he wants to move back to a *prior* defun. - (if (and (looking-at "{") - (looking-back (csharp--regexp 'func-start) nil) - (not (looking-back (csharp--regexp 'namespace-start) nil))) - (forward-char -1)) - - ;; now do the real work - (setq found (csharp--move-back-to-beginning-of-something - (csharp--regexp 'func-start) - (csharp--regexp 'namespace-start)))) - (if found - (goto-char found)))))) - - -(defun csharp--on-defun-open-curly-p () - "Return t when point is on the open-curly of a method." - (and (looking-at "{") - (not (looking-back (csharp--regexp 'class-start) nil)) - (not (looking-back (csharp--regexp 'namespace-start) nil)) - (looking-back (csharp--regexp 'func-start) nil))) - - -(defun csharp--on-class-open-curly-p () - "Return t when point is on the open-curly of a class." - (and (looking-at "{") - (not (looking-back (csharp--regexp 'namespace-start) nil)) - (looking-back (csharp--regexp 'class-start) nil))) - - -(defun csharp-move-fwd-to-end-of-defun () - "Move forward to the close-curly that ends the enclosing method. -If point is outside a method, moves forward to the close-curly that -defines the end of the next method. - -See also, `csharp-move-back-to-beginning-of-defun'." - (interactive) - - (let ((really-move - (lambda () - (let ((start (point)) - dest-char) - (save-excursion - (csharp-move-back-to-beginning-of-defun) - (forward-sexp) - (if (>= (point) start) - (setq dest-char (point)))) - (if dest-char - (goto-char dest-char)))))) - - (cond - - ;; case 1: end of buffer. do nothing. - ((eobp) nil) - - ;; case 2: we're at the top of a class - ((csharp--on-class-open-curly-p) - (let (found-it) - (save-excursion - (forward-char 1) ;; get off the curly - (setq found-it - (and ;; look for next open curly - (re-search-forward "{" (point-max) t) - (funcall really-move)))) - (if found-it - (goto-char found-it)))) - - - ;; case 3: we're at the top of a fn now. - ((csharp--on-defun-open-curly-p) - (forward-sexp)) - - - ;; case 4: we're at the bottom of a fn now (possibly - ;; after just calling csharp-move-fwd-to-end-of-defun. - ((and (looking-back "}" nil) - (save-excursion - (forward-sexp -1) - (csharp--on-defun-open-curly-p))) - - (let (found-it) - (save-excursion - (setq found-it - (and (re-search-forward "{" (point-max) t) - (funcall really-move)))) - (if found-it - (goto-char found-it)))) - - - ;; case 5: we're at none of those places. - (t - (funcall really-move))))) - - - - -(defun csharp-move-back-to-beginning-of-class () - "Move back to the open-curly that begin the enclosing class. -If point is outside a class, then move back to the -beginning of the prior class. - -See also, `csharp-move-fwd-to-end-of-defun'." - (interactive) - - (cond - ((bobp) nil) - - (t - (let (found) - (save-excursion - ;; handle the case where we're at the top of a class now. - ;; if the user is asking to move back, then obviously - ;; he wants to move back to a *prior* defun. - (if (and (looking-at "{") - (looking-back (csharp--regexp 'class-start) nil) - (not (looking-back (csharp--regexp 'namespace-start) nil))) - (forward-char -1)) - - ;; now do the real work - (setq found (csharp--move-back-to-beginning-of-something - (csharp--regexp 'class-start) - (csharp--regexp 'namespace-start)))) - (if found - (goto-char found)))))) - - - - -(defun csharp-move-fwd-to-end-of-class () - "Move forward to the close-curly that ends the enclosing class. - -See also, `csharp-move-back-to-beginning-of-class'." - (interactive) - (let ((start (point)) - dest-char) - (save-excursion - (csharp-move-back-to-beginning-of-class) - (forward-sexp) - (if (>= (point) start) - (setq dest-char (point)))) - - (if dest-char - (goto-char dest-char)))) - - - -(defun csharp-move-back-to-beginning-of-namespace () - "Move back to the open-curly that begins the enclosing namespace. -If point is outside a namespace, then move back -to the beginning of the prior namespace." - (interactive) - (cond - - ((bobp) nil) - - (t - (let (found) - (save-excursion - ;; handle the case where we're at the top of a namespace now. - ;; if the user is asking to move back, then obviously - ;; he wants to move back to a *prior* defun. - (if (and (looking-at "{") - (looking-back (csharp--regexp 'namespace-start) nil)) - (forward-char -1)) - - ;; now do the real work - (setq found (csharp--move-back-to-beginning-of-something - (csharp--regexp 'namespace-start)))) - (if found - (goto-char found)))))) - -;; moving -;; ======================================================================== - - - - ;; ================================================================== ;;; imenu stuff @@ -2197,938 +685,22 @@ This is done by modifying the contents of `RESULT' in place." (imenu-add-menubar-index)) - - - -;; ================================================================== -;; 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 on third consecutive slash. -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 template is inserted if the prior line is empty, - or contains only an open curly brace; - a template is inserted if the prior word - closes the element; - a template is inserted if the prior word - closes the element; - an template is inserted if the prior word closes - the element; - a template is inserted if the prior word closes - a element. - -In all other cases the slash is inserted as normal. - -The prefix argument ARG is passed on to `self-insert-command' -when the code documentation template isn't triggered. This makes -sure that M-10 / still produces 10 consecutive slashes as expected. - -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-event) - (cb0 (char-before (- (point) 0))) - (cb1 (char-before (- (point) 1))) - is-first-non-whitespace - did-auto-insert - ) - - ;; check if two prior chars were slash, in other words, - ;; check if this is the third slash in a row. - (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 - (forward-line -1) - (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 "/ \n /// \n /// " - 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 "/ \n /// \n /// \n /// \n /// " - 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 "/ \n /// \n /// " - 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 "/ " - 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\n ///%s \n ///%s" - 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/// \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. - (forward-line (- 0 (/ 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 -;; ================================================================== - -(defun csharp-time () - "Return the time of day as a string. Used in the `csharp-log' function." - (substring (current-time-string) 11 19)) ;24-hr time - - -(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 %s" (csharp-time) msg)))) - -;; ================================================================== -;; C#-specific optimizations of cc-mode funcs -;; ================================================================== - -;; 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) - "Make `c-forward-objc-directive' a no-op in `csharp-mode'." - (if (c-major-mode-is 'csharp-mode) - nil - ad-do-it) - ) - -(defadvice c-clear-string-fences (around - csharp-disable-clear-string-fences - compile activate) - "This turns off `c-clear-string-fences' for `csharp-mode'. When -on for `csharp-mode' font lock breaks after an interpolated -string or terminating simple string." - (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 -;; ================================================================== -;; -;; The following 2 defuns redefine functions from cc-mode, to add -;; special cases for C#. 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. -;; - -;; verabatim copy of c-font-lock-invalid-string before it was removed -;; from emacs/cc-mode in Git commit bb591f139f0602af292c772f974dcc14dabb1deb. - -(defun csharp-mode-font-lock-invalid-string () - ;; Assuming the point is after the opening character of a string, - ;; fontify that char with `font-lock-warning-face' if the string - ;; decidedly isn't terminated properly. - ;; - ;; This function does hidden buffer changes. - (let ((start (1- (point)))) - (save-excursion - (and (eq (elt (parse-partial-sexp start (c-point 'eol)) 8) start) - (if (if (eval-when-compile (integerp ?c)) - ;; Emacs - (integerp c-multiline-string-start-char) - ;; XEmacs - (characterp c-multiline-string-start-char)) - ;; There's no multiline string start char before the - ;; string, so newlines aren't allowed. - (not (eq (char-before start) c-multiline-string-start-char)) - ;; Multiline strings are allowed anywhere if - ;; c-multiline-string-start-char is t. - (not c-multiline-string-start-char)) - (if c-string-escaped-newlines - ;; There's no \ before the newline. - (not (eq (char-before (point)) ?\\)) - ;; Escaped newlines aren't supported. - t) - (c-put-font-lock-face start (1+ start) 'font-lock-warning-face))))) - -(advice-add 'c-looking-at-inexpr-block - :around 'csharp--c-looking-at-inexpr-block-hack) - -(defun csharp--c-looking-at-inexpr-block-hack (orig-fun &rest args) - (apply - (if (eq major-mode 'csharp-mode) - #'csharp--c-looking-at-inexpr-block - orig-fun) - args)) - -(defun csharp--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) - (or (looking-at "[\]\).]\\|\w\\|\\s_") - (looking-at ">"))) - (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[ \t\n\f\v\r]+\\([[: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 (csharp--at-lambda-header) - (cons 'inexpr (point)))))) - - (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)))) - -(advice-add 'c-inside-bracelist-p - :around 'csharp-inside-bracelist-or-c-inside-bracelist-p) - -(defun csharp-inside-bracelist-or-c-inside-bracelist-p (command &rest args) - "Run `csharp-inside-bracelist-p' if in `csharp-mode'. - -Otherwise run `c-inside-bracelist-p'." - (if (eq major-mode 'csharp-mode) - (csharp-inside-bracelist-p (nth 0 args) (nth 1 args)) - (apply command args))) - -(defun csharp-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)) - - (and (c-major-mode-is 'csharp-mode) - (or - ;; 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 - (progn - (c-safe (c-forward-sexp -1)) - (looking-at csharp-enum-decl-re)) - - ;; type-initializers are not properly detected and - ;; indented unless we help out. (no need to forward - ;; when looking here, because enum-check already did - ;; it!) - (looking-at csharp-type-initializer-statement-re)))) - - (setq bracepos (c-down-list-forward (point))) - (or - (not (c-crosses-statement-barrier-p (point) - (- bracepos 2))) - ;; this little hack (combined with the regexp-check above) - ;; fixes indentation for all type-initializers. - (c-major-mode-is 'csharp-mode))) - (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 `= 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))) - -;;; Compilation regexps -;; When invoked by MSBuild, csc’s errors look like this: -;; subfolder\file.cs(6,18): error CS1006: Name of constructor must -;; match name of class [c:\Users\user\project.csproj] - -(defun csharp--compilation-error-file-resolve () - "Resolve an msbuild error to a (filename . dirname) cons cell." - ;; http://stackoverflow.com/a/18049590/429091 - (cons (match-string 1) (file-name-directory (match-string 4)))) - -(defconst csharp-compilation-re-msbuild-error - (concat - "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" - "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): " - "error [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$") - "Regexp to match compilation error from msbuild.") - -(defconst csharp-compilation-re-msbuild-warning - (concat - "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" - "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): " - "warning [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$") - "Regexp to match compilation warning from msbuild.") - -;; Notes on xbuild and devenv commonalities -;; -;; These regexes were tailored for xbuild, but apart from the concurrent -;; build-marker ("1>") they share exactly the same match-markers. -;; -;; If we don't exclude the match-markers explicitly, these regexes -;; will also be used to match for devenv as well, including the build-marker -;; in the file-name, causing the lookup to fail. -;; -;; So if we don't want devenv to fail, we actually need to handle it in our -;; xbuild-regexes, but then we automatically get devenv-support for free. - -(defconst csharp-compilation-re-xbuild-error - (concat - "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" - "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?" - ;; handle weird devenv output format with 4 numbers, not 2 by having optional - ;; extra capture-groups. - "\\(?:,\\([0-9]+\\)\\)*): " - "error [[:alnum:]]+: .+$") - "Regexp to match compilation error from xbuild.") - -(defconst csharp-compilation-re-xbuild-warning - (concat - "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" - "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?" - ;; handle weird devenv output format with 4 numbers, not 2 by having optional - ;; extra capture-groups. - "\\(?:,\\([0-9]+\\)\\)?*): " - "warning [[:alnum:]]+: .+$") - "Regexp to match compilation warning from xbuild.") - -(eval-after-load 'compile - (lambda () - (dolist - (regexp - `((xbuild-error - ,csharp-compilation-re-xbuild-error - 1 2 3 2) - (xbuild-warning - ,csharp-compilation-re-xbuild-warning - 1 2 3 1) - (msbuild-error - ,csharp-compilation-re-msbuild-error - csharp--compilation-error-file-resolve - 2 - 3 - 2 - nil - (1 compilation-error-face) - (4 compilation-error-face)) - (msbuild-warning - ,csharp-compilation-re-msbuild-warning - csharp--compilation-error-file-resolve - 2 - 3 - 1 - nil - (1 compilation-warning-face) - (4 compilation-warning-face)))) - (add-to-list 'compilation-error-regexp-alist-alist regexp) - (add-to-list 'compilation-error-regexp-alist (car regexp))))) - - ;;; 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 . 0) - (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 . 0) - (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 . +) - )) - )) - - ;;;###autoload (define-derived-mode csharp-mode prog-mode "C#" "Major mode for editing C# code. -The mode provides fontification and indent for C# syntax, as well -as some other handy features. - -At mode startup, there are two interesting hooks that run: -`prog-mode-hook' is run with no args, then `csharp-mode-hook' is run after -that, also with no args. - -To run your own logic after csharp-mode starts, do this: - - (defun my-csharp-mode-fn () - \"my function that runs when csharp-mode is initialized for a buffer.\" - (turn-on-font-lock) - (turn-on-auto-revert-mode) ;; helpful when also using Visual Studio - (setq indent-tabs-mode nil) ;; tabs are evil - ....your own code here... - ) - (add-hook 'csharp-mode-hook 'my-csharp-mode-fn t) - - -The function above is just a suggestion. - - -Imenu Integration -=============================== - -Check the menubar for menu entries for Imenu; it is labelled -\"Index\". - -The Imenu index gets computed when the file is .cs first opened and loaded. -This may take a moment or two. If you don't like this delay and don't -use Imenu, you can turn this off with the variable `csharp-want-imenu'. - - - Key bindings: \\{csharp-mode-map}" - (make-local-variable 'beginning-of-defun-function) - (make-local-variable 'end-of-defun-function) + :after-hook (c-update-modeline) (c-initialize-cc-mode t) + (c-common-init 'java-mode) - ;; 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) - - ;; `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) - - ;; Use our predefined "C#" style unless a file local or default - ;; style is found. This is done by rebinding `c-default-style' - ;; during the `c-common-init' call. 'c-common-init' will initialize - ;; the buffer's style using the value of `c-default-style'. - (let ((c-default-style (if (or c-file-style - (stringp c-default-style) - (assq 'csharp-mode c-default-style)) - c-default-style - "C#"))) - ;; `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)) - - (define-key csharp-mode-map (kbd "/") 'csharp-maybe-insert-codedoc) - - ;; 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) - - ;; Allow fill-paragraph to work on xml code doc - ;; This setting gets overwritten quietly by c-run-mode-hooks, - ;; so I put it afterwards to make it stick. - (make-local-variable 'paragraph-separate) - - ;; Speedbar handling - (when (fboundp 'speedbar-add-supported-extension) - (speedbar-add-supported-extension '(".cs"))) ;; idempotent - - (c-update-modeline) - - ;; maybe do imenu scan after hook returns - (when csharp-want-imenu - (csharp--setup-imenu)) - - ;; The paragraph-separate variable was getting stomped by - ;; other hooks, so it must reside here. - (setq-local paragraph-separate - "[ \t]*\\(//+\\|\\**\\)\\([ \t]+\\|[ \t]+<.+?>\\)$\\|^\f") - - (setq-local beginning-of-defun-function 'csharp-move-back-to-beginning-of-defun) - ;; `end-of-defun-function' can remain forward-sexp !! - - (set (make-local-variable 'comment-auto-fill-only-comments) t) - - (set (make-local-variable 'syntax-propertize-function) - 'csharp-mode-syntax-propertize-function) - - ;; required since Emacs git master - ;; https://github.com/emacs-mirror/emacs/commit/edcdf64960a2ab4e8d9ce4419874e43b6d3ccee4 - ;; - ;; Basically syntax-propertize-function is a construct which belongs - ;; to font-lock. But correct indentation depends on - ;; syntax-properties of the text, and that should ideally be - ;; independent of font-lock being activated or not. - ;; - ;; For csharp-mode, this means that with font-lock disabled, we wont - ;; have our syntax-properties set correctly, and indentation will - ;; suffer. - ;; - ;; To patch our way around this, we issue a syntax-propertize call - ;; manually, font-lock enabled or not. - (with-silent-modifications - (csharp-mode-syntax-propertize-function (point-min) (point-max)))) + (c-init-language-vars-for 'java-mode)) (provide 'csharp-mode)