tags:

views:

197

answers:

1

I fixed all the problems described here (and one additional), and posted the modified
csharp-mode.el (v0.7.1)
at emacswiki


The csharp-mode I use is almost really good.

It works for most things, but has a few problems:

  • #if / #endif tags break indentation, but only within the scope of a method.

  • attributes applied to fields within a struct, break indentation. (sometimes, see example)

  • within classes that implement interfaces, the indenting is broken. from that point forward.

  • Literal strings (prefixed with @) do not fontify correctly, and in fact break fontification from that point forward in the source file, if the last character in the literal string is a slash.

  • I think there are some other problems, too.

I'm not a mode writer.

Has anyone got improvements on that mode?
anyone want to volunteer to fix these few things?


example code

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Xml.Serialization;

namespace Cheeso.Says.TreyIsTheBest
{
    public class Class1
    {
        private void Method1()
        {
            // Problem 1: the following if / endif pair causes indenting to break.
            // This occurs only within the scope of a method. If the #if/#endif  is
            // outside of a method, then the indenting does not break.

            #if DIAGS

                // this first line of code within the conditional scope
                // is indented 
                String StringNumber1;

            // the second line of code within the conditional scope
            // is un-indented
            public String StringNumber2;

            #endif

                // The endif is where I expect it to be, I guess.
                // It's in-line with the matched #if.  But the comments here
                // are weirdly indented still further. ??  

                }

        // The prior close-curly is indented 2 units more than I would expect.
    }
    // the close-curly for the class is indented correctly. 


    // ==================================================================
    // ------------------------------------------------------------------

    [StructLayout(LayoutKind.Sequential,
                  CharSet = CharSet.Unicode)]
    public struct Class2
    {
        // Problem 2: when there is an attribute applied to a field
        // within a struct, and the attribute include a newline, then
        // the field indents strangely.  See also "Note 1", and "Note 2"
        // below.
        [MarshalAs(UnmanagedType.ByValArray,
                   SizeConst = 128)]
            public int Value1;

        // Note 1: this indents fine.  
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public int Value2;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public class Class3
    {
        public short PrintNameLength;

        [MarshalAs(UnmanagedType.ByValArray,
                   SizeConst = 128)]
        // Note 2: this indents just fine
        public int Value1;
    }

    // ==================================================================
    // ------------------------------------------------------------------

    // Linq Syntax is not a problem as I had originally thought
    public class Class4
    {
        #region eee

        #endregion

        private void Method1()
        {
            var files = Directory.GetFiles("Something");

            var selection = from f in files
                where System.IO.Path.GetFileName(f).StartsWith("C")
                select f;

            foreach (var e in selection)
                Console.WriteLine(e);
        }
    }


    // ==================================================================
    // ------------------------------------------------------------------

    public interface IGuess { }

    public class Class5 : IGuess
    {
        // Problem 3: When a #region tag is used inside a class that
        // implements an interface (or derives from a class) the line
        // following the region tag gets indented one extra unit.

        #region utility

            private static System.Random rnd= new System.Random(); 

        private string FigureCategory()
        {
            return "unknown";
        }

        #endregion


            // You can also see artifacts of the same confusion in
            // methods that have multiple attributes.  Again, this only
            // occurs when the containing class implements a particular
            // interface or derives from a parent class.

        [System.Web.Services.WebMethodAttribute()]
            [return: System.Xml.Serialization.XmlElementAttribute("getContainerObjectsReturn")]
            public String Method1()
        {
            return "Hello.";
        }
    }


    // ==================================================================
    // ------------------------------------------------------------------

    public class Pippo
    {
        // Problem 4: when the final char in an "escaped" string literal is a
        // slash, indenting and fontification breaks.

        List<string> directories = new List<string> { 
            @"C:\Temp\sub1\",

                // The emacs parser thinks the string has not ended.
                // This comment is fontified and indented as if it is in
                // the middle of a string literal.

                @"C:\Temp\sub2\",

            // Because we have another \" at the end of a string,
            // emacs now thinks we're "out" of the string literal.
            // This comment is now indented and fontified correctly. 

            @"C:\Home\"

                // A third \", and now emacs thinks we're back inside the string literal.
                // The rest of the code will be treated as if it were inside the string literal.

            };

        protected void Page_Load(object sender, EventArgs e)
        {
            Console.WriteLine("Hello {0}", "world");
        }
    }

}

+3  A: 

This snippet of advice appears to fixes the first half of the indentation problem #1. I'm hoping it won't cause problems elsewhere. It just looks for the condition that is causing the bad indentation (syntax statement-cont and #if or #endif (well, just #)) at the beginning of that) and returns the syntax deduced from before that point. Looks good to me, but I'm not the judge here.

(defvar csharp-mode-syntax-table-no-special-slash
  (let ((res (copy-syntax-table csharp-mode-syntax-table)))
    (modify-syntax-entry ?\\ "w" res)
    res)
  "same as regular csharp-mode-syntax-table, only \\ is not an escape char")

(defadvice c-guess-basic-syntax (after c-guess-basic-syntax-csharp-hack activate)
  "following an #if/#endif, indentation gets screwey, fix it"
  (let ((res ad-return-value))
    (save-excursion
      (save-match-data
        (cond ((and (eq major-mode 'csharp-mode)
                    (eq 'statement-cont (caar res))
                    (progn
                      (goto-char (cadar res))
                      (looking-at "#")))
               ;; when following a #if, try for a redo
               (goto-char (cadar res))
               (setq ad-return-value (c-guess-basic-syntax)))

              ((and (eq major-mode 'csharp-mode)
                    (eq 'string (caar res)))
               ;; inside a string
               ;; check to see if it is a literal
               ;; and if so, redo with modified syntax table
               (let ((p (point))
                     (extent (c-literal-limits)))
                 (when extent
                   (goto-char (- (car extent) 1))
                   (when (looking-at "@\"")
                     ;; yup, a string literal
                     (with-syntax-table csharp-mode-syntax-table-no-special-slash
                       (goto-char p)
                       (setq ad-return-value (c-guess-basic-syntax))))))))))))

The close curly brace is still indented improperly. I think folks who maintain the indentation code would know how to make changes. It's beyond the scope of my understanding. There are 104 different "cases" of indentation managed by the cc-engine...

(Same with indentation for Problems 2 & 3, they all are deemed to be a part of 'statement-cont syntax). To see the what the cc-engine thinks the syntax under the current point is, do: C-c C-s.

And regarding Problem 4, the literal string, the above seems to properly indent the literal string, but fontification is still broken.

Trey Jackson
I dug into cc-mode and found a bunch of language-specific constants to fiddle with. Modifying them here and there I was able to fix all except the last problem. For example, the indenting of fields inside a struct, I needed to modify the constant c-class-decl-kwds to include the keyword "struct". Updated version is posted at http://www.emacswiki.org/emacs/csharp-mode.el
Cheeso