branch: externals/csharp-mode commit 756f0865cd8ca8c1abf4ee1bec03e2d84b0b612d Author: Dino Chiesa <dpchi...@hotmail.com> Commit: Dino Chiesa <dpchi...@hotmail.com>
Few updates to csharp-mode. First checkin of aspx-mode.el, for ASPX files. --- aspx-mode.el | 496 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ csharp-mode.el | 262 +++++++++++++++++++++--------- 2 files changed, 686 insertions(+), 72 deletions(-) diff --git a/aspx-mode.el b/aspx-mode.el new file mode 100644 index 0000000..984e907 --- /dev/null +++ b/aspx-mode.el @@ -0,0 +1,496 @@ +;;; aspx-mode.el --- mode for editing ASPX files +;; +;; Copyright (C) 2010 Dino Chiesa +;; +;; Author: Dino Chiesa <dpchi...@hotmail.com> +;; Created: May 2010 +;; Version: 0.1 +;; Keywords: C#, languages, extensions, files +;; URL: ??? +;; +;; This is an emacs mode for editing single-file ASPX modules, +;; which can contain HTML, javascript, C# or VB, and +;; CSS code. +;; +;; It relies on multi-mode. +;; (see http://www.loveshack.ukfsn.org/emacs ) +;; +;; It provides context-sensitive fontification and indent in all of the +;; various chunks o an ASPX file. Browser-side Javascript within script +;; blocks gets fontified correctly. Server-side script blocks get +;; fontified properly. CSS gets indented and fontified. And of course +;; HTML. +;; +;; It relies on espresso for the javascript mode, css-mode for CSS, +;; html-mode for HTML, and csharp-mode 0.7.5 or later for the +;; server-side c# code. +;; +;; Bugs: +;; +;; - The fontification sort of turns on and off as you cursor through +;; the buffer, making for a somewhat odd user experience. +;; +;; - the fontification sometimes doesn't happen within a chunk, til you +;; modify the text within the chunk. There's probably a fix for +;; this. +;; +;; +;; Thu, 13 May 2010 23:44 +;; +;; Licensed according to the Microsoft Public License (Ms-PL) +;; +;; This license governs use of the accompanying software. If you use +;; the software, you accept this license. If you do not accept the +;; license, do not use the software. +;; +;; 1. Definitions +;; +;; The terms "reproduce," "reproduction," "derivative +;; works," and "distribution" have the same meaning here as under +;; U.S. copyright law. +;; +;; A "contribution" is the original software, or any additions or +;; changes to the software. +;; +;; A "contributor" is any person that distributes its contribution +;; under this license. +;; +;; "Licensed patents" are a contributor's patent claims that read +;; directly on its contribution. +;; +;; 2. Grant of Rights +;; +;; (A) Copyright Grant- Subject to the terms of this license, +;; including the license conditions and limitations in section 3, +;; each contributor grants you a non-exclusive, worldwide, +;; royalty-free copyright license to reproduce its contribution, +;; prepare derivative works of its contribution, and distribute its +;; contribution or any derivative works that you create. +;; +;; (B) Patent Grant- Subject to the terms of this license, including +;; the license conditions and limitations in section 3, each +;; contributor grants you a non-exclusive, worldwide, royalty-free +;; license under its licensed patents to make, have made, use, sell, +;; offer for sale, import, and/or otherwise dispose of its +;; contribution in the software or derivative works of the +;; contribution in the software. +;; +;; 3. Conditions and Limitations +;; +;; (A) No Trademark License- This license does not grant you rights +;; to use any contributors' name, logo, or trademarks. +;; +;; (B) If you bring a patent claim against any contributor over +;; patents that you claim are infringed by the software, your patent +;; license from such contributor to the software ends automatically. +;; +;; (C) If you distribute any portion of the software, you must +;; retain all copyright, patent, trademark, and attribution notices +;; that are present in the software. +;; +;; (D) If you distribute any portion of the software in source code +;; form, you may do so only under this license by including a +;; complete copy of this license with your distribution. If you +;; distribute any portion of the software in compiled or object code +;; form, you may only do so under a license that complies with this +;; license. +;; +;; (E) The software is licensed "as-is." You bear the risk of using +;; it. The contributors give no express warranties, guarantees or +;; conditions. You may have additional consumer rights under your +;; local laws which this license cannot change. To the extent +;; permitted under your local laws, the contributors exclude the +;; implied warranties of merchantability, fitness for a particular +;; purpose and non-infringement. +;; +;;; + + +(require 'multi-mode) +(require 'csharp-mode) +(require 'espresso "espresso.el") +;;(require 'javascript-mode "javascript.el") +(require 'css-mode) + + + +(defvar aspx-mode-log-level 0 + "The current log level for operatopms specific to aspx-mode. +0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY. ") + + +(defun aspx-mode-log (level text &rest args) + "Log a message at level LEVEL. +If LEVEL is higher than `aspx-mode-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 aspx-mode-log-level) + (let* ((msg (apply 'format text args))) + (message "aspx-mode: %s" msg)) + t)) + + +(defconst aspx-mode-server-lang-re + "\\([Cc]#\\|[Vv][Bb]\\)" + "Regex for matching on the ASPX langauge.") + + +(defconst aspx-mode-server-script-start-re + (concat + "<\\(script\\|SCRIPT\\)[ \t\n\r\v\f]+" + "\\(" + "language=[\"']" + aspx-mode-server-lang-re + "[\"'][ \t\n\r\v\f]+runat=[\"']server[\"']" + "\\|" + "runat=[\"']server[\"'][ \t\n\r\v\f]+language=[\"']" + aspx-mode-server-lang-re + "[\"']" + "\\)[ \t\n\r\v\f]*>" + ) +"Regex for matching the <script> tag that begins a block of +ASPX server-side code. It tries to match on <script language='C#' runat='server'...> +as well as <script runat='server' language='C#' ...> +" ) + + +(defconst aspx-mode-page-decl-re + (concat + "<%@" + "[ \t\n\r\v\f]+" + "\\(Page\\|Control\\)" + "[ \t\n\r\v\f]+" + ) + + "Regex for matching the page/control declaration" + ) + + +(defconst aspx-mode-browser-script-start-re + (concat + "<\\(script\\|SCRIPT\\)[ \t\n\r\v\f]+" + "\\(" + "type=[\"']text/javascript[\"'][ \t\n\r\v\f]+language=[\"'][Jj]ava[Ss]cript[\"']" + "\\|" + "language=[\"'][Jj]ava[Ss]cript[\"'][ \t\n\r\v\f]+type=[\"']text/javascript[\"']" + "\\|" + "type=[\"']text/javascript[\"']" + "\\|" + "language=[\"'][Jj]ava[Ss]cript[\"']" + "\\)") + +"Regex for matching the <script> tag that begins a block of +browser-side javascript code. It tries to match on +<script language='javascript' ...> or +<script type='text/javascript' ...> or +<script type='text/javascript' language='javascript' ...> or +<script language='javascript' type='text/javascript' ...> +") + + +(defconst aspx-mode-css-block-start-re + (concat + "<\\(style\\|STYLE\\)" + "[ \t\n\r\v\f]+" + "type=[\"']text/css[\"']" + "[ \t\n\r\v\f]*" + ">") + "Regex to match the beginning of a CSS block." + ) + + + +(defvar aspx-mode--last-chunk-result nil + "cached result of the last chunk analysis") + +(defvar aspx-mode-update-interval 1 + "The amount of time in seconds after the last change before trying to +re-fontify the current block.") + +(defvar aspx-mode-timer nil) + + + + + +;; When in multi-mode, I want espresso to indent to the +;; <script> tag. Use advice on the espresso indentation +;; calculation, to make that happen. +(defadvice espresso--proper-indentation (after + aspx-mode-advice-1 + compile activate) + (if (and (boundp 'multi-mode) + multi-mode) + (if (eq ad-return-value 0) + (setq ad-return-value (+ ad-return-value 4))))) + + + + +;; ======================================================= +;; dinoch - Thu, 13 May 2010 23:38 +;; factored out so that I can attach advice to it. +;; Did this for multi-mode support in ASPX files. +;; ======================================================= +(defun css--proper-indentation () + (save-excursion + (back-to-indentation) + (let ((p (parse-partial-sexp (point-min) (point))) + (end-brace-p (looking-at "}"))) + (cond + ((or (nth 8 p) (looking-at "/[/*]")) + (current-indentation)) + ((save-excursion + (and (skip-chars-backward " \t\n:,") + (looking-at "[:,]"))) + (save-excursion + (css-re-search-backward "^[ \t]*\\w") + (+ (current-indentation) css-indent-level))) + ((nth 1 p) + (save-excursion + (goto-char (nth 1 p)) + (+ (current-indentation) (if end-brace-p 0 css-indent-level)))) + (t + 0))))) + + +(defun css-indent-line () + (interactive) + (let ((indent (css--proper-indentation)) + (offset (- (current-column) (current-indentation)))) + (indent-line-to indent) + (if (> offset 0) (forward-char offset)))) + + + +;; Likewise with css-mode indentation. +(defadvice css--proper-indentation (after + aspx-mode-advice-2 + compile activate) + (if (and (boundp 'multi-mode) + multi-mode) + (if (eq ad-return-value 0) + (setq ad-return-value (+ ad-return-value 4))))) + + + + + + +(defun aspx-mode-timer-elapsed () + (aspx-mode-log 2 "timer fired.") + ;;(run-hooks 'aspx-mode-timer-elapsed-hook) + (aspx-mode-refontify-current-chunk-after-idle)) + + +(defun aspx-mode-restart-timer () + (if (timerp aspx-mode-timer) (cancel-timer aspx-mode-timer)) + (setq aspx-mode-timer + (run-with-timer aspx-mode-update-interval nil 'aspx-mode-timer-elapsed))) + +(defun aspx-mode-after-change-fn (begin end length) + (aspx-mode-maybe-invalidate-cached-chunk begin end length) + (if multi-mode (aspx-mode-restart-timer))) + + + +(defun aspx-mode-maybe-invalidate-cached-chunk (begin end old-length) + (let ((new-length (- end begin)) + (old-end (+ begin old-length))) + + ;; Invalidate if the length changed (we need to recalc the chunk limits) + ;; or if the change traversed the end of the chunk. + (if (and aspx-mode--last-chunk-result + (or (/= old-length new-length) + (>= old-end (nth 2 aspx-mode--last-chunk-result)))) + (setq aspx-mode--last-chunk-result nil)))) + + + +(defun aspx-mode-refontify-current-chunk-after-idle () + "Fontify the current (cached) chunk. This fn is called after a timer +expires, when the buffer has sats idle for 2s. +" + (aspx-mode-log 2 "fontifying (%d %d)" + (nth 1 aspx-mode--last-chunk-result) + (nth 2 aspx-mode--last-chunk-result)) + + (if aspx-mode--last-chunk-result + ;; Remove text props in the chunk, to force a new fontification + ;; later. Do this within a save-buffer-state, because we're not + ;; *really* changing the buffer. + (c-save-buffer-state () + (set-text-properties (nth 1 aspx-mode--last-chunk-result) + (nth 2 aspx-mode--last-chunk-result) + nil)))) + + + + + + +(defun aspx-mode-determine-current-chunk (pos) + "Determine the type (mode) and limits of the chunk at POS. +Return (MODE START END), where MODE is one of `csharp-mode', +`javascript-mode', `html-mode', or `css-mode', +and START and END are the limits of the chunk. + +Or, maybe return nil if not sure what mode it should be. +I don't know. The doc is thin and the code is impenetrable. + +This method attempts to cache the calculated result and use it +intelligently. For example if the first execution determines +that the POS is within a C# chunk, the limits of that chunk +are cached. If a subsequent invocation of this method provides a +POS that is within those limits, the function can safely return +the same chunk response, without further scanning. + +This works as long as the buffer hasn't changed - in other words +it's just cursor navigation. +" + + ;; If we're in the right zone, then use the cached value. + ;; Don't use the cache if it is HTML mode, because an HTML + ;; chunk can contain a javascript chunk, a CSS chunk, a + ;; csharp chunk. + (if (and aspx-mode--last-chunk-result + (> pos (nth 1 aspx-mode--last-chunk-result)) + (< pos (nth 2 aspx-mode--last-chunk-result)) + (not (eq 'html-mode (nth 0 aspx-mode--last-chunk-result)))) + (progn + (aspx-mode-log 3 "determine-chunk: pos %d chunk cache %s" + pos + (prin1-to-string aspx-mode--last-chunk-result)) + aspx-mode--last-chunk-result) + + (let ((mode 'html-mode) + (start-of-block (point-min)) + (end-of-block (point-max)) + sp ep + new-result) + + (save-excursion + (save-restriction + (widen) + (goto-char pos) + (cond + + ;; Between <script language='javascript' ..> and </script>? + ((save-excursion + (and (and (re-search-backward aspx-mode-browser-script-start-re nil t) + (setq sp (match-end 0))) + (and (re-search-forward "</\\(script\\|SCRIPT\\)>" nil t) + (setq ep (line-beginning-position))) + (> ep pos))) + + (setq + ;;mode 'javascript-mode + mode 'espresso-mode + start-of-block sp + end-of-block (1- ep) )) + + + ;; Between <style type="text/css"> and </style>? + ((save-excursion + (and (and (re-search-backward aspx-mode-css-block-start-re nil t) + (setq sp (match-end 0))) + (and (re-search-forward "</\\(style\\|style\\)>" nil t) + (setq ep (line-beginning-position))) + (> ep pos))) + (setq mode 'css-mode + start-of-block sp + end-of-block (1- ep) )) + + + ;; Between <script language='??' runat='server'> and </script>? + ((save-excursion + (and (and (re-search-backward aspx-mode-server-script-start-re nil t) + (setq sp (match-end 0))) + (and (re-search-forward "</\\(script\\|SCRIPT\\)>" nil t) + (setq ep (line-beginning-position))) + (> ep pos))) + + ;; TODO: support VBNET-mode, too. Check the language at the + ;; start block. + (setq mode 'csharp-mode + start-of-block sp + end-of-block (1- ep) )) + + ;; Between <%@ Page...> and the first <html> + ((save-excursion + (and (and (re-search-forward "<\\(html\\|HTML\\)>" nil t) + (setq ep (line-beginning-position))) + (> ep pos))) + + ;; TODO: support VBNET-mode, too. Check the specified language at the + ;; start block. + ;; This works only because csharp-mode has smarts to fontify the + ;; @Page directive. + (setq mode 'csharp-mode + start-of-block 1 + end-of-block (1- ep) )) + + + + ;; ;; Between <html..> and </html> + ;; ((save-excursion + ;; (and (and (re-search-backward "<\\(HTML\\|html\\)>" nil t) + ;; (setq sp (match-beginning 0))) + ;; (and (re-search-forward "</\\(html\\|HTML\\)>" nil t) + ;; (setq ep (line-end-position))) + ;; (> ep pos))) + ;; (setq mode 'html-mode + ;; start-of-block sp + ;; end-of-block (1- ep) )) + + (t + nil)))) + + ;; multi-make-list does not actually make a new list. + ;; Instead it destructively modifies the existing list. + ;; The doc says it wants to avoid producing a cons cell + ;; in the post-command-hook. + ;; Therefore, to cache the result, we need to actually + ;; cons a distinct list. To check that the new item is + ;; distinct, we need to compare each elt in the list. + ;; If that's the case, start a timer. + (setq new-result (list mode start-of-block end-of-block)) + + (if (or (not (eq (nth 0 new-result) (nth 0 aspx-mode--last-chunk-result))) + (not (eq (nth 1 new-result) (nth 1 aspx-mode--last-chunk-result))) + (not (eq (nth 2 new-result) (nth 2 aspx-mode--last-chunk-result)))) + (progn + (aspx-mode-log 3 "new chunk, restart timer") + (aspx-mode-restart-timer))) + + (setq aspx-mode--last-chunk-result + (multi-make-list mode start-of-block end-of-block)) + + ))) + + + +(defun aspx-mode () + "Mode for editing ASPX files with embedded C# script blocks, +as well as CSS, Javascript, and HTML. +" + (interactive) + (set (make-local-variable 'multi-mode-alist) + ;; This is a very odd data structure. It doesn't make sense that + ;; it is formatted this way. The documentation is completely + ;; unhelpful. + '( + (csharp-mode . aspx-mode-determine-current-chunk) + (espresso-mode . nil) ;; javascript + (css-mode . nil) + (html-mode . nil) + )) + (add-hook 'after-change-functions 'aspx-mode-after-change-fn nil t) + (multi-mode-install-modes)) + + + + + +(provide 'aspx-mode) diff --git a/csharp-mode.el b/csharp-mode.el index 6bd9e96..69467f0 100644 --- a/csharp-mode.el +++ b/csharp-mode.el @@ -6,6 +6,7 @@ ;; Modified: April 2010 ;; Version: 0.7.5 ;; Keywords: c# languages oop mode +;; X-URL: http://code.google.com/p/csharpmode/ ;; 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 @@ -74,7 +75,6 @@ ;; ;; - ;;; Known Bugs: ;; ;; Leading identifiers are no longer being fontified, for some reason. @@ -256,55 +256,79 @@ ;; 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. +a semicolon or close-brace. This happens in 2 cases in C#: + + - after an attribute that decorates a class, method, field, or + property. + + - after an ASPNET directive, that appears in a aspx/ashx/ascx file + +An example of the former is [WebMethod] or [XmlElement]. +An example of the latter is something like this: + + <%@ WebHandler Language=\"C#\" Class=\"Handler\" %> + Providing this function allows the indenting in csharp-mode -to work properly with syntax items that follow attributes. +to work properly with code that includes attributes and ASPNET +directives. -Returns t if at the end of a attribute. Otherwise nil. +Returns t if at a position where a virtual-semicolon is. +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)) + (cond - (progn - (c-safe (backward-sexp)) - (c-backward-syntactic-ws) - (cond + ;; put a vsemi after an ASPNET directive, like + ;; <%@ WebHandler Language="C#" Class="Handler" %> + ((looking-back (concat csharp-aspnet-directive-re "$") nil t) + t) + + ;; put a vsemi after an attribute, as with + ;; [XmlElement] + ((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) - ((eq (char-before) 93) ;; close sq brace - (csharp-at-vsemi-p (point))) + (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))) + + (t nil))) + + (t nil)) + ))) - ((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) @@ -490,7 +514,9 @@ but I could not figure out how to do it. So I wrote this alternative. ;;(error (byte-compile-dest-file)) ;;(error (c-get-current-file)) - +(defconst csharp-aspnet-directive-re + "<%@.+?%>" + "Regex for matching directive blocks in ASP.NET files (.aspx, .ashx, .ascx)") (defconst csharp-enum-decl-re (concat @@ -510,7 +536,9 @@ but I could not figure out how to do it. So I wrote this alternative. ;; 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+ - +;; vsemi's allow proper indentation of code that includes inline +;; attributes and ASPNET directives. These are c#-specific things that +;; need custom treatment. (c-lang-defconst c-at-vsemi-p-fn csharp 'csharp-at-vsemi-p) @@ -528,14 +556,14 @@ but I could not figure out how to do it. So I wrote this alternative. ;; The matchers elements can be of many forms. It gets pretty -;; complicated. do a describe-variable on font-lock-keywords to get a +;; 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: +;; 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)) ;; @@ -556,14 +584,14 @@ but I could not figure out how to do it. So I wrote this alternative. ;; Prop1 = "foo" ;; } ;; -;; sharp-mode needs to fontify the properties in the +;; 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 +;; 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 +;; `c-make-font-lock-search-function' form. But the general syntax for a ;; constructor + object initializer in C# is more complex: ;; ;; new MyType(..arglist..) { @@ -579,9 +607,9 @@ but I could not figure out how to do it. So I wrote this alternative. ;; 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: +;; 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 @@ -751,15 +779,47 @@ but I could not figure out how to do it. So I wrote this alternative. csharp `( ;; option 1: - ;; ,@(when t + ;; ,@(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 } + ;; }; + ;; - - ;; Case 1: invocation of constructor + maybe an object initializer ,@(when t `((,(byte-compile `(lambda (limit) @@ -869,7 +929,15 @@ but I could not figure out how to do it. So I wrote this alternative. ))) - ;; Case 2: declaration of enum with or without an explicit base type + ;; 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) @@ -905,6 +973,11 @@ but I could not figure out how to do it. So I wrote this alternative. ;; Case 3: declaration of constructor + ;; + ;; Example: + ;; + ;; private Foo(...) {...} + ;; ,@(when t `((,(byte-compile `(lambda (limit) @@ -1064,6 +1137,51 @@ but I could not figure out how to do it. So I wrote this alternative. nil)) + ;; Case 6: directive blocks for .aspx/.ashx/.ascx + ,`((lambda (limit) + (let ((parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + + (while (re-search-forward csharp-aspnet-directive-re limit t) + (csharp-log 3 "aspnet template? - %d limit(%d)" (match-beginning 1) + limit) + + (unless + (progn + (goto-char (match-beginning 0)) + (c-skip-comments-and-strings limit)) + + (save-match-data + (let ((end-open (+ (match-beginning 0) 3)) + (beg-close (- (match-end 0) 2))) + (c-put-font-lock-face (match-beginning 0) + end-open + 'font-lock-preprocessor-face) + + (c-put-font-lock-face beg-close + (match-end 0) + 'font-lock-preprocessor-face) + + ;; fontify within the directive + (while (re-search-forward + ,(concat + "\\(" + (c-lang-const c-symbol-key) + "\\)" + "=?" + ) + beg-close t) + + (c-put-font-lock-face (match-beginning 1) + (match-end 1) + 'font-lock-keyword-face) + (c-skip-comments-and-strings beg-close)) + )) + (goto-char (match-end 0))))) + nil)) + + ;; ;; Case 5: #if ;; ,@(when t ;; `((,(byte-compile @@ -2137,18 +2255,8 @@ The return value is meaningless, and is ignored by cc-mode. ;; ================================================================== -;; 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 +;; 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) @@ -2556,8 +2664,9 @@ 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. +This mode will automatically add a symbol and regexp to the +`compilation-error-regexp-alist' and `compilation-error-regexp-alist-alist' +respectively, for Csc.exe error and warning messages. Key bindings: \\{csharp-mode-map}" @@ -2608,12 +2717,9 @@ Key bindings: ;; 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) + (local-set-key (kbd "/") 'csharp-maybe-insert-codedoc) + (local-set-key (kbd "{") 'csharp-insert-open-brace) ;; Need the following for parse-partial-sexp to work properly with @@ -2628,8 +2734,20 @@ Key bindings: ;; 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-run-mode-hooks 'c-mode-common-hook 'csharp-mode-hook) + + ;; 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) + (setq paragraph-separate + "[ \t]*\\(//+\\|\\**\\)\\([ \t]+\\|[ \t]+<.+?>\\)$\\|^\f") + + ;;(message "C#: set paragraph-separate") + + ;; Speedbar handling + (if (fboundp 'speedbar-add-supported-extension) + (speedbar-add-supported-extension '(".cs"))) ;; idempotent (c-update-modeline))