changelog shortlog tags files raw

changeset: Adding CSharp Mode and Google Weather

changeset 66: 5b737eefe5ea
parent 65:44ffac0d4bf5
tag:tip
author: kim.vanwyk
date: Wed Nov 10 15:19:03 2010 +0200 (18 months ago)
files: csharp-mode/CscompUtilities.cs csharp-mode/Readme.txt csharp-mode/aspx-mode.el csharp-mode/csharp-completion.el csharp-mode/csharp-mode.el csharp-mode/csharp-shell.el csharp-mode/flymake-for-csharp.el csharp-mode/makefile csharp-mode/svn_location.txt csharp-mode/tfs.el custom.el de_emacs_env.el de_programming.el google-weather.el
description: Adding CSharp Mode and Google Weather
       1--- a/custom.el	Wed Aug 11 10:19:02 2010 +0200
       2+++ b/custom.el	Wed Nov 10 15:19:03 2010 +0200
       3@@ -11,6 +11,7 @@
       4  '(column-number-mode t)
       5  '(compilation-search-path (quote ("c:\\sys_en")))
       6  '(compile-command "delphi32.exe -b dsr4660.dpr")
       7+ '(delphi-indent-level 2)
       8  '(desktop-save t)
       9  '(diff-command "diff")
      10  '(display-time-mode t)
      11@@ -49,8 +50,8 @@
      12  '(transient-mark-mode t)
      13  '(twit-follow-idle-interval 300)
      14  '(twit-user "rooijan")
      15- '(twitter-password nil)
      16- '(twitter-username "rooijan")
      17+ '(twitter-password nil t)
      18+ '(twitter-username "rooijan" t)
      19  '(w32shell-shell (quote cmd)))
      20 (custom-set-faces
      21   ;; custom-set-faces was added by Custom.
     1.1--- a/de_emacs_env.el	Wed Aug 11 10:19:02 2010 +0200
     1.2+++ b/de_emacs_env.el	Wed Nov 10 15:19:03 2010 +0200
     1.3@@ -287,4 +287,7 @@
     1.4     (if (eq fill '-) (setq fill nil)))
     1.5   (apply-on-rectangle 'delete-whitespace-rectangle-line start end fill ragged))
     1.6 
     1.7+;; Google weather, from http://julien.danjou.info/google-weather-el.html
     1.8+(require-if-exists 'google-weather)
     1.9+
    1.10 (provide 'de_emacs_env)
    1.11\ No newline at end of file
     2.1--- a/de_programming.el	Wed Aug 11 10:19:02 2010 +0200
     2.2+++ b/de_programming.el	Wed Nov 10 15:19:03 2010 +0200
     2.3@@ -216,4 +216,7 @@
     2.4       (eval-after-load 'po-mode '(load "gb-po-mode"))
     2.5       ))
     2.6 
     2.7+;; Require C-sharp mode
     2.8+(require-if-exists 'csharp-mode "csharp-mode/")
     2.9+
    2.10 (provide 'de_programming)
    2.11\ No newline at end of file
     3.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2+++ b/csharp-mode/CscompUtilities.cs	Wed Nov 10 15:19:03 2010 +0200
     3.3@@ -0,0 +1,1658 @@
     3.4+//#define CscompTrace
     3.5+
     3.6+// CscompUtilities.cs
     3.7+// ------------------------------------------------------------------
     3.8+//
     3.9+// Author: Dinoch
    3.10+// built on host: DINOCH-2
    3.11+// Created Mon Apr 21 08:40:47 2008
    3.12+//
    3.13+// Last Saved: <2010-May-24 17:17:19>
    3.14+//
    3.15+//
    3.16+// This thing defines an assembly containing one main class, a static
    3.17+// class that exposes only static methods.  The assembly is intended to
    3.18+// run within Powershell, in an emacs inferior shell.
    3.19+//
    3.20+// Using csde-complete, when the user asks for code-completion on a
    3.21+// segment of code, csde-complete will invoke a command in the
    3.22+// powershell - which really is just invoking a method on this static
    3.23+// class.
    3.24+//
    3.25+// The logic in this assembly will then perform whatever is necessary:
    3.26+// reflect on the specified type, or qualify a name, and so on, and then
    3.27+// return the result information to the CSDE elisp logic.
    3.28+//
    3.29+// In broad strokes, you can think of this assembly as the thing that
    3.30+// performs .NET reflection, and sends the list of potential completions
    3.31+// to elisp, which presents a pop-up menu. There are a bunch of
    3.32+// supplementary tasks required, in order to make the "return the list
    3.33+// of potential completions" possible: for example, is the completion
    3.34+// being requested on a type?  A namespace?  is it a static method?  A
    3.35+// property? and so on.  All of these extra supporting functions are also
    3.36+// implemented as static methods on the main Utilities class.
    3.37+//
    3.38+// =======================================================
    3.39+//
    3.40+// compile with:
    3.41+//   csc.exe  /target:library  /debug /out:CscompUtilities.dll  CscompUtilities.cs
    3.42+//
    3.43+// ------------------------------------------------------------------
    3.44+//
    3.45+// Copyright (c) 2008-2010 by Dino Chiesa
    3.46+// All rights reserved!
    3.47+//
    3.48+// ------------------------------------------------------------------
    3.49+
    3.50+
    3.51+using System;
    3.52+using System.IO;
    3.53+using System.Linq;
    3.54+using System.Diagnostics;
    3.55+using System.Collections.Generic;
    3.56+using System.Text.RegularExpressions;
    3.57+using System.Reflection;
    3.58+
    3.59+
    3.60+// to allow fast ngen
    3.61+[assembly: AssemblyTitle("CscompUtilities.cs")]
    3.62+[assembly: AssemblyDescription("an assembly to be loaded into powershell, allows integration with emacs, code completion, etc.")]
    3.63+[assembly: AssemblyConfiguration("")]
    3.64+[assembly: AssemblyCompany("Dino Chiesa")]
    3.65+[assembly: AssemblyProduct("Tools")]
    3.66+[assembly: AssemblyCopyright("Copyright © Dino Chiesa 2010")]
    3.67+[assembly: AssemblyTrademark("")]
    3.68+[assembly: AssemblyCulture("")]
    3.69+[assembly: AssemblyVersion("1.2.0.4")]
    3.70+
    3.71+
    3.72+
    3.73+namespace Ionic.Cscomp
    3.74+{
    3.75+    public static class Utilities
    3.76+    {
    3.77+        private static readonly string DotNetDir= "c:\\windows\\Microsoft.NET\\Framework\\v2.0.50727";
    3.78+
    3.79+        private static string[] BaseAssembliesToLoad = {
    3.80+            // must be strong names
    3.81+            "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    3.82+            "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    3.83+        };
    3.84+
    3.85+
    3.86+        private static Dictionary<string,string> GacAssemblies =
    3.87+            new Dictionary<string,string>()
    3.88+        {
    3.89+            {"System.Xml","Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" },
    3.90+            {"System.Xml.Linq", "Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" },
    3.91+            {"System.Data", "Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" },
    3.92+        };
    3.93+
    3.94+
    3.95+//             "Microsoft.JScript",
    3.96+//             "Microsoft.VisualBasic",
    3.97+//             "Microsoft.VisualBasic.Vsa",
    3.98+//             "Microsoft.VisualC",
    3.99+//             "Microsoft.Vsa",
   3.100+//             "Microsoft.Vsa.Vb.CodeDOMPRocessor",
   3.101+//             "System.Configuration.Install",
   3.102+//             "System.Data",
   3.103+//             "System.Design",
   3.104+//             "System.DirectoryServices",
   3.105+//             "System.Drawing",
   3.106+//             "System.Drawing.Design",
   3.107+//             "System.EnterpriseServices",
   3.108+//             "System.Management",
   3.109+//             "System.Messaging",
   3.110+//             "System.Runtime.Remoting",
   3.111+//             "System.Runtime.Serialization.Formatters.Soap",
   3.112+//             "System.Security",
   3.113+//             "System.ServiceProcess",
   3.114+//             "System.Web",
   3.115+//             "System.Web.RegularExpressions",
   3.116+//             "System.Web.Services",
   3.117+//             "System.Windows.Forms",
   3.118+
   3.119+        private static Dictionary<String,Object>       _assembliesNotLoaded;
   3.120+        private static Dictionary<String,Assembly>     _assembliesLoaded;
   3.121+        private static Dictionary<String,String>       _assemblyForType;
   3.122+        private static Dictionary<String,List<String>> _typesForNamespace;
   3.123+        private static Dictionary<String,String>       _fullNamesForShortNames;
   3.124+
   3.125+        static Utilities()
   3.126+        {
   3.127+            Tracing.SetupDebugConsole();
   3.128+            LoadAssembliesAndPopulateHashes();
   3.129+        }
   3.130+
   3.131+
   3.132+        private static Assembly AssemblyIsLoaded(string assemblyName)
   3.133+        {
   3.134+            // exact match
   3.135+            if (_assembliesLoaded.Keys.Contains(assemblyName))
   3.136+                return _assembliesLoaded[assemblyName];
   3.137+
   3.138+            // check for short name
   3.139+            if (!assemblyName.Contains(","))
   3.140+            {
   3.141+                foreach (var key in _assembliesLoaded.Keys)
   3.142+                {
   3.143+                    int ix = key.LastIndexOf(',');
   3.144+                    if (ix > 0)
   3.145+                    {
   3.146+                        var stub = key.Substring(0, ix);
   3.147+                        if (assemblyName == stub)
   3.148+                            return _assembliesLoaded[key];
   3.149+                    }
   3.150+                }
   3.151+            }
   3.152+            return null;
   3.153+        }
   3.154+
   3.155+
   3.156+
   3.157+        private static String InternalLoadOneAssembly(string assemblyName)
   3.158+        {
   3.159+            // check if already loaeded
   3.160+            if (AssemblyIsLoaded(assemblyName)!=null)
   3.161+                return "t";
   3.162+
   3.163+            // doesn't appear to be loaded. Try to load it.
   3.164+
   3.165+            Assembly thisAssembly = null;
   3.166+            try
   3.167+            {
   3.168+                thisAssembly = TryLoadAssembly(assemblyName);
   3.169+
   3.170+            }
   3.171+            catch(Exception exc1)
   3.172+            {
   3.173+                _assembliesNotLoaded[assemblyName] = exc1;
   3.174+                return null;
   3.175+            }
   3.176+
   3.177+            if (thisAssembly == null)
   3.178+            {
   3.179+                _assembliesNotLoaded[assemblyName] = "Assembly was null.";
   3.180+                return null;
   3.181+            }
   3.182+
   3.183+            _assembliesLoaded.Add(assemblyName, thisAssembly);
   3.184+
   3.185+            Module[] ma = thisAssembly.GetModules();
   3.186+            if (ma != null)
   3.187+            {
   3.188+                List<String> list;
   3.189+
   3.190+                for (int k = 0; k < ma.Length; k++)
   3.191+                {
   3.192+                    try
   3.193+                    {
   3.194+                        if (ma[k] == null)  continue;
   3.195+
   3.196+                        Type[] types = ma[k].GetTypes();
   3.197+                        if (types == null) continue;
   3.198+
   3.199+                        foreach (Type t in types)
   3.200+                        {
   3.201+                            try
   3.202+                            {
   3.203+                                if (t == null) continue;
   3.204+                                String ns = t.Namespace;
   3.205+                                if (ns == null) ns = String.Empty;
   3.206+
   3.207+                                if (_typesForNamespace.ContainsKey(ns))
   3.208+                                    list= (List<String>) _typesForNamespace[ns];
   3.209+                                else
   3.210+                                {
   3.211+                                    list= new List<String>();
   3.212+                                    _typesForNamespace[ns]= list;
   3.213+                                }
   3.214+
   3.215+                                // sometimes we get duplicate types
   3.216+                                if (!list.Contains(t.FullName))
   3.217+                                {
   3.218+                                    _assemblyForType[t.FullName]= assemblyName;
   3.219+                                    list.Add(t.FullName);
   3.220+                                    _fullNamesForShortNames[t.Name] = t.FullName;
   3.221+                                }
   3.222+                            }
   3.223+                            catch(ReflectionTypeLoadException)
   3.224+                            {
   3.225+                                //Response.Write("Problem with : " + t.FullName);
   3.226+                                continue;
   3.227+                            }
   3.228+                        }
   3.229+                    }
   3.230+                    catch(Exception)
   3.231+                    {
   3.232+                        continue;
   3.233+                    }
   3.234+                }
   3.235+            }
   3.236+
   3.237+            return assemblyName;
   3.238+        }
   3.239+
   3.240+
   3.241+        private static void LoadAssembliesAndPopulateHashes()
   3.242+        {
   3.243+            _assembliesNotLoaded    = new Dictionary<String,Object>();
   3.244+            _assemblyForType        = new Dictionary<String,String>();
   3.245+            _typesForNamespace      = new Dictionary<String,List<String>>();
   3.246+            _fullNamesForShortNames = new Dictionary<String,String>();
   3.247+            _assembliesLoaded       = new Dictionary<String,Assembly>();
   3.248+
   3.249+            for (int i=0; i<BaseAssembliesToLoad.Length; ++i)
   3.250+                InternalLoadOneAssembly(BaseAssembliesToLoad[i]);
   3.251+
   3.252+            Alphabetize();
   3.253+        }
   3.254+
   3.255+
   3.256+        private static void Alphabetize()
   3.257+        {
   3.258+            foreach (string key in _typesForNamespace.Keys)
   3.259+            {
   3.260+                _typesForNamespace[key].Sort();
   3.261+            }
   3.262+        }
   3.263+
   3.264+
   3.265+        public static String GetTypeInfo(String typeName)
   3.266+        {
   3.267+            string q= null;
   3.268+            String[] s =  null;
   3.269+            try
   3.270+            {
   3.271+                q= QualifyType(typeName);
   3.272+                s = q.Replace(")","").Replace("(","").Split(" ".ToCharArray(), 3);
   3.273+                return GetTypeInfo(s[1].Replace("\"",""), s[2].Replace("\"",""));
   3.274+
   3.275+            }
   3.276+            catch (System.Exception exc1)
   3.277+            {
   3.278+                System.Console.WriteLine("uncaught exception {0}", exc1.ToString());
   3.279+                System.Console.WriteLine("q= {0}", q);
   3.280+                System.Console.WriteLine("s.Length= {0}", s.Length);
   3.281+                throw ;
   3.282+            }
   3.283+        }
   3.284+
   3.285+
   3.286+        public static String GetTypeInfo(String typeName, String assemblyName)
   3.287+        {
   3.288+            try
   3.289+            {
   3.290+                if (_assemblyForType.Keys.Contains(typeName) &&
   3.291+                    _assemblyForType[typeName] == assemblyName &&
   3.292+                    _assembliesLoaded.Keys.Contains(assemblyName))
   3.293+                {
   3.294+                    Assembly a2 = _assembliesLoaded[assemblyName];
   3.295+                    Ionic.Cscomp.TypeInfo ti2= new Ionic.Cscomp.TypeInfo(a2, typeName);
   3.296+                    return ti2.AsSexp();
   3.297+                }
   3.298+
   3.299+                // Load from a strongname, eg
   3.300+                // "System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
   3.301+
   3.302+                Assembly a= Assembly.Load(assemblyName);
   3.303+
   3.304+                if ((a == null) && (System.IO.File.Exists(assemblyName)))
   3.305+                    a= Assembly.LoadFrom(assemblyName);
   3.306+
   3.307+                if (a == null)
   3.308+                {
   3.309+                    System.Console.Error.WriteLine("Cannot load that assembly");
   3.310+                    return null;
   3.311+                }
   3.312+
   3.313+                Ionic.Cscomp.TypeInfo ti= new Ionic.Cscomp.TypeInfo(a, typeName);
   3.314+                return ti.AsSexp();
   3.315+            }
   3.316+            catch(TypeLoadException e2)
   3.317+            {
   3.318+                Console.Error.WriteLine("TypeLoadException: Could not load type: \"{0}\"\n{1}", typeName, e2);
   3.319+
   3.320+                return null;
   3.321+            }
   3.322+            catch (Exception e1)
   3.323+            {
   3.324+                Console.Error.WriteLine("Exception: type '{0}'\n{1}", typeName, e1);
   3.325+                return null;
   3.326+            }
   3.327+        }
   3.328+
   3.329+
   3.330+
   3.331+        private static Assembly TryLoadAssembly(String assemblyName)
   3.332+        {
   3.333+            Assembly a= null;
   3.334+
   3.335+            if (assemblyName.Contains(','))
   3.336+            {
   3.337+                // smells like a fully-qualified name
   3.338+                a= Assembly.Load(assemblyName);
   3.339+            }
   3.340+            else if (assemblyName.EndsWith(".dll") ||
   3.341+                     assemblyName.EndsWith(".exe"))
   3.342+            {
   3.343+                if (System.IO.File.Exists(assemblyName))
   3.344+                    a= Assembly.LoadFrom(assemblyName) ;
   3.345+                else
   3.346+                {
   3.347+                    // try finding a DLL by that name in the .net2.0 directory.
   3.348+                    string GuessedDll = String.Format("{0}\\{1}", DotNetDir, assemblyName);
   3.349+                    if (System.IO.File.Exists(GuessedDll))
   3.350+                        a= Assembly.LoadFrom(GuessedDll) ;
   3.351+                }
   3.352+            }
   3.353+            else
   3.354+            {
   3.355+                // try finding a DLL by that name in the .net2.0 directory.
   3.356+                string GuessedDll = String.Format("{0}\\{1}.dll", DotNetDir, assemblyName);
   3.357+                if (System.IO.File.Exists(GuessedDll))
   3.358+                    a= Assembly.LoadFrom(GuessedDll) ;
   3.359+            }
   3.360+
   3.361+            return a;
   3.362+        }
   3.363+
   3.364+
   3.365+
   3.366+        private static System.Type TryLoadType(String theTypeName, String assemblyName)
   3.367+        {
   3.368+            System.Type t= null;
   3.369+            Assembly a= TryLoadAssembly(assemblyName);
   3.370+            if (a != null)
   3.371+                t = a.GetType(theTypeName, false, true);
   3.372+            return t;  // maybe null
   3.373+        }
   3.374+
   3.375+
   3.376+
   3.377+
   3.378+        public static String LoadOneAssembly (string name)
   3.379+        {
   3.380+            Tracing.Trace("LoadOneAssembly: {0}", name);
   3.381+            string r = InternalLoadOneAssembly(name);
   3.382+            Alphabetize();
   3.383+
   3.384+            if (r == null) return "nil";
   3.385+            if (r == "t") return r;
   3.386+            return "\"" + r + "\"";
   3.387+        }
   3.388+
   3.389+
   3.390+
   3.391+        public static String ListLoadedAssemblies ()
   3.392+        {
   3.393+            string atoms = String.Join("\" \"", _assembliesLoaded.Keys.ToArray());
   3.394+            return "(list \"" + atoms + "\")";
   3.395+        }
   3.396+
   3.397+
   3.398+        /// <summary>
   3.399+        ///   Gets the version of the assembly, in a string form.
   3.400+        /// </summary>
   3.401+        /// <remarks>
   3.402+        ///   <para>
   3.403+        ///     Returns a quoted string, suitable for use as a lisp
   3.404+        ///     s-expression.  Example: "1.2.0.4"
   3.405+        ///   </para>
   3.406+        /// </remarks>
   3.407+        /// <returns>
   3.408+        ///   The quoted version string
   3.409+        /// </returns>
   3.410+        public static String Version ()
   3.411+        {
   3.412+            return "\"" +
   3.413+                System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\"";
   3.414+        }
   3.415+
   3.416+
   3.417+        public static String ListKnownTypes()
   3.418+        {
   3.419+            string atoms = String.Join("\" \"", _assemblyForType.Keys.ToArray());
   3.420+            return "(list \"" + atoms + "\")" ;
   3.421+        }
   3.422+
   3.423+
   3.424+
   3.425+        /// <summary>
   3.426+        ///   Gets all the known completions in the given namespace.
   3.427+        /// </summary>
   3.428+        /// <remarks>
   3.429+        ///   <para>
   3.430+        ///     The completions include all the types, and all the child namespaces.
   3.431+        ///     So, for ns "System", the completion list will include System.Delegate
   3.432+        ///     as well as System.Diagnostics
   3.433+        ///   </para>
   3.434+        /// </remarks>
   3.435+        /// <returns>
   3.436+        /// </returns>
   3.437+        public static String GetCompletionsForNamespace(string ns)
   3.438+        {
   3.439+            if (String.IsNullOrEmpty(ns)) return null;
   3.440+
   3.441+            if (!_typesForNamespace.ContainsKey(ns))
   3.442+            {
   3.443+                //System.Console.WriteLine("t4n no contain '{0}'", ns);
   3.444+                return null;
   3.445+            }
   3.446+
   3.447+            var result= new System.Text.StringBuilder();
   3.448+            int len = ns.Length+1;
   3.449+            result.Append("(list \"").Append(ns).Append("\" (list 'types (list ");
   3.450+            foreach (var t in _typesForNamespace[ns])
   3.451+            {
   3.452+                //System.Console.WriteLine("  " + t.Substring(len));
   3.453+                result.Append("\"").Append(t.Substring(len)).Append("\" ");
   3.454+            }
   3.455+            result.Append("))");
   3.456+
   3.457+            var childlist = new List<String>();
   3.458+            foreach (var key in _typesForNamespace.Keys)
   3.459+            {
   3.460+                if (key.StartsWith(ns) && !key.Equals(ns))
   3.461+                {
   3.462+                    var child = key.Substring(len);
   3.463+                    var p = child.IndexOf('.');
   3.464+                    if (p > 0)
   3.465+                        child = child.Substring(0,p);
   3.466+                    if (!childlist.Contains(child))
   3.467+                        childlist.Add(child);
   3.468+                }
   3.469+            }
   3.470+
   3.471+            if (childlist.Count() > 0)
   3.472+            {
   3.473+                result.Append(" (list 'namespaces (list ");
   3.474+                foreach (var c in childlist)
   3.475+                    result.Append("\"").Append(c).Append("\" ");
   3.476+                result.Append("))");
   3.477+            }
   3.478+
   3.479+            result.Append(")");
   3.480+            return result.ToString();
   3.481+        }
   3.482+
   3.483+
   3.484+        private static string Escape(string s)
   3.485+        {
   3.486+            return s.Replace("\"", "\\\"");
   3.487+        }
   3.488+
   3.489+
   3.490+        /// <summary>
   3.491+        ///   Qualify a name
   3.492+        /// </summary>
   3.493+        /// <returns>
   3.494+        ///   ("type"       fulltypename)    if the name is a type
   3.495+        ///   ("namespace"  parentNamespace) if the name is a namespace
   3.496+        ///   ("unknown"    name)            if the name is a namespace
   3.497+        /// </returns>
   3.498+        public static String QualifyName(String name)
   3.499+        {
   3.500+            var suffix = "." + name;
   3.501+            IEnumerable<String> collection;
   3.502+
   3.503+//             if (!name.Contains("."))
   3.504+//             {
   3.505+//                 // no dot in the name = assume short name
   3.506+//                 collection = _fullNamesForShortNames.Keys;
   3.507+//
   3.508+//                 // check for exact match in the keys
   3.509+//                 foreach (var key in collection)
   3.510+//                 {
   3.511+//                     if (key.Equals(name))
   3.512+//                         return String.Format("(list \"type\" \"{0}\")",
   3.513+//                                              _fullNamesForShortNames[key]);
   3.514+//                 }
   3.515+//
   3.516+//                 return String.Format("(list \"unknown\" \"{0}\")",name);
   3.517+//             }
   3.518+
   3.519+
   3.520+            if (Verbose)
   3.521+                System.Console.WriteLine("checking name: {0}", name);
   3.522+
   3.523+
   3.524+            // look for exact match on a fully-qualified typename
   3.525+            collection = _fullNamesForShortNames.Values;
   3.526+            foreach (var value in collection)
   3.527+            {
   3.528+                if (value.Equals(name))
   3.529+                    return String.Format("(list \"type\" \"{0}\")", value);
   3.530+            }
   3.531+
   3.532+            // look for ends-with match on a fully-qualified typename
   3.533+            foreach (var value in collection)
   3.534+            {
   3.535+                if (value.EndsWith(suffix))
   3.536+                    return String.Format("(list \"type\" \"{0}\")", value);
   3.537+            }
   3.538+
   3.539+            // now check for exact match on known namespaces...
   3.540+            collection = _typesForNamespace.Keys;
   3.541+            foreach (var key in collection)
   3.542+            {
   3.543+                if (key.Equals(name))
   3.544+                    return String.Format("(list \"namespace\" \"{0}\")", name);
   3.545+            }
   3.546+
   3.547+            // match on the last segment of the namespace.  Eg, if name is "Diagnostics",
   3.548+            // should match on "System.Diagnostics".
   3.549+            foreach (var key in collection)
   3.550+            {
   3.551+                if (key.EndsWith(suffix))
   3.552+                    return String.Format("(list \"namespace\" \"{0}\")", key);
   3.553+            }
   3.554+
   3.555+            // Finally, check the names of common namespaces that map to assemblies.
   3.556+            // If found, load the assembly.
   3.557+            collection = GacAssemblies.Keys;
   3.558+            foreach (var key in collection)
   3.559+            {
   3.560+                if (key.Equals(name))
   3.561+                {
   3.562+                    LoadOneAssembly(key + ", " + GacAssemblies[key]);
   3.563+                    return String.Format("(list \"namespace\" \"{0}\")", name);
   3.564+                }
   3.565+            }
   3.566+
   3.567+            return String.Format("(list \"unknown\" \"{0}\")", Escape(name));
   3.568+        }
   3.569+
   3.570+
   3.571+
   3.572+        /// <summary>
   3.573+        ///   Return all possible matches on a given symbol fragment.
   3.574+        /// </summary>
   3.575+        ///
   3.576+        /// <param name='fragment'>
   3.577+        ///   the fragment of the name to match on.
   3.578+        /// </param>
   3.579+        ///
   3.580+        /// <param name='namespaces'>
   3.581+        ///   a comma-separated list of namespaces
   3.582+        /// </param>
   3.583+        ///
   3.584+        /// <returns>
   3.585+        ///   a list containing pairs of all possible completions.
   3.586+        ///   eg, if completing on Ba?, maybe return:
   3.587+        ///   (list
   3.588+        ///      ("type"      "Foo.Bar")
   3.589+        ///      ("type"      "Utils.Bands")
   3.590+        ///      ("namespace"  "Barrels")
   3.591+        ///   )
   3.592+        /// </returns>
   3.593+        public static String GetMatches(String fragment, String namespaces)
   3.594+        {
   3.595+            List<String> responseSet = new List<String>();
   3.596+            var reTypeStub = "\\." + fragment + ".*$";
   3.597+            var reNamespace = "^" + fragment + ".*$";
   3.598+            IEnumerable<String> collection;
   3.599+            Tracing.Trace("checking fragment: {0}", fragment);
   3.600+
   3.601+            // look for types with short names that begin with the fragment
   3.602+            collection = _fullNamesForShortNames.Values;
   3.603+            foreach (string ns in namespaces.Split(','))
   3.604+            {
   3.605+                foreach (var value in collection)
   3.606+                {
   3.607+                    Match match = Regex.Match(value,"^"+ns+reTypeStub);
   3.608+                    if (match.Success)
   3.609+                        responseSet.Add(String.Format("(list \"type\" \"{0}\")", value));
   3.610+                }
   3.611+            }
   3.612+
   3.613+            // look for namespaces that begin with the fragment
   3.614+            collection = _typesForNamespace.Keys;
   3.615+            foreach (var key in collection)
   3.616+            {
   3.617+                Match match = Regex.Match(key,reNamespace);
   3.618+                if (match.Success)
   3.619+                    responseSet.Add(String.Format("(list \"namespace\" \"{0}\")", key));
   3.620+
   3.621+                // I think maybe we want to exclude child namespaces. . .
   3.622+                // maybe later.
   3.623+            }
   3.624+
   3.625+            if (responseSet.Count == 0)
   3.626+                return "nil";
   3.627+
   3.628+            string items = String.Join(" ", responseSet.ToArray());
   3.629+            return "(list " + items + ")";
   3.630+        }
   3.631+
   3.632+
   3.633+        /// <summary>
   3.634+        ///   Qualifies the type name.
   3.635+        /// </summary>
   3.636+        /// <param name='typeName'>
   3.637+        ///   the name of the type, possibly a short name, like "Console" or "Stream",
   3.638+        ///   and possibly a long name like System.IO.Stream
   3.639+        /// </param>
   3.640+        /// <returns>
   3.641+        ///   sexp:  (list "fulltypename" "assemblyname") or nil if the type is not known
   3.642+        ///   The assembly name
   3.643+        /// </returns>
   3.644+        public static String QualifyType(String typeName)
   3.645+        {
   3.646+            var name = typeName;
   3.647+            string stub = null;
   3.648+            System.Text.StringBuilder residual = null;
   3.649+            int repeats = 0;
   3.650+
   3.651+            Tracing.Trace("QualifyType: {0}", typeName);
   3.652+
   3.653+            Match match = Regex.Match(name,"(.+`[1-9])\\[.+\\]$");
   3.654+            if (match.Success)
   3.655+                name = match.Groups[1].Value.ToString();
   3.656+
   3.657+            name = name.Trim();
   3.658+            Tracing.Trace("QualifyType: name '{0}'", name);
   3.659+
   3.660+            if (!name.Contains("."))
   3.661+            {
   3.662+                Tracing.Trace("QualifyType: name contains no dot");
   3.663+                Tracing.Trace("QualifyType: examining {0} keys",
   3.664+                              _fullNamesForShortNames.Keys.Count);
   3.665+
   3.666+                foreach (var key in _fullNamesForShortNames.Keys)
   3.667+                {
   3.668+                    if (key.Equals(name))
   3.669+                    {
   3.670+                        return
   3.671+                            String.Format("(list \"{0}\" \"{1}\")",
   3.672+                                          _fullNamesForShortNames[key],
   3.673+                                          _assemblyForType[_fullNamesForShortNames[key]]);
   3.674+                    }
   3.675+                }
   3.676+            }
   3.677+
   3.678+            // it may be a fully-qualified type name
   3.679+            Tracing.Trace("QualifyType: examining {0} full names",
   3.680+                          _fullNamesForShortNames.Values.Count);
   3.681+
   3.682+            foreach (var value in _fullNamesForShortNames.Values)
   3.683+            {
   3.684+                if (stub == null || !value.StartsWith(stub))
   3.685+                {
   3.686+                    int ix = value.LastIndexOf('.');
   3.687+                    stub= (ix > 0)
   3.688+                        ? value.Substring(0, ix)
   3.689+                        : value ;
   3.690+                    repeats = 0;
   3.691+                    if (residual!=null)
   3.692+                    {
   3.693+                        var r = residual.ToString();
   3.694+                        if (!String.IsNullOrEmpty(r))
   3.695+                            Tracing.Trace("  {0}", r);
   3.696+                    }
   3.697+
   3.698+                    residual = new System.Text.StringBuilder();
   3.699+                }
   3.700+                else
   3.701+                {
   3.702+                    residual.Append(".");
   3.703+                    repeats++;
   3.704+                }
   3.705+                if (repeats == 0)
   3.706+                    Tracing.Trace("  check: {0}.*", stub);
   3.707+
   3.708+                // exact match
   3.709+                if (value.Equals(name))
   3.710+                {
   3.711+                    return
   3.712+                        String.Format("(list \"{0}\" \"{1}\")",
   3.713+                                      value,
   3.714+                                      _assemblyForType[value]);
   3.715+                }
   3.716+            }
   3.717+
   3.718+            return "nil";
   3.719+        }
   3.720+
   3.721+
   3.722+
   3.723+
   3.724+        public static string GetConstructors (string typeName)
   3.725+        {
   3.726+            Tracing.Trace("GetConstructors: {0}", typeName);
   3.727+            if (!_assemblyForType.Keys.Contains(typeName))
   3.728+                return "nil";
   3.729+
   3.730+            Assembly a = AssemblyIsLoaded(_assemblyForType[typeName]);
   3.731+            if (a==null)
   3.732+                return "nil";
   3.733+
   3.734+            var tinfo= new Ionic.Cscomp.TypeInfo(a, typeName);
   3.735+            return tinfo.GetConstructorsSexp();
   3.736+        }
   3.737+
   3.738+
   3.739+
   3.740+        public static string GetTypeGivenVarDecl (string csharpVarDeclaration)
   3.741+        {
   3.742+            return GetTypeGivenVarDecl(csharpVarDeclaration, null, null, -1,
   3.743+                                       "Foo1", // classname
   3.744+                                       "", "");
   3.745+        }
   3.746+
   3.747+
   3.748+        /// <summary>
   3.749+        ///   Get the type of the Nth variable in the declaration list.
   3.750+        /// </summary>
   3.751+        /// <remarks>
   3.752+        ///   <para>
   3.753+        ///     This method compiles the provided variable declaration list
   3.754+        ///     into an assembly, and then performs reflection on the result.
   3.755+        ///   </para>
   3.756+        /// </remarks>
   3.757+        ///
   3.758+        /// <param name='csharpVarDeclaration'>
   3.759+        ///   a fragment of csharp code to compile.  It should contain one or
   3.760+        ///   more variable declarations.
   3.761+        /// </param>
   3.762+        /// <param name='varIndex'>
   3.763+        ///   the number of the variable to determine the type of.
   3.764+        ///   There's no way to interrogate the type of a local var by
   3.765+        ///   name. That information is not in the assembly metadata -
   3.766+        ///   it's in the PDB, and it's not easily accessible.  But, the
   3.767+        ///   MSIL apparently lists the local variables in the order in
   3.768+        ///   which they were declared. So we can use the index to find
   3.769+        ///   the desired local var.
   3.770+        /// </param>
   3.771+        /// <param name='namespaces'>
   3.772+        ///   a comma-separated list of namespaces
   3.773+        /// </param>
   3.774+        /// <param name='references'>
   3.775+        ///   a comma-separated list of assembly references
   3.776+        /// </param>
   3.777+        /// <param name='classname'>
   3.778+        ///   name of the class to use. Helpful in satisfying static references.
   3.779+        /// </param>
   3.780+        /// <param name='arglist'>
   3.781+        ///   a comma-separated list of method types and arguments. This is
   3.782+        ///   a legal fragment of C# code, suitable to put right into the method
   3.783+        ///  signature.
   3.784+        /// </param>
   3.785+        public static string GetTypeGivenVarDecl (string csharpVarDeclaration,
   3.786+                                                  String namespaces,
   3.787+                                                  String assemblyReferences,
   3.788+                                                  int varIndex,
   3.789+                                                  String classname,
   3.790+                                                  String arglist,
   3.791+                                                  String instanceMembers)
   3.792+        {
   3.793+            try
   3.794+            {
   3.795+                Tracing.Trace("GetTypeGivenVarDecl {0}", csharpVarDeclaration);
   3.796+                foreach (string aName in namespaces.Split(','))
   3.797+                {
   3.798+                    Tracing.Trace("Autoload assy {0}", aName);
   3.799+                    InternalLoadOneAssembly(aName);
   3.800+                }
   3.801+
   3.802+                Object compileResult = CompileFragment(csharpVarDeclaration,
   3.803+                                                       namespaces,
   3.804+                                                       assemblyReferences,
   3.805+                                                       classname,
   3.806+                                                       arglist,
   3.807+                                                       instanceMembers);
   3.808+
   3.809+                MethodInfo methodInfo = compileResult as MethodInfo;
   3.810+                if (methodInfo == null)
   3.811+                {
   3.812+                    String[] emsgs = (String[]) compileResult;
   3.813+                    var estring = (emsgs!=null)
   3.814+                        ? String.Join("\" \"", emsgs)
   3.815+                        : String.Format("unknown error (cr = {0})",
   3.816+                                        (compileResult==null)?"-null-":compileResult.ToString());
   3.817+                    return String.Format("(list \"error\" \"{0}\")", estring.Replace("\\", "\\\\"));
   3.818+                }
   3.819+
   3.820+
   3.821+                var res = GetTypeOfNthLocalVar(methodInfo, varIndex).ToString();
   3.822+                res = String.Format("(list \"type\" \"{0}\")", res);
   3.823+
   3.824+                Tracing.Trace("GetTypeGivenVarDecl: result {0}", res);
   3.825+
   3.826+                return res;
   3.827+
   3.828+            }
   3.829+            catch (System.Exception exc1)
   3.830+            {
   3.831+                Tracing.Trace("GetTypeGivenVarDecl Exception: {0}", exc1.ToString());
   3.832+                return String.Format ("(list \"exception\" \"{0}\")", exc1.Message);
   3.833+            }
   3.834+        }
   3.835+
   3.836+
   3.837+
   3.838+
   3.839+        private static string GetAssemblyPathForNamespace(String ns)
   3.840+        {
   3.841+            Assembly a = AssemblyIsLoaded(ns);
   3.842+            if (a!=null)
   3.843+                return a.Location;
   3.844+            return null;
   3.845+        }
   3.846+
   3.847+        private static string GetUsingClauses(IEnumerable<String> namespaces)
   3.848+        {
   3.849+            string s = "";
   3.850+            foreach (var ns in namespaces)
   3.851+            {
   3.852+                if (!String.IsNullOrEmpty(ns))
   3.853+                    s += "using " + ns + ";\n";
   3.854+            }
   3.855+            return s;
   3.856+        }
   3.857+
   3.858+
   3.859+
   3.860+        /// <summary>
   3.861+        ///   Compile a C# var declaration fragment.
   3.862+        /// </summary>
   3.863+        /// <remarks>
   3.864+        ///   <para>
   3.865+        ///     The goal is to determine the types of the local variables,
   3.866+        ///     so that we can do completion on them.
   3.867+        ///   </para>
   3.868+        /// </remarks>
   3.869+        /// <param name='fragment'>
   3.870+        ///   a comma-separated list of namespaces
   3.871+        /// </param>
   3.872+        /// <param name='namespaces'>
   3.873+        ///   a comma-separated list of namespaces
   3.874+        /// </param>
   3.875+        /// <param name='references'>
   3.876+        ///   a comma-separated list of assembly references
   3.877+        /// </param>
   3.878+        /// <param name='classname'>
   3.879+        ///   name of the class to use. Helpful in satisfying static references.
   3.880+        /// </param>
   3.881+        /// <param name='arglist'>
   3.882+        ///   a C# fragment, representing an arglist, suitable for
   3.883+        ///   framing within parens for the method declaration.
   3.884+        /// </param>
   3.885+        /// <returns>
   3.886+        ///   a MethodInfo, if success.  Otherwise, an array of Strings containing
   3.887+        ///   error messages.
   3.888+        /// </returns>
   3.889+        private static Object CompileFragment(string fragment,
   3.890+                                              String namespaces,
   3.891+                                              String references,
   3.892+                                              string classname,
   3.893+                                              String arglist,
   3.894+                                              String instanceMembers)
   3.895+        {
   3.896+            string nsname = "N"+Path.GetRandomFileName().Replace(".","");
   3.897+            string methodname = "M"+Path.GetRandomFileName().Replace(".","");
   3.898+            //string classname = Path.GetRandomFileName().Replace(".","");
   3.899+            string usingBlock = (String.IsNullOrEmpty(namespaces))
   3.900+                ? "using System;\n"
   3.901+                : GetUsingClauses(namespaces.Split(','));
   3.902+            string literalSource =
   3.903+                usingBlock +
   3.904+                "\nnamespace " + nsname + " {" +
   3.905+                "\n  class " + classname + " {" +
   3.906+                "\n    " + instanceMembers.Replace("; ",";\n    ")
   3.907+                                          .Replace("} ","}\n    ")
   3.908+                                          .Replace(";}","; }") +
   3.909+                "\n    void "+ methodname + " (" + arglist + ") {"+
   3.910+                "\n      " + fragment.Replace(";",";\n      ") +
   3.911+                "}\n  }\n}\n";
   3.912+
   3.913+            if (Verbose)
   3.914+                System.Console.WriteLine("code to compile:\n{0}", literalSource);
   3.915+
   3.916+            Tracing.Trace("code to compile:\n{0}", literalSource);
   3.917+
   3.918+            try
   3.919+            {
   3.920+                var csharp = new Microsoft.CSharp.CSharpCodeProvider(new Dictionary<String, String> { { "CompilerVersion", "v3.5" } });
   3.921+
   3.922+                var cp = new System.CodeDom.Compiler.CompilerParameters();
   3.923+                cp.GenerateInMemory = true;
   3.924+                cp.GenerateExecutable = false;
   3.925+                cp.IncludeDebugInformation = true;
   3.926+
   3.927+                if (!String.IsNullOrEmpty(references))
   3.928+                    foreach (string ra in references.Split(','))
   3.929+                        cp.ReferencedAssemblies.Add(ra);
   3.930+
   3.931+                // do I need to worry about duplicates?
   3.932+                foreach (string aName in namespaces.Split(','))
   3.933+                {
   3.934+                    Tracing.Trace("maybe add Ref: {0}", aName);
   3.935+                    var path = GetAssemblyPathForNamespace(aName);
   3.936+                    if (path!=null)
   3.937+                        cp.ReferencedAssemblies.Add(path);
   3.938+                }
   3.939+
   3.940+                System.CodeDom.Compiler.CompilerResults cr =
   3.941+                    csharp.CompileAssemblyFromSource(cp,literalSource);
   3.942+                if (cr == null)
   3.943+                {
   3.944+                    var e = new List<String>();
   3.945+                    Tracing.Trace("CompilerResults == null");
   3.946+                    e.Add("CompilerResults == null");
   3.947+                    return e.ToArray();
   3.948+                }
   3.949+
   3.950+                foreach (string s in cr.Output)
   3.951+                {
   3.952+                    if (Verbose)
   3.953+                        System.Console.WriteLine(s);
   3.954+                    Tracing.Trace(s);
   3.955+                }
   3.956+
   3.957+                if (cr.Errors.Count != 0)
   3.958+                {
   3.959+                    var e = new List<String>();
   3.960+                    e.Add(String.Format("Errors.Count = {0}", cr.Errors.Count));
   3.961+                    e.Add(cr.Errors[0].ToString());
   3.962+                    foreach(var error in cr.Errors)
   3.963+                         Tracing.Trace(error.ToString());
   3.964+                    return e.ToArray();
   3.965+                }
   3.966+
   3.967+                var a = cr.CompiledAssembly;
   3.968+                MethodInfo mi = a.GetType(nsname + "." + classname)
   3.969+                    .GetMethod(methodname, BindingFlags.Instance | BindingFlags.NonPublic);
   3.970+
   3.971+                return mi;
   3.972+            }
   3.973+            catch (System.Exception e1)
   3.974+            {
   3.975+                var e = new List<String>();
   3.976+                e.Add("Exception during compile: " + e1.Message );
   3.977+                Tracing.Trace("{0}", e1.ToString());
   3.978+                return e.ToArray();
   3.979+            }
   3.980+        }
   3.981+
   3.982+
   3.983+
   3.984+        /// <summary>
   3.985+        ///   Get the type of the Nth local variable in the given method.
   3.986+        /// </summary>
   3.987+        /// <remarks>
   3.988+        ///   <para>
   3.989+        ///     Reflection doesn't provide access to var names.  And,
   3.990+        ///     some variables listed in LocalVariables are synthetic -
   3.991+        ///     generated by the compiler.  But apparently the IL does
   3.992+        ///     list the format local vars first, and in the order in
   3.993+        ///     which they are declared.  So, to retrieve a local var,
   3.994+        ///     rely on the count.
   3.995+        ///   </para>
   3.996+        /// </remarks>
   3.997+        private static Type GetTypeOfNthLocalVar(MethodInfo methodInfo, int ix)
   3.998+        {
   3.999+            MethodBody body = methodInfo.GetMethodBody();
  3.1000+            var localVars = body.LocalVariables;
  3.1001+            Type ft = null;
  3.1002+            int c = 0;
  3.1003+            foreach (LocalVariableInfo lvi in localVars)
  3.1004+            {
  3.1005+                if (Verbose)
  3.1006+                    System.Console.WriteLine("Local var [{0}] {1}",
  3.1007+                                             c, lvi.LocalType.ToString());
  3.1008+                if (c==ix || ix < 0)
  3.1009+                    ft = lvi.LocalType;
  3.1010+                c++;
  3.1011+            }
  3.1012+            return ft;
  3.1013+        }
  3.1014+
  3.1015+        private static bool _Verbose;
  3.1016+        public static bool Verbose
  3.1017+        {
  3.1018+            get
  3.1019+            {
  3.1020+                return _Verbose;
  3.1021+            }
  3.1022+            set
  3.1023+            {
  3.1024+                if (value)
  3.1025+                {
  3.1026+                    // turn on
  3.1027+                    Tracing.Trace("Verbose = true");
  3.1028+                }
  3.1029+                _Verbose = value;
  3.1030+            }
  3.1031+        }
  3.1032+
  3.1033+
  3.1034+    }
  3.1035+
  3.1036+
  3.1037+
  3.1038+    public class TypeInfo
  3.1039+    {
  3.1040+        internal TypeInfo(Assembly a, string typeName)
  3.1041+        {
  3.1042+            mt = a.GetType(typeName, false, true);
  3.1043+            if ( mt == null )
  3.1044+                throw new Exception(String.Format("Cannot get that type ({0})", typeName));
  3.1045+        }
  3.1046+
  3.1047+        /// <summary>
  3.1048+        ///   Returns the TypeInfo as a lisp S-expression.
  3.1049+        /// </summary>
  3.1050+        /// <remarks>
  3.1051+        ///   <para>
  3.1052+        ///     It looks like this:
  3.1053+        ///
  3.1054+        ///   </para>
  3.1055+        /// </remarks>
  3.1056+        internal String AsSexp()
  3.1057+        {
  3.1058+            var result= new System.Text.StringBuilder();
  3.1059+            result.Append("(list \"").Append(mt.FullName).Append("\" 'type (list ");
  3.1060+
  3.1061+            // properties
  3.1062+            var props = GetPropertiesInfo();
  3.1063+            if (props != null)
  3.1064+            {
  3.1065+                foreach (string s in props)
  3.1066+                    result.Append(s);
  3.1067+            }
  3.1068+
  3.1069+            result.Append(") (list ");
  3.1070+
  3.1071+            // methods
  3.1072+            var meth = GetMethodsInfo();
  3.1073+            if (meth != null)
  3.1074+            {
  3.1075+                foreach (string s in meth)
  3.1076+                    result.Append(s);
  3.1077+
  3.1078+            }
  3.1079+            result.Append(") (list ");
  3.1080+
  3.1081+
  3.1082+            // fields
  3.1083+            var fields = GetFieldsInfo();
  3.1084+            if (fields != null)
  3.1085+            {
  3.1086+                foreach (string s in fields)
  3.1087+                    result.Append(s);
  3.1088+
  3.1089+            }
  3.1090+            result.Append(")");
  3.1091+
  3.1092+            // events?  constructors?
  3.1093+
  3.1094+            result.Append(")");
  3.1095+            return result.ToString();
  3.1096+        }
  3.1097+
  3.1098+        //     public String LastError { get { return lastError;}  }
  3.1099+        //     public Type   TheType   { get { return mt;      }  }
  3.1100+        //     public String FQN       { get { return (mt!=null) ? mt.AssemblyQualifiedName: null; }  }
  3.1101+        //     public String Name      { get { return (mt!=null) ? mt.Name: null;}  }
  3.1102+        //     public String FullName  { get { return (mt != null) ? mt.FullName : null;}  }
  3.1103+        //     public String Status    { get { return status;}  }
  3.1104+
  3.1105+        //     public String Href
  3.1106+        //     {
  3.1107+        //       set { theHref= value; }
  3.1108+        //       get { return theHref; }
  3.1109+        //     }
  3.1110+
  3.1111+        private static Type ReferencedType(Type t)
  3.1112+        {
  3.1113+            return (t.HasElementType) ? ReferencedType(t.GetElementType()) : t ;
  3.1114+        }
  3.1115+
  3.1116+        private static String EmitOneType(Type t1)
  3.1117+        {
  3.1118+            return t1.ToString();
  3.1119+        }
  3.1120+
  3.1121+
  3.1122+        private static String EmitOneTypeWithInterfaces(Type t1)
  3.1123+        {
  3.1124+            Type t= ReferencedType(t1);
  3.1125+            var result= new System.Text.StringBuilder();
  3.1126+            result.Append(t1.ToString());
  3.1127+
  3.1128+            Type[] it=  t.GetInterfaces();
  3.1129+            if (it.Length > 0 )
  3.1130+            {
  3.1131+                int j=0;
  3.1132+                for (int i=0; i < it.Length; i++)
  3.1133+                {
  3.1134+                    if ((t.BaseType!=null) && !(it[i].IsAssignableFrom(t.BaseType)))
  3.1135+                    {
  3.1136+                        if (j==0) result.Append(" : ");
  3.1137+                        else result.Append(", ");
  3.1138+                        result.Append(EmitOneType(it[i]));
  3.1139+                        j++;
  3.1140+                    }
  3.1141+                }
  3.1142+            }
  3.1143+
  3.1144+            return result.ToString();
  3.1145+        }
  3.1146+
  3.1147+
  3.1148+
  3.1149+        private string ParamString(System.Reflection.ParameterInfo[] pi, bool isProperty)
  3.1150+        {
  3.1151+            if (pi.Length==0) return "nil";
  3.1152+
  3.1153+            var sb=  new System.Text.StringBuilder("(list ");
  3.1154+            int j;
  3.1155+            String openBracket= "(";
  3.1156+            String closeBracket= ")";
  3.1157+            if (isProperty)
  3.1158+            {
  3.1159+                openBracket= "[";
  3.1160+                closeBracket= "]";
  3.1161+            }
  3.1162+
  3.1163+            for (j=0; j < pi.Length; j++)
  3.1164+            {
  3.1165+                // ParameterAttributes Attributes =  pi[j].Attributes;
  3.1166+                // if (Attributes != ParameterAttributes.None)
  3.1167+                //     sb.Append("[").Append(Attributes.ToString()).Append("] "); // eg, In,Out,Optional
  3.1168+
  3.1169+                sb.Append("\"").Append(pi[j].ParameterType.ToString())
  3.1170+                    .Append(" ")
  3.1171+                    .Append(pi[j].Name)
  3.1172+                    .Append("\" ");
  3.1173+            }
  3.1174+            if (isProperty)
  3.1175+            {
  3.1176+                if (j!=0) sb.Append(closeBracket);
  3.1177+            }
  3.1178+            else
  3.1179+            {
  3.1180+                if (j==0) sb.Append(openBracket);
  3.1181+                sb.Append(closeBracket);
  3.1182+            }
  3.1183+
  3.1184+            return sb.ToString();
  3.1185+        }
  3.1186+
  3.1187+
  3.1188+        private string NewParamString(System.Reflection.ParameterInfo[] pi)
  3.1189+        {
  3.1190+            if (pi.Length==0) return "nil";
  3.1191+            var sb=  new System.Text.StringBuilder("(list ");
  3.1192+            for (int j=0; j < pi.Length; j++)
  3.1193+            {
  3.1194+                sb.Append("(list \"")
  3.1195+                    .Append(pi[j].Name)
  3.1196+                    .Append("\" 'variable (list :type \"")
  3.1197+                    .Append(pi[j].ParameterType.ToString())
  3.1198+                    .Append("\")) ");
  3.1199+            }
  3.1200+            sb.Append(")");
  3.1201+            return sb.ToString();
  3.1202+        }
  3.1203+
  3.1204+
  3.1205+        private static String EmitAttributes(Type t) {
  3.1206+            System.Text.StringBuilder result= new System.Text.StringBuilder();
  3.1207+            if (t.IsSerializable)   result.Append("[serializable]<br>\n ");
  3.1208+            if (t.IsPublic)         result.Append("public ");
  3.1209+            if (t.IsAbstract)       result.Append("abstract ");
  3.1210+            if (t.IsSealed)         result.Append("sealed ");
  3.1211+            if (t.IsClass)          result.Append("class ");
  3.1212+            if (t.IsEnum)           result.Append("enum ");
  3.1213+            if (t.IsInterface)      result.Append("interface ");
  3.1214+            return result.ToString();
  3.1215+        }
  3.1216+
  3.1217+
  3.1218+        internal String GetConstructorsSexp()
  3.1219+        {
  3.1220+            if (mt==null) return "nil";
  3.1221+            System.Reflection.ConstructorInfo[] cia= mt.GetConstructors();
  3.1222+            if (cia==null) return "nil";
  3.1223+            if (cia.Length==0) return "nil";
  3.1224+
  3.1225+            Tracing.Trace("{1}: Found {0} constructors", cia.Length, mt.FullName);
  3.1226+
  3.1227+            var sb1 = new System.Text.StringBuilder();
  3.1228+            sb1.Append("(list \"").Append(mt.FullName)
  3.1229+                .Append("\" 'type (list :constructors (list\n");
  3.1230+
  3.1231+            foreach (ConstructorInfo ci in cia)
  3.1232+            {
  3.1233+                sb1.Append(" (list :typemodifiers ")
  3.1234+                    .Append(NewMethodBaseModifiers(ci))
  3.1235+                    .Append(" :arguments ")
  3.1236+                    .Append(NewParamString(ci.GetParameters()))
  3.1237+                    .Append(")\n");
  3.1238+            }
  3.1239+            sb1.Append(")))");
  3.1240+            return sb1.ToString();
  3.1241+        }
  3.1242+
  3.1243+
  3.1244+
  3.1245+        private String PropertyModifiers(PropertyInfo p)
  3.1246+        {
  3.1247+            var sb= new System.Text.StringBuilder("(cons 'typemodifiers (list ");
  3.1248+            System.Reflection.MethodInfo mi= null;
  3.1249+
  3.1250+            if (p.GetGetMethod() != null)
  3.1251+            {
  3.1252+                mi= p.GetGetMethod();
  3.1253+                if (p.GetSetMethod() == null)
  3.1254+                    sb.Append("\"readonly\" ");
  3.1255+            }
  3.1256+            else if (p.GetSetMethod() != null) {
  3.1257+                mi= p.GetSetMethod();
  3.1258+                sb.Append("\"writeonly\" ");
  3.1259+            }
  3.1260+
  3.1261+            if (mi != null) {
  3.1262+                if (mi.IsPublic)
  3.1263+                    sb.Append("\"public\" ");
  3.1264+                if (mi.IsPrivate)
  3.1265+                    sb.Append("\"private\" ");
  3.1266+                if (mi.IsFamily)
  3.1267+                    sb.Append("\"protected\" ");
  3.1268+
  3.1269+                if (mi.IsStatic)
  3.1270+                    sb.Append("\"static\" ");
  3.1271+            }
  3.1272+
  3.1273+            sb.Append("))");
  3.1274+            return sb.ToString();
  3.1275+        }
  3.1276+
  3.1277+
  3.1278+        private String[] GetPropertiesInfo()
  3.1279+        {
  3.1280+            if (mt==null) return null;
  3.1281+            System.Reflection.PropertyInfo[] pi= mt.GetProperties();
  3.1282+            if (pi==null) return null;
  3.1283+            if (pi.Length==0) return null;
  3.1284+
  3.1285+            var a= new List<String>();
  3.1286+            System.Text.StringBuilder sb1;
  3.1287+            foreach (PropertyInfo p in pi) {
  3.1288+
  3.1289+                sb1 = new System.Text.StringBuilder();
  3.1290+                sb1.Append("(list \"").Append(p.Name).Append("\" 'property ");
  3.1291+
  3.1292+                sb1.Append("\"").Append(p.PropertyType.ToString()).Append("\" ");
  3.1293+
  3.1294+                sb1.Append(PropertyModifiers(p));
  3.1295+
  3.1296+                sb1.Append(")");
  3.1297+
  3.1298+                a.Add(sb1.ToString());
  3.1299+            }
  3.1300+            return a.ToArray();
  3.1301+        }
  3.1302+
  3.1303+
  3.1304+
  3.1305+        private String EmitMethodAttrs(MethodInfo m) {
  3.1306+            System.Text.StringBuilder result= new System.Text.StringBuilder();
  3.1307+
  3.1308+            if (m.IsPublic)
  3.1309+                result.Append("public ");
  3.1310+
  3.1311+            if (m.IsFamily)
  3.1312+                result.Append("protected ");
  3.1313+
  3.1314+            if (m.IsPrivate)
  3.1315+                result.Append("private ");
  3.1316+
  3.1317+            if (m.IsAbstract)
  3.1318+                result.Append("abstract ");
  3.1319+
  3.1320+            if (m.IsStatic)
  3.1321+                result.Append("static ");
  3.1322+
  3.1323+            if (m.IsFinal)
  3.1324+                result.Append("final ");
  3.1325+
  3.1326+            return result.ToString();
  3.1327+        }
  3.1328+
  3.1329+
  3.1330+
  3.1331+        public String[] GetMethodsInfo()
  3.1332+        {
  3.1333+            System.Reflection.MethodInfo[] mi= mt.GetMethods();
  3.1334+            System.Array.Sort(mi,new MpfComparer());
  3.1335+            var a= new List<String>();
  3.1336+            System.Text.StringBuilder sb1;
  3.1337+            foreach (MethodInfo m in mi)
  3.1338+            {
  3.1339+                sb1= null;
  3.1340+
  3.1341+                if (m.IsPrivate) continue;
  3.1342+
  3.1343+                // special name denotes???? I don't know.
  3.1344+                if (!m.IsSpecialName)
  3.1345+                {
  3.1346+                    // it's a method:
  3.1347+                    sb1 = new System.Text.StringBuilder(" (list \"");
  3.1348+                    sb1.Append(m.Name).Append("\" 'method ")
  3.1349+                        .Append("\"").Append(m.ReturnType.ToString()).Append("\" ")
  3.1350+                        .Append(ParamString(m.GetParameters(), false))
  3.1351+                        .Append(MethodBaseModifiers(m))
  3.1352+                        .Append(")");
  3.1353+                }
  3.1354+
  3.1355+                if (sb1 != null)
  3.1356+                    a.Add(sb1.ToString());
  3.1357+            }
  3.1358+            return a.ToArray();
  3.1359+        }
  3.1360+
  3.1361+
  3.1362+
  3.1363+        private string MethodBaseModifiers(MethodBase mi)
  3.1364+        {
  3.1365+            var sb= new System.Text.StringBuilder(" (cons 'typemodifiers (list ");
  3.1366+            if (mi.IsFinal)
  3.1367+                sb.Append("\"sealed\" ");
  3.1368+            if (mi.IsPublic)
  3.1369+                sb.Append("\"public\" ");
  3.1370+            if (mi.IsPrivate)
  3.1371+                sb.Append("\"private\" ");
  3.1372+            if (mi.IsFamily)
  3.1373+                sb.Append("\"protected\" ");
  3.1374+            if (mi.IsStatic)
  3.1375+                sb.Append("\"static\" ");
  3.1376+            sb.Append("))");
  3.1377+            return sb.ToString();
  3.1378+        }
  3.1379+
  3.1380+
  3.1381+        private string NewMethodBaseModifiers(MethodBase mi)
  3.1382+        {
  3.1383+            var sb= new System.Text.StringBuilder(" (list ");
  3.1384+            if (mi.IsFinal)
  3.1385+                sb.Append("\"sealed\" ");
  3.1386+            if (mi.IsPublic)
  3.1387+                sb.Append("\"public\" ");
  3.1388+            if (mi.IsPrivate)
  3.1389+                sb.Append("\"private\" ");
  3.1390+            if (mi.IsFamily)
  3.1391+                sb.Append("\"protected\" ");
  3.1392+            if (mi.IsStatic)
  3.1393+                sb.Append("\"static\" ");
  3.1394+            sb.Append(")");
  3.1395+            return sb.ToString();
  3.1396+        }
  3.1397+
  3.1398+
  3.1399+        //     private void BuildClassHierarchy(Type t) {
  3.1400+        //       classHierarchy.Push(t);
  3.1401+        //       if (t.BaseType != null)
  3.1402+        //      BuildClassHierarchy(t.BaseType);
  3.1403+        //     }
  3.1404+
  3.1405+
  3.1406+        //     public String GetHierarchyHtml() {
  3.1407+        //       if (mt == null) return null;
  3.1408+        //       classHierarchy= new Stack();
  3.1409+        //       BuildClassHierarchy(mt);
  3.1410+        //       int c= classHierarchy.Count;
  3.1411+        //       System.Text.StringBuilder sb= new System.Text.StringBuilder("\n");
  3.1412+        //       int i=0;
  3.1413+        //       while (classHierarchy.Count != 0) {
  3.1414+        //      sb.Append("<div class='elt'>");
  3.1415+        //      if (i!=0) sb.Append("+&nbsp;");
  3.1416+        //      sb.Append(EmitOneTypeWithInterfaces((Type)classHierarchy.Pop())).Append("\n");
  3.1417+        //      i++;
  3.1418+        //       }
  3.1419+        //       for (i=0; i < c; i++) sb.Append("</div>");
  3.1420+
  3.1421+        //       return sb.ToString();
  3.1422+        //     }
  3.1423+
  3.1424+
  3.1425+
  3.1426+
  3.1427+        //     public String[] GetPropertiesHtml() {
  3.1428+        //       if (mt == null) return null;
  3.1429+        //       System.Reflection.PropertyInfo[] pi= mt.GetProperties();
  3.1430+        //       System.Array.Sort(pi,new myComparer());  // by name
  3.1431+        //       ArrayList a= new ArrayList();
  3.1432+        //       System.Text.StringBuilder sb1;
  3.1433+        //       foreach (PropertyInfo p in pi) {
  3.1434+        //      try{
  3.1435+        //        sb1 = new System.Text.StringBuilder();
  3.1436+        //        sb1.Append("  ").Append(PropAttrsString(p));
  3.1437+        //        sb1.Append("  ").Append(EmitOneType(p.PropertyType));
  3.1438+        //        sb1.Append("  <b>").Append(p.Name).Append("</b>");
  3.1439+        //        AppendParams(sb1,p.GetIndexParameters(), true);
  3.1440+        //      }
  3.1441+        //      catch(Exception e){
  3.1442+        //        a.Add(e.Message);
  3.1443+        //        continue;
  3.1444+        //      }
  3.1445+        //      a.Add(sb1.ToString());
  3.1446+        //       }
  3.1447+        //       return (String[]) a.ToArray(typeof(String));
  3.1448+        //     }
  3.1449+
  3.1450+
  3.1451+
  3.1452+        private static String FieldAttrsString(FieldInfo f)
  3.1453+        {
  3.1454+            var sb= new System.Text.StringBuilder(" (cons 'typemodifiers (list ");
  3.1455+            if (f.IsPublic)
  3.1456+                sb.Append("\"public\" ");
  3.1457+            if (f.IsFamily)
  3.1458+                sb.Append("\"protected\" ");
  3.1459+            if (f.IsPrivate)
  3.1460+                sb.Append("\"private\" ");
  3.1461+            if (f.IsLiteral)
  3.1462+                sb.Append("\"const\" ");
  3.1463+            if (f.IsStatic)
  3.1464+                sb.Append("\"static\" ");
  3.1465+            sb.Append("))");
  3.1466+            return sb.ToString();
  3.1467+        }
  3.1468+
  3.1469+
  3.1470+        public String[] GetFieldsInfo()
  3.1471+        {
  3.1472+            if (mt == null) return null;
  3.1473+            System.Reflection.FieldInfo[] fi= mt.GetFields();
  3.1474+            System.Array.Sort(fi,new MpfComparer());  // by name
  3.1475+            var a= new List<String>();
  3.1476+            System.Text.StringBuilder sb1;
  3.1477+            foreach (FieldInfo f in fi)
  3.1478+            {
  3.1479+                if (!f.IsPrivate)
  3.1480+                {
  3.1481+                    try
  3.1482+                    {
  3.1483+                        sb1 = new System.Text.StringBuilder(" (list \"");
  3.1484+                        sb1.Append(f.Name).Append("\" 'field ")
  3.1485+                            .Append("\"").Append(f.FieldType.ToString()).Append("\" ")
  3.1486+                            .Append(FieldAttrsString(f))
  3.1487+                            .Append(")");
  3.1488+                    }
  3.1489+                    catch(Exception e){
  3.1490+                        a.Add(e.Message);
  3.1491+                        continue;
  3.1492+                    }
  3.1493+                    if (sb1 != null)
  3.1494+                        a.Add(sb1.ToString());
  3.1495+                }
  3.1496+            }
  3.1497+            return a.ToArray();
  3.1498+        }
  3.1499+
  3.1500+        private System.Type mt;
  3.1501+    }
  3.1502+
  3.1503+
  3.1504+
  3.1505+    public class MpfComparer : System.Collections.IComparer
  3.1506+    {
  3.1507+        static Type mi= typeof(MethodInfo);
  3.1508+        static Type pi= typeof(PropertyInfo);
  3.1509+        static Type fi= typeof(FieldInfo);
  3.1510+
  3.1511+        public int Compare (Object x, Object y)
  3.1512+        {
  3.1513+            if (mi.IsInstanceOfType(x)) {
  3.1514+                MethodInfo i1= (MethodInfo) x;
  3.1515+                MethodInfo i2= (MethodInfo) y;
  3.1516+                return i1.Name.CompareTo(i2.Name);
  3.1517+            }
  3.1518+
  3.1519+            if (pi.IsInstanceOfType(x)) {
  3.1520+                PropertyInfo i1= (PropertyInfo) x;
  3.1521+                PropertyInfo i2= (PropertyInfo) y;
  3.1522+                return i1.Name.CompareTo(i2.Name);
  3.1523+            }
  3.1524+            if (fi.IsInstanceOfType(x)) {
  3.1525+                FieldInfo i1= (FieldInfo) x;
  3.1526+                FieldInfo i2= (FieldInfo) y;
  3.1527+                return i1.Name.CompareTo(i2.Name);
  3.1528+            }
  3.1529+
  3.1530+            return 0;
  3.1531+        }
  3.1532+    }
  3.1533+
  3.1534+    internal static class Tracing
  3.1535+    {
  3.1536+        #if UseCopyData
  3.1537+        private static  Ionic.CopyData.Transceiver transceiver;
  3.1538+        #endif
  3.1539+
  3.1540+        [Conditional("CscompTrace")]
  3.1541+        public static void SetupDebugConsole()
  3.1542+        {
  3.1543+        #if UseCopyData
  3.1544+
  3.1545+            // use object initializer syntax
  3.1546+            System.Diagnostics.Process p3 = new System.Diagnostics.Process
  3.1547+                {
  3.1548+                    StartInfo =
  3.1549+                    {
  3.1550+                        FileName = "c:\\dinoch\\vsp\\UnitTestProgressMonitor\\UnitTestProgressMonitor\\bin\\Debug\\UnitTestProgressMonitor.exe",
  3.1551+                        Arguments = "-channel CscompShell",
  3.1552+                        CreateNoWindow = false,
  3.1553+                        UseShellExecute = false
  3.1554+                    }
  3.1555+                };
  3.1556+            p3.Start();
  3.1557+
  3.1558+            // wait for the process to start?
  3.1559+            System.Threading.Thread.Sleep(650);
  3.1560+
  3.1561+            transceiver = new Ionic.CopyData.Transceiver();
  3.1562+            transceiver.Channel = "CscompShell";
  3.1563+
  3.1564+            transceiver.Send("title CSDE Shell Trace Monitor");
  3.1565+
  3.1566+            System.Threading.Thread.Sleep(400);
  3.1567+            transceiver.Send("log Hello from CscompShell");
  3.1568+        #endif
  3.1569+        }
  3.1570+
  3.1571+
  3.1572+        [Conditional("CscompTrace")]
  3.1573+        public static void Trace(string format, params object[] args)
  3.1574+        {
  3.1575+        #if UseCopyData
  3.1576+            var s2 = String.Format(format, args);
  3.1577+            transceiver.Send("log " + s2);
  3.1578+        #endif
  3.1579+        }
  3.1580+
  3.1581+    }
  3.1582+
  3.1583+}
  3.1584+
  3.1585+
  3.1586+
  3.1587+/*
  3.1588+
  3.1589+  [System.Reflection.Assembly]::LoadFrom("c:\\dinoch\\dev\\dotnet\\CscompUtilities.dll");
  3.1590+  [Ionic.Cscomp.Utilities]::Verbose = $TRUE
  3.1591+
  3.1592+  [Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl(' var foo = "this is a string"; var fred = new System.Collections.Generic.List<String> { foo, foo.Length.ToString() }; var z = fred.Count; var mmm = count + 8; var nnn = mmm.ToString() + this.InstanceMethod1(count);','System,System.Xml,System.IO','',4,'CsharpCompletion','int count','private static int staticField1 = default(int); string InstanceMethod1(int index) { return default(string);} ')
  3.1593+
  3.1594+
  3.1595+  [Ionic.Cscomp.Utilities]::GetConstructors("System.String");
  3.1596+
  3.1597+  [Ionic.Cscomp.Utilities]::GetConstructors("System.DateTimeKind");
  3.1598+
  3.1599+  [Ionic.Cscomp.Utilities]::GetMatches("DateT", "System,System.IO");
  3.1600+
  3.1601+
  3.1602+
  3.1603+  [Ionic.Cscomp.Utilities]::QualifyType("System.Collections.Generic.List`1");
  3.1604+
  3.1605+  [Ionic.Cscomp.Utilities]::GetTypeInfo("System.Collections.Generic.List");
  3.1606+
  3.1607+  [Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl('var x = String.Format("{0}", 928);' )
  3.1608+
  3.1609+  [Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl('var x = new System.Collections.Generic.List<string>();')
  3.1610+
  3.1611+
  3.1612+
  3.1613+[Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl(' var doo = "Tra la la"; var fred = new System.Collections.Generic.List<String>
  3.1614+            {
  3.1615+                doo.Length.ToString()
  3.1616+            };');
  3.1617+
  3.1618+[Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl(' var doo = "Tra la la"; var fred = new System.Collections.Generic.List<String> { doo.Length.ToString() };', $null, $null, 2);
  3.1619+
  3.1620+
  3.1621+
  3.1622+  [Ionic.Cscomp.Utilities]::GetTypeInfo("System.Data.SqlClient.SqlCommand","System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
  3.1623+
  3.1624+  [Ionic.Cscomp.Utilities]::GetTypeInfo("System.Xml.XmlReader","System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
  3.1625+
  3.1626+
  3.1627+  [Ionic.Cscomp.Utilities]::GetTypeInfo("System.DateTime");
  3.1628+
  3.1629+  [Ionic.Cscomp.Utilities]::QualifyType("System.DateTime");
  3.1630+
  3.1631+  [Ionic.Cscomp.Utilities]::QualifyType("XmlSerializer");
  3.1632+
  3.1633+  [Ionic.Cscomp.Utilities]::QualifyType("System.Xml.XmlReader");
  3.1634+
  3.1635+  [Ionic.Cscomp.Utilities]::QualifyType("System.This.Type.Does.Not.Exist");
  3.1636+
  3.1637+
  3.1638+  [Ionic.Cscomp.Utilities]::LoadOneAssembly("Ionic.Zip.dll");
  3.1639+
  3.1640+  [Ionic.Cscomp.Utilities]::LoadOneAssembly("System.Xml");
  3.1641+
  3.1642+  [Ionic.Cscomp.Utilities]::QualifyName("System.Xml");
  3.1643+
  3.1644+  [Ionic.Cscomp.Utilities]::GetCompletionsForNamespace("System.Collections.Generic")
  3.1645+
  3.1646+  [Ionic.Cscomp.Utilities]::ListLoadedAssemblies();
  3.1647+
  3.1648+
  3.1649+  [Ionic.Cscomp.Utilities]::ListKnownTypes();
  3.1650+
  3.1651+
  3.1652+  [Ionic.Cscomp.Utilities]::Version();
  3.1653+
  3.1654+
  3.1655+  ;(debug-on-entry 'csde-complete-referenced-assemblies-list)
  3.1656+
  3.1657+  (semantic-brute-find-tag-by-class 'using)
  3.1658+
  3.1659+*/
  3.1660+
  3.1661+
     4.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2+++ b/csharp-mode/Readme.txt	Wed Nov 10 15:19:03 2010 +0200
     4.3@@ -0,0 +1,69 @@
     4.4+Mon, 24 May 2010  17:21
     4.5+
     4.6+This is the readme for csharp-mode.
     4.7+
     4.8+You can use csharp-mode alone.  To do so,
     4.9+
    4.10+
    4.11+ put this in your .emacs:
    4.12+
    4.13+   (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t)
    4.14+
    4.15+ or:
    4.16+
    4.17+   (require 'csharp-mode)
    4.18+
    4.19+
    4.20+ AND:
    4.21+
    4.22+   (setq auto-mode-alist
    4.23+      (append '(("\\.cs$" . csharp-mode)) auto-mode-alist))
    4.24+   (defun my-csharp-mode-fn ()
    4.25+      "function that runs when csharp-mode is initialized for a buffer."
    4.26+      ...insert your code here...
    4.27+      ...most commonly, your custom key bindings ...
    4.28+   )
    4.29+   (add-hook  'csharp-mode-hook 'my-csharp-mode-fn t)
    4.30+
    4.31+
    4.32+=======================================================
    4.33+
    4.34+You can also take advantage of C# code completion.
    4.35+To do so, put csharp-completion.el, csharp-shell.el , and powershell.el
    4.36+on your load-path.
    4.37+
    4.38+You must also have semantic, from the CEDET package, on your load path.
    4.39+
    4.40+Put the CscompUtilities.dll in the same location as csharp-shell.el.
    4.41+
    4.42+Put this in your .emacs file:
    4.43+
    4.44+
    4.45+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    4.46+    ;; C# code completion (requires CEDET semantic)
    4.47+
    4.48+    (setq load-path
    4.49+          (append '("~/users/dinoch/elisp/cedet/semantic"
    4.50+                    "~/users/dinoch/elisp/cedet/semantic/bovine"
    4.51+                    "~/users/dinoch/elisp/cedet/common"
    4.52+                    "~/users/dinoch/elisp/cedet/eieio"
    4.53+                    "~/users/dinoch/elisp/cedet/contrib"
    4.54+                    )  load-path ))
    4.55+
    4.56+    (load "semantic")
    4.57+    (load "semantic-load")
    4.58+    (load "wisent-csharp")
    4.59+
    4.60+    (require 'csharp-completion)
    4.61+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    4.62+
    4.63+
    4.64+In your csharp-mode-hook, bind a key to the cscomp completion trigger.
    4.65+Like this:
    4.66+
    4.67+         ;; C# code completion
    4.68+         (local-set-key "\M-\\"   'cscomp-complete-at-point)
    4.69+         (local-set-key "\M-\."   'cscomp-complete-at-point-menu)
    4.70+
    4.71+
    4.72+
     5.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2+++ b/csharp-mode/aspx-mode.el	Wed Nov 10 15:19:03 2010 +0200
     5.3@@ -0,0 +1,496 @@
     5.4+;;; aspx-mode.el --- mode for editing ASPX files
     5.5+;;
     5.6+;; Copyright (C) 2010  Dino Chiesa
     5.7+;;
     5.8+;; Author:   Dino Chiesa <dpchiesa@hotmail.com>
     5.9+;; Created:  May 2010
    5.10+;; Version:  0.1
    5.11+;; Keywords: C#, languages, extensions, files
    5.12+;; URL:      ???
    5.13+;;
    5.14+;; This is an emacs mode for editing single-file ASPX modules,
    5.15+;; which can contain HTML, javascript, C# or VB, and
    5.16+;; CSS code.
    5.17+;;
    5.18+;; It relies on multi-mode.
    5.19+;; (see http://www.loveshack.ukfsn.org/emacs )
    5.20+;;
    5.21+;; It provides context-sensitive fontification and indent in all of the
    5.22+;; various chunks o an ASPX file. Browser-side Javascript within script
    5.23+;; blocks gets fontified correctly. Server-side script blocks get
    5.24+;; fontified properly. CSS gets indented and fontified. And of course
    5.25+;; HTML.
    5.26+;;
    5.27+;; It relies on espresso for the javascript mode, css-mode for CSS,
    5.28+;; html-mode for HTML, and csharp-mode 0.7.5 or later for the
    5.29+;; server-side c# code.
    5.30+;;
    5.31+;; Bugs:
    5.32+;;
    5.33+;;  - The fontification sort of turns on and off as you cursor through
    5.34+;;    the buffer, making for a somewhat odd user experience.
    5.35+;;
    5.36+;;  - the fontification sometimes doesn't happen within a chunk, til you
    5.37+;;    modify the text within the chunk.  There's probably a fix for
    5.38+;;    this.
    5.39+;;
    5.40+;;
    5.41+;; Thu, 13 May 2010  23:44
    5.42+;;
    5.43+;; Licensed according to the Microsoft Public License (Ms-PL)
    5.44+;;
    5.45+;; This license governs use of the accompanying software. If you use
    5.46+;; the software, you accept this license. If you do not accept the
    5.47+;; license, do not use the software.
    5.48+;;
    5.49+;; 1. Definitions
    5.50+;;
    5.51+;; The terms "reproduce," "reproduction," "derivative
    5.52+;; works," and "distribution" have the same meaning here as under
    5.53+;; U.S. copyright law.
    5.54+;;
    5.55+;; A "contribution" is the original software, or any additions or
    5.56+;; changes to the software.
    5.57+;;
    5.58+;; A "contributor" is any person that distributes its contribution
    5.59+;; under this license.
    5.60+;;
    5.61+;; "Licensed patents" are a contributor's patent claims that read
    5.62+;; directly on its contribution.
    5.63+;;
    5.64+;; 2. Grant of Rights
    5.65+;;
    5.66+;; (A) Copyright Grant- Subject to the terms of this license,
    5.67+;; including the license conditions and limitations in section 3,
    5.68+;; each contributor grants you a non-exclusive, worldwide,
    5.69+;; royalty-free copyright license to reproduce its contribution,
    5.70+;; prepare derivative works of its contribution, and distribute its
    5.71+;; contribution or any derivative works that you create.
    5.72+;;
    5.73+;; (B) Patent Grant- Subject to the terms of this license, including
    5.74+;; the license conditions and limitations in section 3, each
    5.75+;; contributor grants you a non-exclusive, worldwide, royalty-free
    5.76+;; license under its licensed patents to make, have made, use, sell,
    5.77+;; offer for sale, import, and/or otherwise dispose of its
    5.78+;; contribution in the software or derivative works of the
    5.79+;; contribution in the software.
    5.80+;;
    5.81+;; 3. Conditions and Limitations
    5.82+;;
    5.83+;; (A) No Trademark License- This license does not grant you rights
    5.84+;; to use any contributors' name, logo, or trademarks.
    5.85+;;
    5.86+;; (B) If you bring a patent claim against any contributor over
    5.87+;; patents that you claim are infringed by the software, your patent
    5.88+;; license from such contributor to the software ends automatically.
    5.89+;;
    5.90+;; (C) If you distribute any portion of the software, you must
    5.91+;; retain all copyright, patent, trademark, and attribution notices
    5.92+;; that are present in the software.
    5.93+;;
    5.94+;; (D) If you distribute any portion of the software in source code
    5.95+;; form, you may do so only under this license by including a
    5.96+;; complete copy of this license with your distribution. If you
    5.97+;; distribute any portion of the software in compiled or object code
    5.98+;; form, you may only do so under a license that complies with this
    5.99+;; license.
   5.100+;;
   5.101+;; (E) The software is licensed "as-is." You bear the risk of using
   5.102+;; it. The contributors give no express warranties, guarantees or
   5.103+;; conditions. You may have additional consumer rights under your
   5.104+;; local laws which this license cannot change. To the extent
   5.105+;; permitted under your local laws, the contributors exclude the
   5.106+;; implied warranties of merchantability, fitness for a particular
   5.107+;; purpose and non-infringement.
   5.108+;;
   5.109+;;;
   5.110+
   5.111+
   5.112+(require 'multi-mode)
   5.113+(require 'csharp-mode)
   5.114+(require 'espresso "espresso.el")
   5.115+;;(require 'javascript-mode "javascript.el")
   5.116+(require 'css-mode)
   5.117+
   5.118+
   5.119+
   5.120+(defvar aspx-mode-log-level 0
   5.121+  "The current log level for operatopms specific to aspx-mode.
   5.122+0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY. ")
   5.123+
   5.124+
   5.125+(defun aspx-mode-log (level text &rest args)
   5.126+  "Log a message at level LEVEL.
   5.127+If LEVEL is higher than `aspx-mode-log-level', the message is
   5.128+ignored.  Otherwise, it is printed using `message'.
   5.129+TEXT is a format control string, and the remaining arguments ARGS
   5.130+are the string substitutions (see `format')."
   5.131+  (if (<= level aspx-mode-log-level)
   5.132+      (let* ((msg (apply 'format text args)))
   5.133+        (message "aspx-mode: %s" msg))
   5.134+    t))
   5.135+
   5.136+
   5.137+(defconst aspx-mode-server-lang-re
   5.138+  "\\([Cc]#\\|[Vv][Bb]\\)"
   5.139+  "Regex for matching on the ASPX langauge.")
   5.140+
   5.141+
   5.142+(defconst aspx-mode-server-script-start-re
   5.143+  (concat
   5.144+   "<\\(script\\|SCRIPT\\)[ \t\n\r\v\f]+"
   5.145+   "\\("
   5.146+   "language=[\"']"
   5.147+   aspx-mode-server-lang-re
   5.148+   "[\"'][ \t\n\r\v\f]+runat=[\"']server[\"']"
   5.149+   "\\|"
   5.150+   "runat=[\"']server[\"'][ \t\n\r\v\f]+language=[\"']"
   5.151+   aspx-mode-server-lang-re
   5.152+   "[\"']"
   5.153+   "\\)[ \t\n\r\v\f]*>"
   5.154+   )
   5.155+"Regex for matching the <script> tag that begins a block of
   5.156+ASPX server-side code.  It tries to match on <script language='C#' runat='server'...>
   5.157+as well as <script runat='server' language='C#' ...>
   5.158+" )
   5.159+
   5.160+
   5.161+(defconst aspx-mode-page-decl-re
   5.162+  (concat
   5.163+   "<%@"
   5.164+   "[ \t\n\r\v\f]+"
   5.165+   "\\(Page\\|Control\\)"
   5.166+   "[ \t\n\r\v\f]+"
   5.167+   )
   5.168+
   5.169+  "Regex for matching the page/control declaration"
   5.170+  )
   5.171+
   5.172+
   5.173+(defconst aspx-mode-browser-script-start-re
   5.174+  (concat
   5.175+   "<\\(script\\|SCRIPT\\)[ \t\n\r\v\f]+"
   5.176+   "\\("
   5.177+   "type=[\"']text/javascript[\"'][ \t\n\r\v\f]+language=[\"'][Jj]ava[Ss]cript[\"']"
   5.178+   "\\|"
   5.179+   "language=[\"'][Jj]ava[Ss]cript[\"'][ \t\n\r\v\f]+type=[\"']text/javascript[\"']"
   5.180+   "\\|"
   5.181+   "type=[\"']text/javascript[\"']"
   5.182+   "\\|"
   5.183+   "language=[\"'][Jj]ava[Ss]cript[\"']"
   5.184+   "\\)")
   5.185+
   5.186+"Regex for matching the <script> tag that begins a block of
   5.187+browser-side javascript code.  It tries to match on
   5.188+<script language='javascript' ...>  or
   5.189+<script type='text/javascript' ...>  or
   5.190+<script type='text/javascript' language='javascript' ...> or
   5.191+<script language='javascript' type='text/javascript' ...>
   5.192+")
   5.193+
   5.194+
   5.195+(defconst aspx-mode-css-block-start-re
   5.196+  (concat
   5.197+   "<\\(style\\|STYLE\\)"
   5.198+   "[ \t\n\r\v\f]+"
   5.199+   "type=[\"']text/css[\"']"
   5.200+   "[ \t\n\r\v\f]*"
   5.201+   ">")
   5.202+  "Regex to match the beginning of a CSS block."
   5.203+  )
   5.204+
   5.205+
   5.206+
   5.207+(defvar aspx-mode--last-chunk-result nil
   5.208+  "cached result of the last chunk analysis")
   5.209+
   5.210+(defvar aspx-mode-update-interval 1
   5.211+  "The amount of time in seconds after the last change before trying to
   5.212+re-fontify the current block.")
   5.213+
   5.214+(defvar aspx-mode-timer nil)
   5.215+
   5.216+
   5.217+
   5.218+
   5.219+
   5.220+;; When in multi-mode, I want espresso to indent to the
   5.221+;; <script> tag.  Use advice on the espresso indentation
   5.222+;; calculation, to make that happen.
   5.223+(defadvice espresso--proper-indentation (after
   5.224+                                         aspx-mode-advice-1
   5.225+                                         compile activate)
   5.226+  (if (and (boundp 'multi-mode)
   5.227+           multi-mode)
   5.228+      (if (eq ad-return-value 0)
   5.229+          (setq ad-return-value (+ ad-return-value 4)))))
   5.230+
   5.231+
   5.232+
   5.233+
   5.234+;; =======================================================
   5.235+;; dinoch - Thu, 13 May 2010  23:38
   5.236+;; factored out so that I can attach advice to it.
   5.237+;; Did this for multi-mode support in ASPX files.
   5.238+;; =======================================================
   5.239+(defun css--proper-indentation ()
   5.240+  (save-excursion
   5.241+    (back-to-indentation)
   5.242+    (let ((p (parse-partial-sexp (point-min) (point)))
   5.243+          (end-brace-p (looking-at "}")))
   5.244+      (cond
   5.245+       ((or (nth 8 p) (looking-at "/[/*]"))
   5.246+        (current-indentation))
   5.247+       ((save-excursion
   5.248+          (and (skip-chars-backward " \t\n:,")
   5.249+               (looking-at "[:,]")))
   5.250+        (save-excursion
   5.251+          (css-re-search-backward "^[ \t]*\\w")
   5.252+          (+ (current-indentation) css-indent-level)))
   5.253+       ((nth 1 p)
   5.254+        (save-excursion
   5.255+          (goto-char (nth 1 p))
   5.256+          (+ (current-indentation) (if end-brace-p 0 css-indent-level))))
   5.257+       (t
   5.258+        0)))))
   5.259+
   5.260+
   5.261+(defun css-indent-line ()
   5.262+  (interactive)
   5.263+  (let ((indent (css--proper-indentation))
   5.264+        (offset (- (current-column) (current-indentation))))
   5.265+    (indent-line-to indent)
   5.266+    (if (> offset 0) (forward-char offset))))
   5.267+
   5.268+
   5.269+
   5.270+;; Likewise with css-mode indentation.
   5.271+(defadvice css--proper-indentation (after
   5.272+                                    aspx-mode-advice-2
   5.273+                                    compile activate)
   5.274+  (if (and (boundp 'multi-mode)
   5.275+           multi-mode)
   5.276+      (if (eq ad-return-value 0)
   5.277+          (setq ad-return-value (+ ad-return-value 4)))))
   5.278+
   5.279+
   5.280+
   5.281+
   5.282+
   5.283+
   5.284+(defun aspx-mode-timer-elapsed ()
   5.285+  (aspx-mode-log 2 "timer fired.")
   5.286+  ;;(run-hooks 'aspx-mode-timer-elapsed-hook)
   5.287+  (aspx-mode-refontify-current-chunk-after-idle))
   5.288+
   5.289+
   5.290+(defun aspx-mode-restart-timer ()
   5.291+  (if (timerp aspx-mode-timer) (cancel-timer aspx-mode-timer))
   5.292+  (setq aspx-mode-timer
   5.293+        (run-with-timer aspx-mode-update-interval nil 'aspx-mode-timer-elapsed)))
   5.294+
   5.295+(defun aspx-mode-after-change-fn (begin end length)
   5.296+  (aspx-mode-maybe-invalidate-cached-chunk begin end length)
   5.297+  (if multi-mode (aspx-mode-restart-timer)))
   5.298+
   5.299+
   5.300+
   5.301+(defun aspx-mode-maybe-invalidate-cached-chunk (begin end old-length)
   5.302+  (let ((new-length (- end begin))
   5.303+        (old-end (+ begin old-length)))
   5.304+
   5.305+    ;; Invalidate if the length changed (we need to recalc the chunk limits)
   5.306+    ;; or if the change traversed the end of the chunk.
   5.307+    (if (and aspx-mode--last-chunk-result
   5.308+             (or (/= old-length new-length)
   5.309+                 (>= old-end  (nth 2 aspx-mode--last-chunk-result))))
   5.310+        (setq aspx-mode--last-chunk-result nil))))
   5.311+
   5.312+
   5.313+
   5.314+(defun aspx-mode-refontify-current-chunk-after-idle ()
   5.315+  "Fontify the current (cached) chunk.  This fn is called after a timer
   5.316+expires, when the buffer has sats idle for 2s.
   5.317+"
   5.318+  (aspx-mode-log 2 "fontifying (%d %d)"
   5.319+           (nth 1 aspx-mode--last-chunk-result)
   5.320+           (nth 2 aspx-mode--last-chunk-result))
   5.321+
   5.322+  (if aspx-mode--last-chunk-result
   5.323+      ;; Remove text props in the chunk, to force a new fontification
   5.324+      ;; later.  Do this within a save-buffer-state, because we're not
   5.325+      ;; *really* changing the buffer.
   5.326+      (c-save-buffer-state  ()
   5.327+        (set-text-properties (nth 1 aspx-mode--last-chunk-result)
   5.328+                             (nth 2 aspx-mode--last-chunk-result)
   5.329+                             nil))))
   5.330+
   5.331+
   5.332+
   5.333+
   5.334+
   5.335+
   5.336+(defun aspx-mode-determine-current-chunk (pos)
   5.337+  "Determine the type (mode) and limits of the chunk at POS.
   5.338+Return (MODE START END), where MODE is one of `csharp-mode',
   5.339+`javascript-mode', `html-mode', or `css-mode',
   5.340+and START and END are the limits of the chunk.
   5.341+
   5.342+Or, maybe return nil if not sure what mode it should be.
   5.343+I don't know. The doc is thin and the code is impenetrable.
   5.344+
   5.345+This method attempts to cache the calculated result and use it
   5.346+intelligently.  For example if the first execution determines
   5.347+that the POS is within a C# chunk, the limits of that chunk
   5.348+are cached. If a subsequent invocation of this method provides a
   5.349+POS that is within those limits, the function can safely return
   5.350+the same chunk response, without further scanning.
   5.351+
   5.352+This works as long as the buffer hasn't changed - in other words
   5.353+it's just cursor navigation.
   5.354+"
   5.355+
   5.356+  ;; If we're in the right zone, then use the cached value.
   5.357+  ;; Don't use the cache if it is HTML mode, because an HTML
   5.358+  ;; chunk can contain a javascript chunk, a CSS chunk, a
   5.359+  ;; csharp chunk.
   5.360+  (if (and aspx-mode--last-chunk-result
   5.361+           (> pos (nth 1 aspx-mode--last-chunk-result))
   5.362+           (< pos (nth 2 aspx-mode--last-chunk-result))
   5.363+           (not (eq 'html-mode (nth 0 aspx-mode--last-chunk-result))))
   5.364+      (progn
   5.365+        (aspx-mode-log 3 "determine-chunk: pos %d chunk cache %s"
   5.366+                       pos
   5.367+                       (prin1-to-string aspx-mode--last-chunk-result))
   5.368+        aspx-mode--last-chunk-result)
   5.369+
   5.370+    (let ((mode 'html-mode)
   5.371+          (start-of-block (point-min))
   5.372+          (end-of-block (point-max))
   5.373+          sp ep
   5.374+          new-result)
   5.375+
   5.376+      (save-excursion
   5.377+        (save-restriction
   5.378+          (widen)
   5.379+          (goto-char pos)
   5.380+          (cond
   5.381+
   5.382+           ;; Between <script language='javascript' ..> and </script>?
   5.383+           ((save-excursion
   5.384+              (and (and (re-search-backward aspx-mode-browser-script-start-re nil t)
   5.385+                        (setq sp (match-end 0)))
   5.386+                   (and (re-search-forward "</\\(script\\|SCRIPT\\)>" nil t)
   5.387+                        (setq ep (line-beginning-position)))
   5.388+                   (> ep pos)))
   5.389+
   5.390+            (setq
   5.391+             ;;mode 'javascript-mode
   5.392+             mode 'espresso-mode
   5.393+             start-of-block sp
   5.394+             end-of-block (1- ep) ))
   5.395+
   5.396+
   5.397+           ;; Between <style type="text/css"> and </style>?
   5.398+           ((save-excursion
   5.399+              (and (and (re-search-backward aspx-mode-css-block-start-re nil t)
   5.400+                        (setq sp (match-end 0)))
   5.401+                   (and (re-search-forward "</\\(style\\|style\\)>" nil t)
   5.402+                        (setq ep (line-beginning-position)))
   5.403+                   (> ep pos)))
   5.404+            (setq mode 'css-mode
   5.405+                  start-of-block sp
   5.406+                  end-of-block (1- ep) ))
   5.407+
   5.408+
   5.409+           ;; Between <script language='??'  runat='server'> and </script>?
   5.410+           ((save-excursion
   5.411+              (and (and (re-search-backward aspx-mode-server-script-start-re nil t)
   5.412+                        (setq sp (match-end 0)))
   5.413+                   (and (re-search-forward "</\\(script\\|SCRIPT\\)>" nil t)
   5.414+                        (setq ep (line-beginning-position)))
   5.415+                   (> ep pos)))
   5.416+
   5.417+            ;; TODO: support VBNET-mode, too.  Check the language at the
   5.418+            ;; start block.
   5.419+            (setq mode 'csharp-mode
   5.420+                  start-of-block sp
   5.421+                  end-of-block (1- ep) ))
   5.422+
   5.423+           ;; Between <%@ Page...>  and the first <html>
   5.424+           ((save-excursion
   5.425+              (and (and (re-search-forward "<\\(html\\|HTML\\)>" nil t)
   5.426+                        (setq ep (line-beginning-position)))
   5.427+                   (> ep pos)))
   5.428+
   5.429+            ;; TODO: support VBNET-mode, too.  Check the specified language at the
   5.430+            ;; start block.
   5.431+            ;; This works only because csharp-mode has smarts to fontify the
   5.432+            ;; @Page directive.
   5.433+            (setq mode 'csharp-mode
   5.434+                  start-of-block 1
   5.435+                  end-of-block (1- ep) ))
   5.436+
   5.437+
   5.438+
   5.439+           ;;              ;; Between <html..> and </html>
   5.440+           ;;              ((save-excursion
   5.441+           ;;                 (and (and (re-search-backward "<\\(HTML\\|html\\)>" nil t)
   5.442+           ;;                           (setq sp (match-beginning 0)))
   5.443+           ;;                      (and (re-search-forward "</\\(html\\|HTML\\)>" nil t)
   5.444+           ;;                           (setq ep (line-end-position)))
   5.445+           ;;                      (> ep pos)))
   5.446+           ;;               (setq mode 'html-mode
   5.447+           ;;                     start-of-block sp
   5.448+           ;;                     end-of-block (1- ep) ))
   5.449+
   5.450+           (t
   5.451+            nil))))
   5.452+
   5.453+      ;; multi-make-list does not actually make a new list.
   5.454+      ;; Instead it destructively modifies the existing list.
   5.455+      ;; The doc says it wants to avoid producing a cons cell
   5.456+      ;; in the post-command-hook.
   5.457+      ;; Therefore, to cache the result, we need to actually
   5.458+      ;; cons a distinct list.  To check that the new item is
   5.459+      ;; distinct, we need to compare each elt in the list.
   5.460+      ;; If that's the case, start a timer.
   5.461+      (setq new-result (list mode start-of-block end-of-block))
   5.462+
   5.463+      (if (or (not (eq (nth 0 new-result) (nth 0 aspx-mode--last-chunk-result)))
   5.464+              (not (eq (nth 1 new-result) (nth 1 aspx-mode--last-chunk-result)))
   5.465+              (not (eq (nth 2 new-result) (nth 2 aspx-mode--last-chunk-result))))
   5.466+          (progn
   5.467+            (aspx-mode-log 3 "new chunk, restart timer")
   5.468+            (aspx-mode-restart-timer)))
   5.469+
   5.470+      (setq aspx-mode--last-chunk-result
   5.471+            (multi-make-list mode start-of-block end-of-block))
   5.472+
   5.473+      )))
   5.474+
   5.475+
   5.476+
   5.477+(defun aspx-mode ()
   5.478+  "Mode for editing ASPX files with embedded C# script blocks,
   5.479+as well as CSS, Javascript, and HTML.
   5.480+"
   5.481+  (interactive)
   5.482+  (set (make-local-variable 'multi-mode-alist)
   5.483+       ;; This is a very odd data structure. It doesn't make sense that
   5.484+       ;; it is formatted this way. The documentation is completely
   5.485+       ;; unhelpful.
   5.486+       '(
   5.487+         (csharp-mode      . aspx-mode-determine-current-chunk)
   5.488+         (espresso-mode    . nil)  ;; javascript
   5.489+         (css-mode         . nil)
   5.490+         (html-mode        . nil)
   5.491+         ))
   5.492+  (add-hook 'after-change-functions 'aspx-mode-after-change-fn nil t)
   5.493+  (multi-mode-install-modes))
   5.494+
   5.495+
   5.496+
   5.497+
   5.498+
   5.499+(provide 'aspx-mode)
     6.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2+++ b/csharp-mode/csharp-completion.el	Wed Nov 10 15:19:03 2010 +0200
     6.3@@ -0,0 +1,2794 @@
     6.4+;;; csharp-completion.el -- Smart code completion for C#
     6.5+;;
     6.6+;; Author:     Dino Chiesa <dpchiesa@hotmail.com>
     6.7+;; Maintainer: Dino Chiesa <dpchiesa@hotmail.com>
     6.8+;; Created:    April 2010
     6.9+;; Modified:   April 2010
    6.10+;; Version:    0.1.5
    6.11+;; Keywords:   c# languages oop mode
    6.12+;; X-URL:      http://code.google.com/p/csharpmode/
    6.13+;;
    6.14+;;
    6.15+;;; Commentary:
    6.16+;;
    6.17+;;    This is a code-completion or "intellisense" package for C#.  The
    6.18+;;    scope of this module is much smaller that a full "development
    6.19+;;    envvironment".  It does smart code completion for C#, in
    6.20+;;    emacs. It does not do font-lock, indenting, debugging,
    6.21+;;    compiling, profiling, and so on.
    6.22+;;
    6.23+;;    To use it, place the cursor after a partially-completed
    6.24+;;    statement, and invoke `cscomp-complete-at-point'.  Normally this
    6.25+;;    would be bound to a particular keystroke, like M-.  This module
    6.26+;;    will insert the first completion that matches. If multiple
    6.27+;;    completions are possible, calling the completion function again
    6.28+;;    will cycle through the possibilities, similar to the way
    6.29+;;    dabbrev-mode works.
    6.30+;;
    6.31+;;    You can also call `cscomp-complete-at-point-menu', and get a popup
    6.32+;;    menu of the completion choices.
    6.33+;;
    6.34+;;    There are 2 complementary sources of information for the
    6.35+;;    completions: introspection into compiled .NET class libraries
    6.36+;;    (like the base class library), and parse analysis from the
    6.37+;;    semantic.el package, which is part of CEDET. In the typical
    6.38+;;    case, this module uses both of those sources of information,
    6.39+;;    together.
    6.40+;;
    6.41+;;    The reflection is done by an inferior powershell shell running
    6.42+;;    within emacs, that has loaded a custom .NET assembly.  The
    6.43+;;    library exposes static methods that perform type reflection,
    6.44+;;    using the capabilities of the System.Reflection namespace. These
    6.45+;;    methods then return strings which are lisp s-expressions that
    6.46+;;    can be eval'd, resulting in structures containing information
    6.47+;;    for a given type - including the available methods, fields and
    6.48+;;    properties, and the attributes on same.  This piece of the
    6.49+;;    puzzle is called the "CscompShell".
    6.50+;;
    6.51+;;    As an example, suppose your code has a local variable of type
    6.52+;;    System.Xml.XmlDocument, named doc.  Suppose the user asks for
    6.53+;;    completion on that variable.  The module uses the semantic parse
    6.54+;;    data to identify the name and type of the local variable.  It then
    6.55+;;    sends a "GetTypeInfo" command to the CscompShell, passing
    6.56+;;    System.Xml.XmlDocument. The CscompShell returns an s-expression
    6.57+;;    enumerating the fields, methods and properties for that type.
    6.58+;;    This s-expression is then used to populate the completion list.
    6.59+;;
    6.60+;;
    6.61+;; Here's a survey of the situations in which this module can offer
    6.62+;; completions:
    6.63+;;
    6.64+;;    a. names of local variables, instance variables, and method arguments.
    6.65+;;
    6.66+;;         void Method1(String longArgumentName)
    6.67+;;         {
    6.68+;;            long?
    6.69+;;         }
    6.70+;;
    6.71+;;    b. Methods, fields and properties (m/f/p) on a local variable
    6.72+;;       with known type, on method arguments of known type, or on
    6.73+;;       instance variables of known type:
    6.74+;;
    6.75+;;         String x = "this is a string";
    6.76+;;         x.?
    6.77+;;
    6.78+;;    c. M/f/p on local variables with var type:
    6.79+;;
    6.80+;;         var x = "this is a string";
    6.81+;;         x.?
    6.82+;;
    6.83+;;    d. Cascading local variable declarations of var type:
    6.84+;;
    6.85+;;         var s = "This is a string";
    6.86+;;         var length = s.Length;
    6.87+;;         var radix = length.?
    6.88+;;
    6.89+;;    e. completion on generic types:
    6.90+;;
    6.91+;;         var x = new List<String>();
    6.92+;;         x.?
    6.93+;;
    6.94+;;    f. completion on local variables that are initialized
    6.95+;;       from instance methods and variables.
    6.96+;;
    6.97+;;         void method1()
    6.98+;;         {
    6.99+;;           var length = this.InstanceMethod();
   6.100+;;           length.?
   6.101+;;         }
   6.102+;;
   6.103+;;    g. constructor completion, provide template when completing
   6.104+;;
   6.105+;;         var x = new System.String(?
   6.106+;;
   6.107+;;    h. constructor completion as above, with unqualified type.
   6.108+;;
   6.109+;;         var x = new TimeSpan(?
   6.110+;;
   6.111+;;    i. finding constructors among qualified and unqualified types
   6.112+;;
   6.113+;;         var x = new TimeS?
   6.114+;;
   6.115+;;    j. complete static methods on known types,
   6.116+;;       whether fully qualified or unqualified.
   6.117+;;
   6.118+;;         String.Jo?
   6.119+;;
   6.120+;;    k. present template fpr static methods on known types,
   6.121+;;       whether fully qualified or unqualified.
   6.122+;;
   6.123+;;         String.Join(?
   6.124+;;
   6.125+;;    l. Immediate values.
   6.126+;;
   6.127+;;         7.C?
   6.128+;;
   6.129+;;    m. other compound Expressions:
   6.130+;;
   6.131+;;         Path.GetRandomFileName().Normalize().?
   6.132+;;
   6.133+;;
   6.134+;;
   6.135+;; =======================================================
   6.136+;;
   6.137+;; Dependencies:
   6.138+;;
   6.139+;;   cc-mode 5.31.?
   6.140+;;
   6.141+;;   semantic.el 1.0pre7
   6.142+;;
   6.143+;;   optionally, yasnippet, for snippet insertion.  If the user has
   6.144+;;     yasnippet loaded, then this completion module will insert
   6.145+;;     a snippet (template) when the user selects a Method from the
   6.146+;;     completion list menu.  The method snippet will have all the
   6.147+;;     method parameters as placeholders; the developer then types over
   6.148+;;     those placeholders to supply the actual method parameters.
   6.149+;;     If yasnippet is not loaded, then the completion is just
   6.150+;;     the method name, and the developer has to fill in the
   6.151+;;     param-list himself.
   6.152+;;
   6.153+;;   PowerShell, and a separate DLL that must run in Powershell.  That
   6.154+;;     DLL is implemented in C#.
   6.155+;;
   6.156+;;
   6.157+;;
   6.158+;;
   6.159+;; Known bugs/problems :
   6.160+;;
   6.161+;;    1. The module does not do completion on anonymous (var) types in
   6.162+;;       for loops.
   6.163+;;
   6.164+;;
   6.165+;;
   6.166+;; TODO :
   6.167+;;
   6.168+;;    make an installer.
   6.169+;;
   6.170+;; Please send any comments, bugs, or upgrade requests to
   6.171+;; Dino Chiesa (dpchiesa@hotmail.com)
   6.172+;;
   6.173+
   6.174+
   6.175+(require 'csharp-shell)
   6.176+
   6.177+(require 'semantic-idle)  ;; for ... reparsing a buffer
   6.178+
   6.179+
   6.180+;; Design notes:
   6.181+;;
   6.182+;; Tue, 04 May 2010  10:47
   6.183+;;
   6.184+;; This completion depends on the semantic package for parsing a C#
   6.185+;; buffer.  That gives the module a way to interrogate the names and
   6.186+;; types of local and instance variables, in order to do completion on
   6.187+;; them.
   6.188+;;
   6.189+;; Semantic also provides the list of using statements for a C# module,
   6.190+;; which tells us which assemblies we need to search in, for
   6.191+;; completions.  These are then loaded into CscompShell for interrogation.
   6.192+;;
   6.193+
   6.194+
   6.195+
   6.196+(defvar cscomp-current-list nil
   6.197+  "The list of all the completion. Each element of the list is
   6.198+either a string, or a list which the car is the possible completion,
   6.199+and the cadr is an additional information about this completion.")
   6.200+
   6.201+(defvar cscomp-current-list-index nil
   6.202+  "An index to an element in cscomp-current-list. This is used to
   6.203+cycle the list.")
   6.204+
   6.205+(defvar cscomp-current-fragment nil
   6.206+  "The current fragment we're trying to complete. This is used to trim the thing that gets inserted.")
   6.207+
   6.208+(defvar cscomp-current-beginning (make-marker)
   6.209+  "The beginning of the region where the last completion was inserted.")
   6.210+
   6.211+(defvar cscomp-current-end (make-marker)
   6.212+  "The end of the region where the last completion was inserted.")
   6.213+
   6.214+(defvar cscomp-typeinfo-cache nil)
   6.215+
   6.216+(defcustom cscomp-typeinfo-cache-size 150
   6.217+  "The max size of completion buffer cache, in entries."
   6.218+  :group 'cscomp
   6.219+  :type 'integer)
   6.220+
   6.221+
   6.222+
   6.223+(defun cscomp-referenced-assemblies-list ()
   6.224+  "Return the list of .NET namespaces referenced in the
   6.225+current buffer via using statements. It uses the semantic parser
   6.226+table to find the 'using' statements. "
   6.227+  (interactive)
   6.228+  (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
   6.229+  (let* ((tokens  (semantic-fetch-tags))
   6.230+         ;;(usings (semantic-find-nonterminal-by-token (quote include) tokens))
   6.231+         (usings (semantic-brute-find-tag-by-class 'include tokens)))
   6.232+    (cscomp-log 3 "cscomp-referenced-assemblies-list: found using statements: '%s'" usings)
   6.233+    (mapcar 'car usings)))
   6.234+
   6.235+
   6.236+
   6.237+(defun cscomp-instance-vars ()
   6.238+  "Return the list of instance variables in a C# module.
   6.239+This uses the semantic parser table to find the variable
   6.240+declarations.
   6.241+
   6.242+The return value is a list of semantic tags.  Looks like:
   6.243+
   6.244+\((\"flavor\" variable
   6.245+             (:type \"int\")
   6.246+             (reparse-symbol class_member_declaration) #<overlay from 580 to 595 in a.cs>)
   6.247+ (\"flicky\" variable
   6.248+             (:type \"String\")
   6.249+             (reparse-symbol class_member_declaration) #<overlay from 604 to 636 in a.cs>)
   6.250+ (\"label\" variable
   6.251+            (:type \"String\")
   6.252+            (reparse-symbol class_member_declaration) #<overlay from 645 to 669 in a.cs>))
   6.253+
   6.254+"
   6.255+
   6.256+  (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
   6.257+  (semantic-fetch-tags)
   6.258+  (let* ((class  (cscomp-find-enclosing-csharp-class))        ;; the enclosing class
   6.259+         (tokens (semantic-tag-type-members class))                  ;; the members of that class
   6.260+         (vars (semantic-brute-find-tag-by-class 'variable tokens))) ;; the members that are variables
   6.261+    (cscomp-log 3 "cscomp-instance-vars: found instance vars: '%s'" vars)
   6.262+    vars))
   6.263+
   6.264+
   6.265+
   6.266+
   6.267+(defun cscomp-instance-members ()
   6.268+  "Return the list of instance members in a C# module.
   6.269+This uses the semantic parser table to find the memebr
   6.270+declarations.
   6.271+
   6.272+The return value is a list of semantic tags.  Looks like:
   6.273+
   6.274+\((\"flavor\" variable
   6.275+             (:type \"int\")
   6.276+             (reparse-symbol class_member_declaration) #<overlay from 580 to 595 in a.cs>)
   6.277+ (\"Hello\" function
   6.278+             (:type \"String\")
   6.279+             (reparse-symbol class_member_declaration) #<overlay from 604 to 636 in a.cs>)
   6.280+ (\"label\" variable
   6.281+            (:type \"String\")
   6.282+            (reparse-symbol class_member_declaration) #<overlay from 645 to 669 in a.cs>))
   6.283+
   6.284+"
   6.285+
   6.286+  (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
   6.287+  (semantic-fetch-tags)
   6.288+  (let ((class  (cscomp-find-enclosing-csharp-class))) ;; the enclosing class
   6.289+    (semantic-tag-type-members class)))                       ;; the members of that class
   6.290+
   6.291+
   6.292+
   6.293+
   6.294+(defun cscomp--find-matching-tags (name-fragment tagset &optional local)
   6.295+  "Return the list of tags from a given set, that
   6.296+match NAME-FRAGMENT.  This is used by `cscomp-matching-local-vars',
   6.297+`cscomp-matching-instance-vars',
   6.298+`cscomp-matching-instance-members'.
   6.299+"
   6.300+    (let ((var-label (if local "(Variable) " "(Field) " ))
   6.301+           result)
   6.302+
   6.303+    (if tagset
   6.304+        (progn
   6.305+        (while tagset
   6.306+          (let* ((tag (car tagset))
   6.307+                 (member-name  (semantic-tag-name tag))
   6.308+                 (member-type  (semantic-tag-type tag))
   6.309+                 (member-clazz (semantic-tag-class tag))
   6.310+                 )
   6.311+
   6.312+            (if (eq 0 (string-match name-fragment member-name))
   6.313+                (let ((descrip
   6.314+                       (cond
   6.315+                        ((string= member-clazz "variable")
   6.316+                         (concat var-label member-type))
   6.317+
   6.318+                        ((string= member-clazz "function")
   6.319+                         (let* ((arglist (semantic-tag-get-attribute tag :arguments))
   6.320+                                (modifiers (semantic-tag-modifiers tag))
   6.321+                                (arg-descrip
   6.322+                                 (if (> (length arglist) 0)
   6.323+                                     (concat "("
   6.324+                                             (mapconcat
   6.325+                                              '(lambda (x) (concat (semantic-tag-type x)
   6.326+                                                                   " "
   6.327+                                                                   (semantic-tag-name x)))
   6.328+                                              arglist  ", ")
   6.329+                                             ")")
   6.330+                                   "()")))
   6.331+
   6.332+                           (concat "(Method) "
   6.333+                                   " " (mapconcat 'identity modifiers " ") " "
   6.334+                                   arg-descrip
   6.335+                                   "  returns "
   6.336+                                   member-type)))
   6.337+
   6.338+                        (t ""))))
   6.339+
   6.340+
   6.341+                  (cscomp-log 2 "cscomp-matching-tags: found %s (%s)"
   6.342+                           member-name member-type)
   6.343+
   6.344+                  (setq result (cons (list member-name descrip) result)))))
   6.345+
   6.346+            (setq tagset (cdr tagset)))
   6.347+        (cscomp-sort-completion-list result))
   6.348+      nil)))
   6.349+
   6.350+
   6.351+
   6.352+
   6.353+(defun cscomp-matching-instance-vars (name-fragment)
   6.354+  "Return the list of instance variables in a C# module, that
   6.355+match NAME-FRAGMENT.  See also, `cscomp-matching-local-vars'.
   6.356+
   6.357+"
   6.358+  (cscomp--find-matching-tags name-fragment (cscomp-instance-vars)))
   6.359+
   6.360+
   6.361+
   6.362+
   6.363+(defun cscomp-matching-instance-members (name-fragment)
   6.364+  "Return the list of instance memebrs in a C# module, that
   6.365+match NAME-FRAGMENT.
   6.366+
   6.367+See also, `cscomp-matching-local-vars',
   6.368+`cscomp-matching-instance-vars'.
   6.369+
   6.370+"
   6.371+  (cscomp--find-matching-tags name-fragment (cscomp-instance-members)))
   6.372+
   6.373+
   6.374+
   6.375+(defun cscomp-matching-local-vars (name-fragment)
   6.376+  "Use the semantic lex/analysis results to find local variables
   6.377+that match the given NAME-FRAGMENT.
   6.378+
   6.379+See also, `cscomp-matching-instance-members',
   6.380+`cscomp-matching-instance-vars'.
   6.381+
   6.382+"
   6.383+  (cscomp-start-stripped-semantic)
   6.384+  (cscomp--find-matching-tags name-fragment (semantic-get-all-local-variables) t))
   6.385+
   6.386+
   6.387+
   6.388+(defun cscomp-find-enclosing-csharp-class (&optional posn)
   6.389+  "returns a tag of type 'type (in other words, a c# class or struct) that
   6.390+encloses POSN, or point if POSN is nil.  If there is no enclosing 'type,
   6.391+then return nil.
   6.392+"
   6.393+;; This isn't quite correct. At this time, the C# namespace defn gets
   6.394+;; parsed as a type. I couldn't figure how to get namespace to get
   6.395+;; parsed as a new 'namespace tag.  Therefore, this fn can sometimes
   6.396+;; return a tag corresponding to a namespace, as opposed to a tag
   6.397+;; corresponding to a bonafide type.
   6.398+
   6.399+(let ((nar (semantic-current-tag-of-class 'type)))
   6.400+    nar))
   6.401+
   6.402+
   6.403+
   6.404+;; (defun cscomp-find-semantic-things (tag-class)
   6.405+;;   "Search for tags in semantic parse state."
   6.406+;;   (interactive "sTag type: ")
   6.407+;;   (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
   6.408+;;   (let* ((tokens  (semantic-fetch-tags))
   6.409+;;          (matches (cscomp-find-by-class tag-class tokens t)))
   6.410+;;     (if matches
   6.411+;;         (while matches
   6.412+;;           (let ((one (car matches)))
   6.413+;;             (setq matches (cdr matches))))
   6.414+;;       nil
   6.415+;;     )))
   6.416+
   6.417+
   6.418+
   6.419+(defun cscomp-find-by-class (cls streamorbuffer &optional search-parts search-includes)
   6.420+  "Find all tags with class CLS within STREAMORBUFFER.
   6.421+CLS is a string which is the name of the class of the tags returned, such as
   6.422+include, variable, type.
   6.423+See `semantic-tag-class'.
   6.424+Optional argument SEARCH-PARTS and SEARCH-INCLUDES are passed to
   6.425+`semantic-brute-find-tag-by-function'."
   6.426+  (semantic-brute-find-tag-by-function
   6.427+   (lambda (tag)
   6.428+     (let ((class (semantic-tag-class tag)))
   6.429+       (string= class cls)))
   6.430+   streamorbuffer search-parts search-includes))
   6.431+
   6.432+
   6.433+
   6.434+;;    (lambda (tag)
   6.435+;;      (let ((class (semantic-tag-class tag)))
   6.436+;;        (if (and (listp ts)
   6.437+;;                 (or (= (length ts) 1)
   6.438+;;                     (string= (semantic-tag-class ts) type)))
   6.439+;;
   6.440+;;            (setq ts (semantic-tag-name ts)))
   6.441+;;        (equal type ts)))
   6.442+;;    streamorbuffer search-parts search-includes))
   6.443+
   6.444+
   6.445+
   6.446+(defun cscomp-debugonly-list-all-local-variables ()
   6.447+  "fiddle with local variables and semantic."
   6.448+  (interactive)
   6.449+  (cscomp-start-stripped-semantic)
   6.450+  (semantic-lex (point-min) (point-max) 100)
   6.451+  (let ((locals (semantic-get-all-local-variables)))
   6.452+    (mapcar '(lambda (x)
   6.453+               (cscomp-log 3 "local var: name(%s) type(%s) pos(%s)"
   6.454+                        (car x) (cadr (nth 2 x))
   6.455+                        (nth 4 x)))
   6.456+            locals)))
   6.457+
   6.458+
   6.459+
   6.460+;; (defun cscomp-variables-in-scope ()
   6.461+;;   "Return the list of variables currently in scope.
   6.462+;; It uses the semantic parser table to find them."
   6.463+;;   (interactive)
   6.464+;;   (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
   6.465+;;   (let* ((tokens (semantic-fetch-tags))
   6.466+;;          (vars (semantic-brute-find-tag-by-class 'variable tokens)))
   6.467+;;     (cscomp-log 3 "cscomp-variables-in-scope: found variables: '%s'" vars)
   6.468+;;     (mapcar 'car vars)))
   6.469+
   6.470+
   6.471+;; (defun cscomp-valid-csharp-declaration-at (point varname)
   6.472+;;   "Verify that a POINT starts a valid csharp declaration
   6.473+;; for the VARNAME variable."
   6.474+;;   (save-excursion
   6.475+;;     (goto-char point)
   6.476+;;     (if (looking-at
   6.477+;;          (concat "\\([A-Za-z0-9_.\177-\377]+\\)[ \t\n\r]+"
   6.478+;;                  (cscomp-double-backquotes varname)
   6.479+;;                  "[ \t\n\r]*[;=]"))
   6.480+;;         (match-string 1)
   6.481+;;       nil)))
   6.482+
   6.483+
   6.484+
   6.485+
   6.486+;; (defun cscomp-double-backslashes (varname)
   6.487+;;   "Build a new string identical to VARNAME, except that every backslash
   6.488+;; `\' is doubled, so that it can be used in a regex expression.
   6.489+;; "
   6.490+;;   (let (result (idx 0) (len (length varname)) curcar)
   6.491+;;     (while (< idx len)
   6.492+;;       (setq curcar (elt varname idx))
   6.493+;;       (setq result (concat result (if (eq curcar ?\\)
   6.494+;;                                       "\\\\"
   6.495+;;                                     (make-string 1 curcar))))
   6.496+;;       (setq idx (1+ idx)))
   6.497+;;     result))
   6.498+
   6.499+
   6.500+
   6.501+
   6.502+;; (defun cscomp-declared-type-of (name)
   6.503+;;   "Find in the current buffer the csharp type of the variable NAME.  The
   6.504+;; function returns a string containing the name of the class, or nil
   6.505+;; otherwise. This function does not give the fully-qualified csharp class
   6.506+;; name, it just returns the type as it is declared."
   6.507+;;   (save-excursion
   6.508+;;     (let (found res pos orgpt resname)
   6.509+;;       (while (and (not found)
   6.510+;;                   (search-backward name nil t))
   6.511+;;         (setq pos (point))
   6.512+;;         (backward-word 1)
   6.513+;;         (setq resname (cscomp-valid-csharp-declaration-at (point) name))
   6.514+;;         (goto-char pos)
   6.515+;;         (forward-char -1)
   6.516+;;         (if resname
   6.517+;;             (progn (setq res resname)
   6.518+;;                    (setq found t))))
   6.519+;;       res)))
   6.520+
   6.521+
   6.522+;; (defun cscomp-filter-fqn (importlist)
   6.523+;;   "Filter all the fully-qualified classnames in the import list. It uses
   6.524+;; the knowledge that those classnames are at the beginning of the list,
   6.525+;; so that it can stops at the first package import (with a star `*' at
   6.526+;; the end of the declaration)."
   6.527+;;   (if importlist
   6.528+;;       (if (string= "*" (car (cdr (car importlist))))
   6.529+;;           importlist
   6.530+;;         (cscomp-filter-fqn (cdr importlist)))))
   6.531+
   6.532+
   6.533+
   6.534+(defun cscomp-escape-string-for-powershell (arg)
   6.535+  "Powershell uses the backquote for an escape char.  This fn
   6.536+escapes the backquote for a string that will eventually be sent
   6.537+to powershell (CscompShell).
   6.538+
   6.539+I think this is only necessary when the arg is submitted to
   6.540+powershell within double-quotes. If the arg is within single
   6.541+quotes, backquotes do not need to be escaped.
   6.542+
   6.543+"
   6.544+  (let ((matcho (string-match "\\(.+\\)`\\(.+\\)" arg)))
   6.545+    (if matcho
   6.546+        (concat
   6.547+         (substring arg (match-beginning 1) (match-end 1))
   6.548+         "``"
   6.549+         (substring arg (match-beginning 2) (match-end 2)))
   6.550+      arg)))
   6.551+
   6.552+
   6.553+
   6.554+
   6.555+
   6.556+(defun cscomp-send-string-to-shell (command-string)
   6.557+  "sends a string to cscompshell function, returns the result."
   6.558+  (let ((result (csharp-shell-exec-and-eval-result command-string)))
   6.559+    (cscomp-log 2 "send-string-to-shell (%s) result(%s)" command-string (prin1-to-string  result))
   6.560+    ;;(if (and result (listp result)) result nil)
   6.561+    result
   6.562+    ))
   6.563+
   6.564+
   6.565+
   6.566+(defun cscomp-invoke-shell-fn (fn arg)
   6.567+  "invokes a 1-arg CscompShell function, returns the result."
   6.568+
   6.569+  ;; need to use single-quotes here around the arg, because in
   6.570+  ;; some cases the arg can have double-quotes in it.
   6.571+
   6.572+  (let* ((escaped-arg (cscomp-escape-string-for-powershell arg)))
   6.573+    (cscomp-send-string-to-shell (concat "[Ionic.Cscomp.Utilities]::" fn "(\'" escaped-arg "\')"))))
   6.574+
   6.575+
   6.576+
   6.577+
   6.578+(defun cscomp-type-exists (typename)
   6.579+  "Determines if the given type is known by the CscompShell.  You can provide a short type name, or a fully-qualified name.  You must have loaded the assembly into the shell, for it to be known.  See `cscomp-load-assembly'."
   6.580+  (interactive "sType name: ")
   6.581+  (cscomp-invoke-shell-fn "QualifyType" typename))
   6.582+
   6.583+
   6.584+
   6.585+(defun cscomp-get-members-of-class (semantic-tag)
   6.586+  "Gets the members of the class denoted by the SEMANTIC-TAG.
   6.587+If SEMANTIC-TAG is nil, then this function gets the closest type
   6.588+containing point, and gets the members of that.
   6.589+
   6.590+"
   6.591+  (if (null semantic-tag) (setq semantic-tag (cscomp-get-current-class)))
   6.592+  (if (eq (cadr semantic-tag) 'type)
   6.593+      (semantic-tag-type-members semantic-tag)
   6.594+    nil))
   6.595+
   6.596+
   6.597+
   6.598+
   6.599+(defun cscomp-get-current-class (&optional posn)
   6.600+  "Return the semantic tag for the current class or type in scope at POSN.
   6.601+"
   6.602+  (interactive)
   6.603+  (save-excursion
   6.604+    (if posn (goto-char posn))
   6.605+    (semantic-fetch-tags)
   6.606+    (let ((containing-type (semantic-current-tag-of-class 'type)))
   6.607+      containing-type)))
   6.608+
   6.609+
   6.610+(defun cscomp-produce-csharp-arglist-block-from-dbrecord (arglist)
   6.611+  "Produces an argument list block, suitable for framing within parens
   6.612+in a method declaration, from ARGLIST, a list of local arguments obtained from
   6.613+`semantic-get-local-arguments'.
   6.614+
   6.615+When the format of ARGLIST is like this:
   6.616+
   6.617+   ((\"count\"
   6.618+      variable
   6.619+      (:type \"int\")
   6.620+      (:filename \"c:/dinoch/dev/dotnet/CsharpCompletion.cs\"
   6.621+                 reparse-symbol formal_parameters)
   6.622+      [621 630])
   6.623+    (\"melvin\"
   6.624+      variable
   6.625+      (:type \"string\")
   6.626+      (:filename \"c:/dinoch/dev/dotnet/CsharpCompletion.cs\"
   6.627+                 reparse-symbol formal_parameters)
   6.628+      [631 645]))
   6.629+
   6.630+The return value is like this:
   6.631+
   6.632+    int count, string melvin
   6.633+
   6.634+When the arglist is empty, the return value is a string of zero length.
   6.635+
   6.636+
   6.637+"
   6.638+  (let ((fragment ""))
   6.639+    (while arglist
   6.640+      (let* ((x (car arglist))
   6.641+             (var-name (car x))
   6.642+             (var-type (cadr (nth 2 x))))
   6.643+
   6.644+        (setq fragment (concat fragment var-type " " var-name)
   6.645+              arglist (cdr arglist))
   6.646+        (if arglist
   6.647+            (setq fragment (concat fragment ", ")))))
   6.648+    fragment))
   6.649+
   6.650+
   6.651+
   6.652+
   6.653+(defun cscomp-produce-instance-member-code-fragment (member-list)
   6.654+  "Produce a C# fragment that defines placeholder instance members,
   6.655+to be inserted into a class template which is then compiled, so that
   6.656+Cscomp can inspect the resulting IL to determine the type of a local var
   6.657+on which the user is asking for completion.
   6.658+
   6.659+Cscomp uses the compiler to determine the type of the var. It
   6.660+dynamically generates and compiles a class with the same variable
   6.661+declaration as the code being edited.
   6.662+
   6.663+The initialization of the var may depend on instance members.  If
   6.664+so, the compiled class must provide instance members of the
   6.665+correct type to satisfy those dependencies.  This function
   6.666+generates C# code to provide those instance members.
   6.667+
   6.668+For input that looks like this:
   6.669+
   6.670+  ((\"staticField1\" variable
   6.671+     (:typemodifiers (\"private\" \"static\") :type \"int\")
   6.672+     (reparse-symbol class_member_declaration)
   6.673+     #<overlay from 605 to 642 in CsharpCompletion.cs>)
   6.674+   (\"InstanceMethod1\" function
   6.675+     (:arguments (...) :type \"string\")
   6.676+     (reparse-symbol class_member_declaration)
   6.677+     #<overlay from 652 to 741 in CsharpCompletion.cs>)
   6.678+   (\"Run\" function
   6.679+     (:typemodifiers (\"public\") :arguments (...) :type \"void\")
   6.680+     (reparse-symbol class_member_declaration)
   6.681+     #<overlay from 752 to 1487 in CsharpCompletion.cs>)
   6.682+   (\"Main\" function
   6.683+     (:typemodifiers (\"public\" \"static\") :arguments (...) :type \"void\")
   6.684+     (reparse-symbol class_member_declaration)
   6.685+     #<overlay from 1497 to 1806 in CsharpCompletion.cs>)
   6.686+   )
   6.687+
   6.688+The output will look like this:
   6.689+
   6.690+    private static int staticField1 = default(int);
   6.691+    string InstanceMethid(...) { return default(string); }
   6.692+
   6.693+Any void methods will not be emitted because they cannot affect the
   6.694+types of local variables declared in methods.
   6.695+
   6.696+"
   6.697+  (let ((synthetic-code ""))
   6.698+
   6.699+    (while member-list
   6.700+      (let* ((x (car member-list))
   6.701+             (member-name (car x))
   6.702+             (member-flavor (cadr x))
   6.703+             (member-type (semantic-tag-get-attribute x :type))
   6.704+             (member-modifiers (semantic-tag-get-attribute x :typemodifiers))
   6.705+             one-frag
   6.706+             )
   6.707+        ;;          (message "n(%s) f(%s) t(%s)"
   6.708+        ;;                   member-name
   6.709+        ;;                   member-flavor
   6.710+        ;;                   member-type)
   6.711+
   6.712+        (setq one-frag
   6.713+              (cond
   6.714+
   6.715+               ((string= member-type "void") ;; the member is a void type
   6.716+                "")                          ;; emit nothing, don't need it.
   6.717+               ;; it's possible we might need it, in which case,
   6.718+               ;; we can just emit an empty fn.
   6.719+
   6.720+               ((eq member-flavor 'function) ;; it's a method
   6.721+                (concat
   6.722+                 (mapconcat 'identity member-modifiers " ")
   6.723+                 " "
   6.724+                 member-type
   6.725+                 " "
   6.726+                 member-name
   6.727+                 "("
   6.728+                 (cscomp-produce-csharp-arglist-block-from-dbrecord
   6.729+                  (semantic-tag-get-attribute x :arguments))
   6.730+                 ") {"
   6.731+                 (if member-type
   6.732+                     (concat
   6.733+                      " return default("
   6.734+                      member-type
   6.735+                      ");")
   6.736+                   "")
   6.737+                 "} "))
   6.738+
   6.739+
   6.740+               ((eq member-flavor 'variable) ;; it's an instance variable
   6.741+
   6.742+                (concat
   6.743+                 (mapconcat 'identity member-modifiers " ")
   6.744+                 " "
   6.745+                 member-type
   6.746+                 " "
   6.747+                 member-name
   6.748+                 " = default("
   6.749+                 member-type
   6.750+                 "); "))
   6.751+
   6.752+               (t
   6.753+                "")))
   6.754+
   6.755+        (setq synthetic-code (concat synthetic-code one-frag)))
   6.756+      (setq member-list (cdr member-list)))
   6.757+    synthetic-code))
   6.758+
   6.759+
   6.760+(defun cscomp-consolidate-whitespace (s)
   6.761+  "Collapse consecutive whitespace characters in the given string S
   6.762+to a single space.
   6.763+"
   6.764+  ;; trim leading spaces
   6.765+  (if (string-match "^\\([ \t\n\r\f\v]+\\)" s)
   6.766+      (setq s (substring s (match-end 1))))
   6.767+
   6.768+  ;; collapse multiple whitespace into one
   6.769+  (while (string-match "\\([ \t\n\r\f\v]\\{2,\\}\\)" s)
   6.770+    (setq s
   6.771+          (concat
   6.772+           (substring s 0 (match-beginning 1))
   6.773+           " "
   6.774+           (substring s (match-end 1)))))
   6.775+  s)
   6.776+
   6.777+
   6.778+(defun cscomp-escape-single-quotes (s)
   6.779+  "Escape single-quotes in the given string S.  This is for use within
   6.780+powershell.
   6.781+"
   6.782+  ;; escape single-quotes
   6.783+  (while (string-match "\\(.+\\)'\\(.+\\)" s)
   6.784+    (setq s
   6.785+          (concat
   6.786+           (substring s 0 (match-beginning 1))
   6.787+           "`'"
   6.788+           (substring s (match-end 1)))))
   6.789+  s)
   6.790+
   6.791+
   6.792+;;(setq cscomp-log-level 2)
   6.793+
   6.794+
   6.795+(defun cscomp-get-var-type-given-decl (var-declaration
   6.796+                                              var-index
   6.797+                                              classname
   6.798+                                              arglist
   6.799+                                              instance-members)
   6.800+  "Determines the type of the var declared in the given declaration.
   6.801+VAR-DECLARATION is  the C# code that declares all the local vars up to
   6.802+and including the local var of interest.
   6.803+
   6.804+VAR-INDEX is the zero-based index of the local arg in that list,
   6.805+that is of interest.  The initialization of that local var may
   6.806+depend on the prior local vars, which is why we need the entire
   6.807+var declaration list.
   6.808+
   6.809+CLASSNAME is the name of the class in which the local vars
   6.810+appear. This is used in the generated (synthetic) code, in case
   6.811+there is a reference to a class-static member.
   6.812+
   6.813+ARGLIST is a string with the arglist for the method that contains the
   6.814+local variable in question.  This will satisfy dependencies on
   6.815+local arguments in the initializer for the var, if any.
   6.816+
   6.817+INSTANCE-MEMBERS is a C# code fragment defining instance members for the
   6.818+synthetic class.  This will satisfy dependencies on instance members in
   6.819+the initializer for the var, if any.
   6.820+
   6.821+"
   6.822+  (let* ((massaged-decl
   6.823+          (cscomp-escape-single-quotes
   6.824+           (cscomp-consolidate-whitespace var-declaration)))
   6.825+         (namespaces (mapconcat 'identity (cscomp-referenced-assemblies-list) ","))
   6.826+         (command-string
   6.827+          (concat "[Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl('"
   6.828+                  massaged-decl
   6.829+                  "','"
   6.830+                  namespaces
   6.831+                  "','" ;; for now, no additional assembly references
   6.832+                  "',"
   6.833+                  (number-to-string var-index)
   6.834+                  ",'"
   6.835+                  classname
   6.836+                  "','"
   6.837+                  arglist
   6.838+                  "','"
   6.839+                  (cscomp-consolidate-whitespace instance-members)
   6.840+                  "')" )))
   6.841+    (cscomp-send-string-to-shell command-string)))
   6.842+
   6.843+
   6.844+
   6.845+
   6.846+(defun cscomp-get-completions-for-namespace (ns)
   6.847+  "Gets a list of known completions (types and child namespaces)
   6.848+for the given namespace. You must have loaded an assembly containing
   6.849+types from the namespace, into the shell, for it to be known.
   6.850+See `cscomp-load-assembly'."
   6.851+  (interactive "sNamespace: ")
   6.852+  (cscomp-invoke-shell-fn "GetCompletionsForNamespace" ns))
   6.853+
   6.854+
   6.855+
   6.856+(defun cscomp-qualify-name (name)
   6.857+  "determines if the thing is a type, namespace, or ...?
   6.858+
   6.859+Result is
   6.860+
   6.861+    (list \"type\"  name)
   6.862+
   6.863+      or
   6.864+
   6.865+    (list \"namespace\"  name)
   6.866+
   6.867+      or
   6.868+
   6.869+    (list \"unknown\"  name)
   6.870+
   6.871+"
   6.872+
   6.873+  (interactive "sname to qualify: ")
   6.874+  (cscomp-invoke-shell-fn "QualifyName" name))
   6.875+
   6.876+
   6.877+(defun cscomp-get-matches (fragment)
   6.878+  "returns a list of all possible matches on a given partial name.
   6.879+The return value is like this:
   6.880+
   6.881+   (list (list \"type\"  \"fullNameOfType\")
   6.882+         (list \"namespace\"  \"FullNameOfNamespace\"))
   6.883+
   6.884+"
   6.885+  (interactive "sfragment to match on: ")
   6.886+
   6.887+  (let ((namespaces (mapconcat 'identity (cscomp-referenced-assemblies-list) ",")))
   6.888+
   6.889+    (cscomp-send-string-to-shell
   6.890+     (concat "[Ionic.Cscomp.Utilities]::GetMatches('"
   6.891+             fragment
   6.892+             "','"
   6.893+             namespaces
   6.894+             "')"))))
   6.895+
   6.896+
   6.897+
   6.898+(defun cscomp-load-additional-assemblies (lib-list)
   6.899+"Loads a set of assemblies into the csharp-shell, which then allows Cscomp
   6.900+to do completion (etc) on the types in those libraries."
   6.901+  (mapcar 'cscomp-load-assembly lib-list))
   6.902+
   6.903+
   6.904+(defun cscomp-load-assembly (lib)
   6.905+  "Loads a assembly into the csharp-shell, which then allows Cscomp
   6.906+to do completion (etc) on the types in that library."
   6.907+  (interactive "sLibrary: ")
   6.908+  (cscomp-invoke-shell-fn "LoadOneAssembly" lib))
   6.909+
   6.910+
   6.911+
   6.912+(defun cscomp-get-qualified-name (name)
   6.913+  "Guess the fully qualified name of the class NAME, using the
   6.914+list of referenced assemblies. It returns a string if the fqn
   6.915+was found, or null otherwise."
   6.916+  (interactive "sType name: ")
   6.917+  (cscomp-log 1 "get-qualified-name (%s)" name)
   6.918+  (let ((result (cscomp-type-exists name)))
   6.919+    (if result result
   6.920+      ;; else
   6.921+      (let ((usinglist (cscomp-referenced-assemblies-list))
   6.922+            fullname namespace )
   6.923+
   6.924+        ;; usinglist is like this:
   6.925+        ;; ("System"  "System.Collections"  "System.Collections.Generic"  "System.Reflection")
   6.926+
   6.927+        (setq result nil)
   6.928+        (while usinglist
   6.929+          (setq namespace (car usinglist))
   6.930+          (cscomp-load-assembly namespace)
   6.931+          (setq fullname (concat namespace "." name))
   6.932+          (cscomp-log 2 "checking this type: '%s'" fullname)
   6.933+          (if (cscomp-type-exists fullname)
   6.934+              (setq result fullname
   6.935+                    usinglist nil)
   6.936+            (setq usinglist (cdr usinglist))))
   6.937+
   6.938+        (cscomp-log 1 "get-qualified-name rtns: '%s'" result)
   6.939+
   6.940+        result))))
   6.941+
   6.942+
   6.943+
   6.944+;; (defun cscomp-flush-typeinfo-cache ()
   6.945+;;   "Flushes all entries in the completion cache"
   6.946+;;   (interactive)
   6.947+;;   (setq cscomp-typeinfo-cache nil))
   6.948+;;
   6.949+;;
   6.950+;; (defun cscomp-flush-classes-in-cache (class-list)
   6.951+;;   "Flushes all the classes in CLASS-LIST as entries of cache."
   6.952+;;   (let ((temp (nth 0 cscomp-typeinfo-cache))
   6.953+;;         (index -1)
   6.954+;;         (found nil)
   6.955+;;         (class (car class-list)))
   6.956+;;     (while class
   6.957+;;       (while (and temp (not found))
   6.958+;;         (setq index (1+ index))
   6.959+;;         (setq temp (nth index cscomp-typeinfo-cache))
   6.960+;;         (if (string= (car temp) class)
   6.961+;;             (setq found t)))
   6.962+;;       (if found
   6.963+;;           (setq cscomp-typeinfo-cache
   6.964+;;                 (nthcdr (1+ index) cscomp-typeinfo-cache)))
   6.965+;;       (setq class-list (cdr class-list))
   6.966+;;       (setq class (car class-list))
   6.967+;;       (setq found nil))))
   6.968+
   6.969+
   6.970+(defun cscomp-add-to-typeinfo-cache (name typeinfo)
   6.971+  (let (new-entry new-list)
   6.972+    (if (nth cscomp-typeinfo-cache-size cscomp-typeinfo-cache)
   6.973+        (progn
   6.974+          (setq new-entry (list name typeinfo))
   6.975+          (setq new-list (list new-entry nil))
   6.976+          (setcdr new-list (cdr cscomp-typeinfo-cache))
   6.977+          (setq cscomp-typeinfo-cache new-list)
   6.978+          (cscomp-log 1 "cache is full")   )
   6.979+      ;;else
   6.980+      (setq cscomp-typeinfo-cache
   6.981+            (append
   6.982+             cscomp-typeinfo-cache
   6.983+             (list (list name typeinfo)))))))
   6.984+
   6.985+
   6.986+(defun cscomp-get-typeinfo-from-cache (name)
   6.987+  (let ((temp (nth 0 cscomp-typeinfo-cache)) (index -1) (found nil))
   6.988+    (while (and temp (not found))
   6.989+      (setq index (1+ index))
   6.990+      (cscomp-log 2 "looking at cache item %d" index)
   6.991+      (setq temp (nth index cscomp-typeinfo-cache))
   6.992+      (if (string= (car temp) name)
   6.993+          (setq found t)))
   6.994+    (if found
   6.995+        (progn
   6.996+          (cscomp-log 3 "cscomp-get-typeinfo-from-cache: HIT name(%s) r(%s)"
   6.997+                    name (prin1-to-string (nth 1 temp)))
   6.998+          (nth 1 temp))
   6.999+      (cscomp-log 1 "cscomp-get-typeinfo-from-cache: MISS name(%s)" name)
  6.1000+      nil)))
  6.1001+
  6.1002+
  6.1003+(defun cscomp-get-typeinfo (name)
  6.1004+  "Return the class info list for the class NAME. This function first
  6.1005+checks to see if the class info is cached. If so, it returns the
  6.1006+cached class info. Otherwise, it creates the type info list. Each
  6.1007+element of the list returned by this function is itself a list whose
  6.1008+car is a possible completion and whose cdr gives additional
  6.1009+informations on the completion - the property type, or the param
  6.1010+list and return type for a method, etc."
  6.1011+  (interactive "sTypename: ")
  6.1012+
  6.1013+  (cscomp-log 2 "cscomp-get-typeinfo name(%s)...trying cache..." name)
  6.1014+
  6.1015+  (let ((type-info (cscomp-get-typeinfo-from-cache name))
  6.1016+        (usinglist (cscomp-referenced-assemblies-list))
  6.1017+        namespace
  6.1018+        qualified-type )
  6.1019+
  6.1020+    ;; load all the assemblies mentioned in the using clauses
  6.1021+    (while usinglist
  6.1022+      (setq namespace (car usinglist))
  6.1023+      (cscomp-load-assembly namespace)
  6.1024+      (setq usinglist (cdr usinglist)))
  6.1025+
  6.1026+    (if (null type-info)
  6.1027+        (progn
  6.1028+          (setq qualified-type
  6.1029+                (csharp-shell-exec-and-eval-result (concat
  6.1030+                                    "[Ionic.Cscomp.Utilities]::QualifyType('"
  6.1031+                                    ;;(cscomp-escape-string-for-powershell name)
  6.1032+                                    ;; dont need to escape if using single quotes
  6.1033+                                     name
  6.1034+                                    "')")))
  6.1035+
  6.1036+          (cscomp-log 1 "cscomp-get-typeinfo...(%s)..." (prin1-to-string qualified-type))
  6.1037+
  6.1038+          (if qualified-type
  6.1039+              (setq type-info
  6.1040+                    (csharp-shell-exec-and-eval-result (concat "[Ionic.Cscomp.Utilities]::GetTypeInfo('"
  6.1041+                                                (car qualified-type) ; type name
  6.1042+                                               "', '"
  6.1043+                                               (cadr qualified-type) ; assembly name
  6.1044+                                               "')" ))))
  6.1045+          (if type-info
  6.1046+              (cscomp-add-to-typeinfo-cache name type-info))))
  6.1047+
  6.1048+    type-info))
  6.1049+
  6.1050+
  6.1051+(defun cscomp-get-type-ctors (type-name)
  6.1052+  "Retrieve constructors from CscompShell for the type named by TYPE-NAME.
  6.1053+"
  6.1054+  (interactive "sType name: ")
  6.1055+  (cscomp-invoke-shell-fn "GetConstructors" type-name))
  6.1056+
  6.1057+
  6.1058+
  6.1059+
  6.1060+(defun cscomp-split-by-dots (s)
  6.1061+  "When the string contains a dot, this fn returns a 2-element
  6.1062+list (TOKEN1 TOKEN2).  TOKEN1 is the substring of s that precedes
  6.1063+the last dot.  TOKEN2 is the substring that follows the last dot.
  6.1064+
  6.1065+When the string does not contain a dot, this fn returns a
  6.1066+2-element list in which the first element is nil and the 2nd
  6.1067+element is the entire string.
  6.1068+
  6.1069+"
  6.1070+  (cscomp-log 2 "cscomp-split-by-dots: s[%s]" s)
  6.1071+  (if (string-match "\\(.*\\)\\.\\(.*\\)" s)
  6.1072+      (let ((result (list (match-string 1 s) (match-string 2 s))))
  6.1073+        (cscomp-log 2 "cscomp-split-by-dots: %s" (prin1-to-string result))
  6.1074+        result)
  6.1075+    (list nil s))) ;; it's a single atom
  6.1076+
  6.1077+
  6.1078+
  6.1079+
  6.1080+(defun cscomp-parse-csharp-expression-before-point ()
  6.1081+  "Parses the text at point, and returns the results.
  6.1082+
  6.1083+The retval is a list (POSN (TOKEN1 TOKEN2)) , where POSN is the position
  6.1084+in the buffer of the beginning of TOKEN1 and TOKEN1 and TOKEN2
  6.1085+are the two tokens surrounding the prior dot.
  6.1086+
  6.1087+For example, suppose System.Diagnostics.D were the name at
  6.1088+point. This function would return the list
  6.1089+
  6.1090+    (888 (\"System.Diagnostics\" \"D\"))
  6.1091+
  6.1092+...if 888 was the position of the beginning of the word System.
  6.1093+
  6.1094+It's just an exercise in syntactically-aware string parsing.
  6.1095+
  6.1096+If the text preceding point doesn't look like two tokens, this fn
  6.1097+returns nil.
  6.1098+
  6.1099+"
  6.1100+  (cscomp-log 2 "parse-csharp-expression-before-point: point(%d)" (point))
  6.1101+
  6.1102+  (interactive)
  6.1103+  (save-excursion
  6.1104+    (let ((opoint (point))
  6.1105+          (cycle-count 0)
  6.1106+          (dot-count 0)
  6.1107+          m1
  6.1108+          (regex "[-\\+\\*\\/%,;( {})=\\.]")
  6.1109+          snip done
  6.1110+          (paren-depth 0)
  6.1111+          ;;           (skip-back '(lambda ()
  6.1112+          ;;                         (skip-chars-backward "\t ")
  6.1113+          ;;                         (backward-char)))
  6.1114+          )
  6.1115+
  6.1116+
  6.1117+      (while (not done)
  6.1118+
  6.1119+        (skip-chars-backward "\t ")
  6.1120+
  6.1121+        (cond
  6.1122+
  6.1123+         ((and (eq cycle-count 0) ;; first time through
  6.1124+               (eq (char-before) 40)) ;; 40 = open paren - means we want fn completion
  6.1125+          (backward-char))             ;; backup
  6.1126+
  6.1127+         ((eq (char-before) 34) ;; 34 = doublequote
  6.1128+          (backward-char 1)     ;; move back into the quoted string
  6.1129+          (let ((limits (c-literal-limits)))
  6.1130+            (if (consp limits)
  6.1131+                (c-safe (goto-char (car limits)))))) ;; goto beginning of literal string
  6.1132+
  6.1133+         ;;          ((eq (char-before) 41)       ;; 41 = close paren - means we want fn completion
  6.1134+         ;;           (incf paren-depth)
  6.1135+         ;;           (backward-char))
  6.1136+         ;;
  6.1137+         ;;          ((and
  6.1138+         ;;            (eq (char-before) 40)      ;; 40 = open paren
  6.1139+         ;;            (> paren-depth 0))         ;; we have a pending close paren (moving backwards)
  6.1140+         ;;           (decf paren-depth)
  6.1141+         ;;           ;;(funcall skip-back))
  6.1142+         ;;           (backward-char))
  6.1143+
  6.1144+         ;;          ((or
  6.1145+         ;;            (eq (char-before) 32)       ;; space
  6.1146+         ;;            (eq (char-before) ?\t))     ;; tab
  6.1147+         ;;          (funcall skip-back))
  6.1148+
  6.1149+         ((re-search-backward regex nil t)
  6.1150+          (cond
  6.1151+
  6.1152+           ((eq (char-after) 41) ;; 41 = close paren - means we want fn completion
  6.1153+            (incf paren-depth)
  6.1154+            t)
  6.1155+
  6.1156+           ((and
  6.1157+             (eq (char-after) 40) ;; 40 = open paren
  6.1158+             (> paren-depth 0)) ;; we have a pending close paren (moving backwards)
  6.1159+            (decf paren-depth)
  6.1160+            ;;(funcall skip-back))
  6.1161+            t)
  6.1162+
  6.1163+
  6.1164+           ((or
  6.1165+             (eq (char-after) 32)   ;; space
  6.1166+             (eq (char-after) ?\t)) ;; tab
  6.1167+            t)                      ;; do nothing
  6.1168+
  6.1169+           ((eq (char-after) ?.)
  6.1170+            (setq m1 (point)
  6.1171+                  regex "[-\\+\\*\\/%,;( {})=]"))
  6.1172+
  6.1173+           (t
  6.1174+            (setq done t))))
  6.1175+
  6.1176+         (t
  6.1177+          (backward-char)))
  6.1178+
  6.1179+        (incf cycle-count)) ;; count of steps backward
  6.1180+
  6.1181+      (setq snip
  6.1182+            (cscomp-consolidate-whitespace
  6.1183+             (buffer-substring-no-properties (1+ (point)) opoint)))
  6.1184+
  6.1185+      (cscomp-log 2 "parse-expression-before-point: B snip(%s)" snip)
  6.1186+      (list (1+ (point)) (cscomp-split-by-dots snip)))
  6.1187+    ))
  6.1188+
  6.1189+
  6.1190+
  6.1191+
  6.1192+(defun cscomp-qualify-local-var (symbol opoint)
  6.1193+  "Use the semantic lex/analysis results to classify the
  6.1194+name as a local variable. Returns a list, 1st elt is the
  6.1195+variable type, and the second elt is a vector, containing
  6.1196+the position of its definition.
  6.1197+
  6.1198+See also `cscomp-qualify-instance-var'.
  6.1199+"
  6.1200+  (cscomp-start-stripped-semantic)
  6.1201+  ;;(semantic-lex (point-min) (point-max) 100)
  6.1202+  (let ((locals (semantic-get-local-variables))
  6.1203+        (args (semantic-get-local-arguments))
  6.1204+        (result nil)
  6.1205+        (decl-count 0)
  6.1206+        (prior-var-decls ""))
  6.1207+
  6.1208+    (while (and locals (not result))
  6.1209+      (let* ((x (car locals))
  6.1210+             (var-name (car x))
  6.1211+             (var-type (cadr (nth 2 x)))
  6.1212+             (var-pos (nth 4 x)))  ;; pair: start and end of var decl
  6.1213+
  6.1214+        ;; The simple string= test will give a false positive if there's
  6.1215+        ;; a foreach loop variable in a prior
  6.1216+        ;; foreach loop with the same name as the one the user
  6.1217+        ;; wants completion on.
  6.1218+        ;;
  6.1219+        ;; This is only an issue with two or more foreach loops, each of
  6.1220+        ;; which create a separate naming scope, and which have the same
  6.1221+        ;; variable name.  All those foreach variables will be reported
  6.1222+        ;; as "local variables" by semantic. But, not all of them are in
  6.1223+        ;; scope for the completion we're performing right now.
  6.1224+        ;;
  6.1225+        ;; This needs to do something more intelligent with
  6.1226+        ;; the declaration. If I had a way to interrogate the scope of
  6.1227+        ;; the variable decl, that would help. But right now I don't have
  6.1228+        ;; that.
  6.1229+
  6.1230+        ;; I think I need a better understanding of the semantic.el
  6.1231+        ;; package.
  6.1232+        ;; =======================================================
  6.1233+
  6.1234+
  6.1235+        ;; if this decl ends *before* the point at which the user is
  6.1236+        ;; asking for completion.
  6.1237+        (if (<  (elt var-pos 1) opoint)
  6.1238+
  6.1239+            ;; If this var decl is the same name as the one
  6.1240+            ;; we want.
  6.1241+            (if (string= var-name symbol)
  6.1242+                (progn
  6.1243+
  6.1244+                  ;; Handle var types - need to determine the actual type.
  6.1245+                  ;;
  6.1246+                  ;; To do that, compile the var declaration, then inspect the IL
  6.1247+                  ;; to determine the var types.
  6.1248+                  ;;
  6.1249+                  ;; This engine will determine the var type, in some portion% of
  6.1250+                  ;; the cases.
  6.1251+                  ;;
  6.1252+                  ;; It will handle:
  6.1253+                  ;;
  6.1254+                  ;;  - simple var declarations that have no dependencies on other vars
  6.1255+                  ;;  - cascaded var decls that depend on other local vars.
  6.1256+                  ;;
  6.1257+                  ;; For now, it will not handle:
  6.1258+                  ;;
  6.1259+                  ;;  - var that depends on a method argument
  6.1260+                  ;;  - var whose initialization depends on an instance var
  6.1261+                  ;;  - var decls in foreach loops
  6.1262+                  ;;
  6.1263+
  6.1264+                  ;; if the type of the variable is "var"
  6.1265+                  (if (string= var-type "var")
  6.1266+                      (let* ((this-decl
  6.1267+                              (buffer-substring-no-properties (elt var-pos 0) (elt var-pos 1)))
  6.1268+
  6.1269+                             (containing-type (cscomp-get-current-class))
  6.1270+                             (member-list (cscomp-get-members-of-class containing-type))
  6.1271+                             (name-of-containing-type  (car containing-type))
  6.1272+
  6.1273+                             (inferred-type
  6.1274+                              (cscomp-get-var-type-given-decl
  6.1275+                               (concat prior-var-decls " " this-decl)
  6.1276+                               decl-count
  6.1277+                               name-of-containing-type
  6.1278+                               (cscomp-produce-csharp-arglist-block-from-dbrecord args)
  6.1279+                               (cscomp-produce-instance-member-code-fragment member-list)
  6.1280+                               )))
  6.1281+
  6.1282+                        (if (and inferred-type (string= (car inferred-type) "type"))
  6.1283+                            (setq var-type (cadr inferred-type))
  6.1284+                          (message "%s" (prin1-to-string inferred-type))
  6.1285+                          )))
  6.1286+
  6.1287+                  (cscomp-log 2 "cscomp-qualify-local-var: found %s (%s)"
  6.1288+                            symbol var-type)
  6.1289+                  (setq result (list var-type var-pos)))
  6.1290+
  6.1291+              ;; else - remember it. We may need it later
  6.1292+              (let* ((this-var-decl
  6.1293+                      (buffer-substring-no-properties (elt var-pos 0) (elt var-pos 1)))
  6.1294+                     (tokens (split-string this-var-decl "[ \t]" t)))
  6.1295+
  6.1296+                ;; include decl in prior decls if not "foreach(var foo in X)"
  6.1297+                (if (or (< (length tokens) 4)
  6.1298+                        (not (string= (nth 3 tokens) "in")))
  6.1299+                    (setq prior-var-decls (concat prior-var-decls " " this-var-decl)
  6.1300+                          decl-count (1+ decl-count))
  6.1301+
  6.1302+                  ;; else - it's a foreach loop
  6.1303+
  6.1304+                  ;; If performing completion on a var within the loop that
  6.1305+                  ;; depends on the loop variable, then we need to infer
  6.1306+                  ;; the type of the foreach loop variable here.
  6.1307+                  ;;
  6.1308+                  ;; But, I'm punting.
  6.1309+
  6.1310+                  )))))
  6.1311+      (setq locals (cdr locals)))
  6.1312+
  6.1313+    result))
  6.1314+
  6.1315+
  6.1316+
  6.1317+
  6.1318+
  6.1319+(defun cscomp-qualify-instance-var (symbol)
  6.1320+  "Use the semantic lex/analysis results to classify the
  6.1321+name as an instance variable. Returns a list, 1st elt is the
  6.1322+variable type, and the second elt is a vector, containing
  6.1323+the position of its definition.
  6.1324+
  6.1325+See also `cscomp-qualify-local-var'.
  6.1326+
  6.1327+"
  6.1328+  (cscomp-start-stripped-semantic)
  6.1329+  ;;(semantic-lex (point-min) (point-max) 100)
  6.1330+  (let ((ivars (cscomp-instance-vars))
  6.1331+        (result nil))
  6.1332+    (while (and ivars (not result))
  6.1333+      (let* ((x (car ivars))
  6.1334+             (var-name (car x))
  6.1335+             (var-type (cadr (nth 2 x)))
  6.1336+             (var-pos (nth 4 x)))
  6.1337+        (if (string= var-name symbol)
  6.1338+            (progn
  6.1339+              (cscomp-log 2 "cscomp-qualify-instance-var: found %s (%s)"
  6.1340+                       symbol var-type)
  6.1341+            (setq result (list var-type var-pos))))
  6.1342+      (setq ivars (cdr ivars))))
  6.1343+    result))
  6.1344+
  6.1345+
  6.1346+
  6.1347+
  6.1348+(defun cscomp-start-stripped-semantic ()
  6.1349+  "Enable a stripped-down semantic for usage with csharp-completion.
  6.1350+Semantic is very ambitious and tries to do many things, including
  6.1351+predictive completion, modified code formatting, and other
  6.1352+things.  We don't want all that for this simple completion
  6.1353+module. So this method starts a stripped-down version of
  6.1354+semantic.
  6.1355+
  6.1356+"
  6.1357+  (interactive)
  6.1358+
  6.1359+  (if (null semantic-load-system-cache-loaded)
  6.1360+      (progn
  6.1361+        ;;(semantic-lex (point-min) (point-max) 100)
  6.1362+        (semantic-fetch-tags)
  6.1363+        (global-semantic-idle-scheduler-mode 1)
  6.1364+        ;;(global-semanticdb-minor-mode 1)
  6.1365+        ;; This loads any created system databases which get linked into
  6.1366+        ;; any searches performed.
  6.1367+        (setq semantic-load-system-cache-loaded t)
  6.1368+        )))
  6.1369+
  6.1370+
  6.1371+
  6.1372+
  6.1373+
  6.1374+;;     (let (start
  6.1375+;;           varname
  6.1376+;;           (curcar (char-before))
  6.1377+;;           found
  6.1378+;;           (original-point (point))
  6.1379+;;           intermediate-point
  6.1380+;;           beg-point
  6.1381+;;           first-part
  6.1382+;;           second-part
  6.1383+;;           (bracket-count 0)
  6.1384+;;           (paren-count 0))
  6.1385+;;
  6.1386+;;
  6.1387+;;       (while (null found)
  6.1388+;;         (cond
  6.1389+;;
  6.1390+;;          ;; car is a-z, A-Z 0-9 or greater than 127, or slash or underscore
  6.1391+;;          ((or (and (>= curcar ?a) (<= curcar ?z))
  6.1392+;;               (and (>= curcar ?A) (<= curcar ?Z))
  6.1393+;;               (and (>= curcar ?0) (<= curcar ?9))
  6.1394+;;               (>= curcar 127)
  6.1395+;;               (member curcar '(?_ ?\\ )))
  6.1396+;;           ;; back up!
  6.1397+;;           (forward-char -1))
  6.1398+;;
  6.1399+;;          ;; curchar is a dot
  6.1400+;;          ((eq ?. curcar)
  6.1401+;;           (setq found (point)))
  6.1402+;;
  6.1403+;;          ;; else
  6.1404+;;          (t
  6.1405+;;           (setq found t)))
  6.1406+;;
  6.1407+;;
  6.1408+;;         (setq curcar (char-before)))
  6.1409+;;
  6.1410+;;       ;; we've backed-up to...the nearest dot or non- alphanumeric char.
  6.1411+;;
  6.1412+;;
  6.1413+;;       ;; ??
  6.1414+;;       (setq intermediate-point (point))
  6.1415+;;
  6.1416+;;
  6.1417+;;       (if (not (eq t found))  ;; not t means we found a dot
  6.1418+;;           (progn
  6.1419+;;
  6.1420+;;             ;; get the char before
  6.1421+;;             (setq curcar (char-before))
  6.1422+;;             (while (or (and (>= curcar ?a) (<= curcar ?z))
  6.1423+;;                        (and (>= curcar ?A) (<= curcar ?Z))
  6.1424+;;                        (and (>= curcar ?0) (<= curcar ?9))
  6.1425+;;                        (>= curcar 127)
  6.1426+;;                        (and (eq curcar ? ) (or (< 0 paren-count) (< 0 bracket-count)))
  6.1427+;;                        (member curcar '(?\. ?\_ ?\\ ?\( ?\) ?\, ?\[ ?\])))
  6.1428+;;               (cond
  6.1429+;;                ((eq curcar ?\) )
  6.1430+;;                 (setq paren-count (1+ paren-count)))
  6.1431+;;                ((eq curcar ?\( )
  6.1432+;;                 (setq paren-count (1- paren-count)))
  6.1433+;;                ((eq curcar ?\] )
  6.1434+;;                 (setq paren-count (1+ bracket-count)))
  6.1435+;;                ((eq curcar ?\[ )
  6.1436+;;                 (setq paren-count (1- bracket-count))))
  6.1437+;;               (forward-char -1)
  6.1438+;;
  6.1439+;;               (setq curcar (char-before)))
  6.1440+;;
  6.1441+;;
  6.1442+;;             (setq beg-point (point))
  6.1443+;;
  6.1444+;;             (set-marker cscomp-current-beginning intermediate-point)
  6.1445+;;
  6.1446+;;             (set-marker cscomp-current-end original-point)
  6.1447+;;
  6.1448+;;             (setq first-part (buffer-substring-no-properties beg-point (- intermediate-point 1)))
  6.1449+;;
  6.1450+;;             (setq first-part (cscomp-isolate-to-complete first-part))
  6.1451+;;
  6.1452+;;             (string-match " *\\(.*\\)" first-part)
  6.1453+;;
  6.1454+;;             (setq first-part (substring first-part (match-beginning 1) (match-end 1)))
  6.1455+;;
  6.1456+;;             (setq second-part (buffer-substring-no-properties intermediate-point original-point))
  6.1457+;;
  6.1458+;;             (list first-part second-part))
  6.1459+;;
  6.1460+;;         nil))))
  6.1461+
  6.1462+
  6.1463+
  6.1464+(defun cscomp-build-clist-for-ns (nsinfo)
  6.1465+  "Build a completion list from the NSINFO list, as returned by the
  6.1466+Ionic.Cscomp.Utilities.GetCompletionsForNamespace function.
  6.1467+
  6.1468+If the incoming NSINFO list looks like this:
  6.1469+
  6.1470+  (\"System.Collections.Generic\"
  6.1471+     (types (\"ArraySortHelper`1\"
  6.1472+             \"ArraySortHelper`2\"
  6.1473+             \"ByteEqualityComparer\"
  6.1474+             \"Comparer`1\"
  6.1475+             \"Dictionary`2\"
  6.1476+             \"EqualityComparer`1\"))
  6.1477+     (namespaces (\"Something1\"
  6.1478+             \"Something2`2\")))
  6.1479+
  6.1480+Then the return value is like this:
  6.1481+
  6.1482+  (\"ArraySortHelper<T1,T2> | (type)\"
  6.1483+   \"ArraySortHelper<T1> | (type)\"
  6.1484+   \"ByteEqualityComparer | (type)\"
  6.1485+   \"Comparer<T1> | (type)\"
  6.1486+   \"Dictionary<T1,T2> | (type)\"
  6.1487+   \"EqualityComparer<T1> | (type)\"
  6.1488+   \"Something1 | (type)\"
  6.1489+   \"Something2`2 | (type)\")
  6.1490+
  6.1491+"
  6.1492+  (let* ((typelist (cadr (cadr nsinfo)))
  6.1493+         (nslist
  6.1494+          (mapcar '(lambda (item) (concat item " | (namespace)") )
  6.1495+                  (cadr (caddr nsinfo)))))
  6.1496+    (cscomp-fix-generic-method-strings typelist)
  6.1497+    (setq typelist (mapcar '(lambda (item) (concat item " | (type)") )
  6.1498+                           typelist))
  6.1499+    ;;(reverse (sort (append typelist nslist) 'string-lessp))
  6.1500+    (sort (append typelist nslist) 'string-lessp)
  6.1501+  ))
  6.1502+
  6.1503+
  6.1504+
  6.1505+(defun string-replace-char (s c1 c2)
  6.1506+  "Replace all occurrences of char C1 in string with char C2.
  6.1507+Return the modified string."
  6.1508+  (let ((string-len  (length s))
  6.1509+        (ix 0))
  6.1510+    (while (< ix string-len)
  6.1511+      (if (eq (aref s ix) c1)
  6.1512+          (aset s ix c2))
  6.1513+      (incf ix)))
  6.1514+  s)
  6.1515+
  6.1516+
  6.1517+
  6.1518+(defun cscomp-fix-one-generic-method-string (descrip)
  6.1519+  "Reformat the generic type string like System.Action`1
  6.1520+into a C#-friendly System.Action<T1> . Returns the reformatted
  6.1521+string.  Returns nil if reformat was unnecessary.
  6.1522+"
  6.1523+  (cond
  6.1524+
  6.1525+   ;; input:  System.Converter`2[T,TOutput]
  6.1526+   ;; output: System.Converter<T,TOutput>
  6.1527+   ((string-match "^\\(.+\\)`[1-9]\\[\\([^]]+\\)\\]$" descrip)
  6.1528+    (concat
  6.1529+     (match-string 1 descrip)
  6.1530+     "<"
  6.1531+     (match-string 2 descrip)
  6.1532+     ">"))
  6.1533+
  6.1534+   ;; input:  System.Collections.Generic.Dictionary`2
  6.1535+   ;; output: System.Collections.Generic.Dictionary<T1,T2>
  6.1536+   ((string-match "^\\(.+\\)`\\([1-9]\\)\\(.*\\)$" descrip)
  6.1537+    (let ((z (string-to-number (match-string 2 descrip)))
  6.1538+          (new-name (concat (match-string 1 descrip) "<"))
  6.1539+          (i 0))
  6.1540+      (while (< i z)
  6.1541+        (setq i (1+ i)
  6.1542+              new-name (concat new-name (format "T%d" i)))
  6.1543+        (if (< i z)
  6.1544+            (setq new-name (concat new-name ","))))
  6.1545+      (setq new-name (concat new-name ">" (match-string 3 descrip)))))
  6.1546+
  6.1547+   ;; anything else
  6.1548+   (t nil)))
  6.1549+
  6.1550+
  6.1551+
  6.1552+(defun cscomp-fix-generic-method-strings (clist)
  6.1553+  "Fixup a list of strings, that may have generic method types
  6.1554+in them, to have C#-friendly formats.  This fn does the modifications
  6.1555+in place. The return value is the original list, with the internal values
  6.1556+modified.
  6.1557+
  6.1558+"
  6.1559+  (let ((count  (list-length clist))
  6.1560+        (n 0)
  6.1561+        new-name
  6.1562+        cur-elt)
  6.1563+    (while (< n count)
  6.1564+      (setq cur-elt (nth n clist))
  6.1565+      (if (setq new-name (cscomp-fix-one-generic-method-string cur-elt))
  6.1566+          (setf (nth n clist) new-name))
  6.1567+      ;; the following will affect the string in the list
  6.1568+      (string-replace-char cur-elt ?+ ?.)
  6.1569+      (setq n (1+ n))))
  6.1570+  clist)
  6.1571+
  6.1572+
  6.1573+
  6.1574+(defun cscomp-fix-generics-in-descrip-line (descrip-line)
  6.1575+  "Fixup a string, a description of a method or property, to
  6.1576+have C#-friendly generic types.
  6.1577+
  6.1578+Eg, convert  (Method) public (System.Converter`2[T,TOutput] converter) returns List`1[TOutput]
  6.1579+
  6.1580+to  (Method) public (System.Converter<T,TOutput> converter) returns List<TOutput>
  6.1581+
  6.1582+"
  6.1583+  (let ((tokens (split-string descrip-line "[ \t]" t)))
  6.1584+    (cscomp-fix-generic-method-strings tokens)
  6.1585+    (mapconcat 'identity tokens " ")))
  6.1586+
  6.1587+
  6.1588+
  6.1589+
  6.1590+
  6.1591+(defun cscomp-build-clist-for-type (typeinfo)
  6.1592+  "Build a completion list from the TYPEINFO list, as returned by the
  6.1593+Ionic.Cscomp.Utilities.GetTypeinfo function in the CscompShell. The list
  6.1594+is used when performing completions on an instance of a given type.
  6.1595+
  6.1596+For input that looks like this:
  6.1597+
  6.1598+  (\"System.IO.DriveInfo\" 'type
  6.1599+   ((\"Name\"               'property \"System.String\" (typemodifiers \"readonly\" \"public\"))
  6.1600+    (\"AvailableFreeSpace\" 'property \"System.Int64\"  (typemodifiers \"readonly\" \"public\"))
  6.1601+    (\"TotalFreeSpace\"     'property \"System.Int64\"  (typemodifiers \"readonly\" \"public\"))
  6.1602+    (\"VolumeLabel\"        'property \"System.String\" (typemodifiers \"public\")))
  6.1603+
  6.1604+   ((\"Equals\" method \"System.Boolean\" (\"System.Object obj\") (typemodifiers \"public\"))
  6.1605+    (\"GetDrives\" method \"System.IO.DriveInfo[]\" nil (typemodifiers \"public\" \"static\"))
  6.1606+    (\"ToString\" method \"System.String\" nil (typemodifiers \"public\"))))
  6.1607+
  6.1608+
  6.1609+The output looks like this:
  6.1610+
  6.1611+  ((\"ToString\"           \"(Method) public () returns System.String\")
  6.1612+   (\"GetDrives\"          \"(Method) public static () returns System.IO.DriveInfo[]\")
  6.1613+   (\"Equals\"             \"(Method) public (System.Object obj)  returns System.Boolean\")
  6.1614+   (\"VolumeLabel\"        \"(Property) public System.String\")
  6.1615+   (\"TotalFreeSpace\"     \"(Property) readonly public System.Int64\")
  6.1616+   (\"AvailableFreeSpace\" \"(Property) readonly public System.Int64\")
  6.1617+   (\"Name\"               \"(Property) readonly public System.String\"))
  6.1618+
  6.1619+"
  6.1620+
  6.1621+  (let (result
  6.1622+        (tname   (car typeinfo))
  6.1623+        (props   (caddr typeinfo))
  6.1624+        (methods (cadddr typeinfo))
  6.1625+        (fields  (caddr (cddr typeinfo)))
  6.1626+        modifiers)
  6.1627+
  6.1628+    (cscomp-log 2 "cscomp-build-clist-for-type: typename(%s)" tname)
  6.1629+
  6.1630+    (while props
  6.1631+      (let ((one-prop (car props) ) )
  6.1632+        (setq modifiers
  6.1633+              (mapconcat 'identity (cdr (nth 3 one-prop)) " "))
  6.1634+        (setq result
  6.1635+              (append (list
  6.1636+                       (list
  6.1637+                        (car one-prop)   ;; the name of the property
  6.1638+
  6.1639+                        ;; additional information about the property
  6.1640+                        (concat "(Property) "
  6.1641+                                modifiers  ;; modifiers on this prop
  6.1642+                                " "
  6.1643+                                (nth 2 one-prop)  ;; type of the prop
  6.1644+                                )))
  6.1645+                      result)))
  6.1646+      (setq props (cdr props)))
  6.1647+
  6.1648+    (while methods
  6.1649+      (let ((one-method (car methods)) params)
  6.1650+        (setq modifiers
  6.1651+              (mapconcat 'identity (cdr (nth 4 one-method)) " "))
  6.1652+        (setq params
  6.1653+              (if (nth 3 one-method)
  6.1654+                  (concat "("
  6.1655+                          (mapconcat 'identity (nth 3 one-method)  ", ")
  6.1656+                          ")")
  6.1657+                ;; else
  6.1658+                "()" ))
  6.1659+
  6.1660+        (setq result
  6.1661+              (append (list
  6.1662+                       (list
  6.1663+                        (car one-method)   ;; the name of the method
  6.1664+
  6.1665+                        ;; additional information about the method (in a string)
  6.1666+                        (concat "(Method) "
  6.1667+                                modifiers           ;; modifiers on this prop
  6.1668+                                "  "
  6.1669+                                params
  6.1670+                                "  returns "
  6.1671+                                (nth 2 one-method)  ;; return type of the method
  6.1672+                                )
  6.1673+                        ))
  6.1674+                      result)))
  6.1675+
  6.1676+      (setq methods (cdr methods)))
  6.1677+
  6.1678+
  6.1679+    (while fields
  6.1680+      (let ((one-field (car fields)))
  6.1681+        (setq modifiers
  6.1682+              (mapconcat 'identity (cdr (nth 3 one-field)) " "))
  6.1683+        (setq result
  6.1684+              (append (list
  6.1685+                       (list
  6.1686+                        (car one-field)   ;; the name of the field
  6.1687+
  6.1688+                        ;; additional information about the field (in a string)
  6.1689+                        (concat "(Field) "
  6.1690+                                modifiers           ;; modifiers on this prop
  6.1691+                                "  "
  6.1692+                                (nth 2 one-field)  ;; type of the field
  6.1693+                                )
  6.1694+                        ))
  6.1695+                      result)))
  6.1696+
  6.1697+      (setq fields (cdr fields)))
  6.1698+
  6.1699+
  6.1700+    (cscomp-log 3 "cscomp-build-clist-for-type: result: "
  6.1701+              (prin1-to-string result))
  6.1702+    ;;(print result (get-buffer "*Messages*"))
  6.1703+    result))
  6.1704+
  6.1705+
  6.1706+
  6.1707+(defun cscomp-build-clist-for-ctors (ctor-info)
  6.1708+  "Build a completion list from the CTOR-INFO list, as returned by the
  6.1709+Ionic.Cscomp.Utilities.GetConstructors function in the CscompShell. The list
  6.1710+is used when performing completions on a constructor for a given type.
  6.1711+
  6.1712+The input looks like:
  6.1713+  (\"System.String\" 'type
  6.1714+               (:constructors
  6.1715+
  6.1716+                ((:typemodifiers (\"public\")
  6.1717+                  :arguments ((\"value\" 'variable
  6.1718+                          (:type \"System.Char*\"))))
  6.1719+
  6.1720+                 (:typemodifiers (\"public\")
  6.1721+                  :arguments ((\"value\" 'variable
  6.1722+                                     (:type \"System.Char*\"))
  6.1723+                   (\"startIndex\" 'variable
  6.1724+                               (:type \"System.Int32\"))
  6.1725+                   (\"length\" 'variable
  6.1726+                           (:type \"System.Int32\"))))
  6.1727+
  6.1728+The output is a completion list, which is a list of (NAME DESCRIP) pairs.
  6.1729+The DESCRIP of each pair should have the arguments for each constructor.
  6.1730+
  6.1731+That list is later transformed into a structure that is suitable
  6.1732+for use in a popup menu.
  6.1733+
  6.1734+"
  6.1735+  (let (result
  6.1736+        (tname   (car ctor-info))
  6.1737+        (ctors   (cadr (caddr ctor-info)))
  6.1738+        ;;(methods (cadddr typeinfo))
  6.1739+        )
  6.1740+
  6.1741+    (cscomp-log 2 "cscomp-build-clist-for-ctor: typename(%s)" tname)
  6.1742+
  6.1743+    (while ctors
  6.1744+      (let* ((one-ctor (car ctors))
  6.1745+             (modifiers (mapconcat 'identity  (nth 1 one-ctor) " "))
  6.1746+             (params
  6.1747+              (if (nth 3 one-ctor)
  6.1748+                  (concat "("
  6.1749+                          (mapconcat
  6.1750+                           '(lambda (x)
  6.1751+                              (concat
  6.1752+                               (cadr (caddr x))
  6.1753+                               " "
  6.1754+                               (car x)))
  6.1755+                           (nth 3 one-ctor)  ", ")
  6.1756+                          ")")
  6.1757+                ;; else
  6.1758+                "()" )))
  6.1759+        (setq result
  6.1760+              (append (list
  6.1761+                       (list
  6.1762+                        tname  ;; name of the ctor
  6.1763+
  6.1764+                        ;; description for this ctor
  6.1765+                        (concat "(Constructor) "
  6.1766+                                modifiers  ;; modifiers on this prop
  6.1767+                                " "
  6.1768+                                params
  6.1769+                                )))
  6.1770+                      result)))
  6.1771+      (setq ctors (cdr ctors)))
  6.1772+
  6.1773+    (cscomp-log 3 "cscomp-build-clist-for-ctors: result: "
  6.1774+              (prin1-to-string result))
  6.1775+    result))
  6.1776+
  6.1777+
  6.1778+
  6.1779+;; (defun cscomp-build-information-for-completion (lst)
  6.1780+;;   (let ((result (concat (car (cdr lst)) " " (car lst) "(")))
  6.1781+;;     (setq lst (cdr (cdr lst)))
  6.1782+;;     (while lst
  6.1783+;;       (setq result (concat result (car lst)))
  6.1784+;;       (setq lst (cdr lst))
  6.1785+;;       (if lst
  6.1786+;;           (setq result (concat result ", "))))
  6.1787+;;     (setq result (concat result ")"))
  6.1788+;;     result))
  6.1789+
  6.1790+
  6.1791+
  6.1792+
  6.1793+;; (defun cscomp-popup-xemacs-completion-menu (completion-list)
  6.1794+;;   (let* ((items
  6.1795+;;        (sort
  6.1796+;;         ;; Change each item in the completion list from the form
  6.1797+;;         ;;   return-value method-name(args)
  6.1798+;;         ;; to the form
  6.1799+;;         ;;   method-name(args) : return-value
  6.1800+;;         (mapcar
  6.1801+;;          (lambda (completion)
  6.1802+;;            (let ((completion-short (nth 0 completion))
  6.1803+;;                  (completion-long (nth 1 completion)))
  6.1804+;;              (if completion-long
  6.1805+;;                  (let ((chop-pos (string-match " " completion-long)))
  6.1806+;;                    (concat
  6.1807+;;                     (substring completion-long (1+ chop-pos)
  6.1808+;;                                (length completion-long))
  6.1809+;;                     " : "
  6.1810+;;                     (substring completion-long 0 chop-pos)))
  6.1811+;;                completion-short)))
  6.1812+;;          completion-list)
  6.1813+;;         'string<))
  6.1814+;;       (menu
  6.1815+;;        (cons
  6.1816+;;         "Completions"
  6.1817+;;         (mapcar
  6.1818+;;          (lambda (item)
  6.1819+;;            (vector item (list 'cscomp-insert-completion item)))
  6.1820+;;          items))))
  6.1821+;;     (popup-menu-and-execute-in-window menu (selected-window))))
  6.1822+
  6.1823+
  6.1824+
  6.1825+
  6.1826+(defun cscomp-sort-completion-list (lst)
  6.1827+  (if (consp (car lst))
  6.1828+      (sort lst
  6.1829+            '(lambda (e1 e2)
  6.1830+               (string< (car e1) (car e2))))
  6.1831+    (sort lst
  6.1832+          '(lambda (e1 e2)
  6.1833+             (string< e1 e2)))))
  6.1834+
  6.1835+
  6.1836+;; (defun cscomp-sort-completion-list (lst)
  6.1837+;;  ;;  "sort LST in place."
  6.1838+;;   (sort lst
  6.1839+;;         '(lambda (e1 e2)
  6.1840+;;            (if (consp e1) ;; is the list elt a consp?
  6.1841+;;                ;; yes, we're completing on a type. Sort on the car of that list
  6.1842+;;                (string< (car e1) (car e2))
  6.1843+;;              ;; no, we're completing on a namespace or local var.
  6.1844+;;              ;; The element should be a string.  Sort on it directly.
  6.1845+;;              (string< e1 e2)
  6.1846+;;              ))))
  6.1847+
  6.1848+
  6.1849+
  6.1850+(defun cscomp-find-all-ns-completions (fragment lst &optional exact-match )
  6.1851+  "Find all completions for FRAGMENT in LST.  If EXACT-MATCH is true,
  6.1852+then...?  LST is a simple list of strings, as obtained from
  6.1853+`cscomp-build-clist-for-ns'.
  6.1854+"
  6.1855+  (let ((result nil))
  6.1856+    (while lst
  6.1857+      (let ((candidate (car lst)))
  6.1858+        (if (or (and exact-match (string= fragment candidate))
  6.1859+                (and (not exact-match) (equal 0 (string-match (concat "^" fragment) candidate))))
  6.1860+            (progn
  6.1861+              (message "  HIT")
  6.1862+              (setq result (append (list candidate) result)))))
  6.1863+      (setq lst (cdr lst)))
  6.1864+
  6.1865+    (setq cscomp-current-fragment fragment)
  6.1866+
  6.1867+    ;; sort, and then transform into a list of (NAME DESCRIP) pairs:
  6.1868+    (mapcar
  6.1869+     '(lambda (item)
  6.1870+        (if (string-match "^\\([^|]+\\) +| +\\(.+\\)$" item)
  6.1871+            (list (match-string 1 item)
  6.1872+                  (match-string 2 item))
  6.1873+          item))
  6.1874+     (cscomp-sort-completion-list result))))
  6.1875+
  6.1876+
  6.1877+
  6.1878+
  6.1879+(defun cscomp-find-all-type-completions (fragment lst static &optional exact-match)
  6.1880+  "Find all completions in LST for FRAGMENT.  In practice,
  6.1881+FRAGMENT is a string containing the characters following the last
  6.1882+dot.  Eg, if the user typed System.IO.Dir, then FRAGMENT would be
  6.1883+\"Dir\".
  6.1884+
  6.1885+LST is a list obtained from `cscomp-build-clist-for-type'.
  6.1886+
  6.1887+If STATIC is non-nil, then match only non-static props/fields/methods.
  6.1888+Otherwise, match only static fields/props/methods.
  6.1889+
  6.1890+If EXACT-MATCH is true, then only the completions that match the
  6.1891+FRAGMENT exactly are returned.  Normally, EXACT-MATCH is not
  6.1892+true, and in thi case, the completions that start with the
  6.1893+FRAGMENT are returned.
  6.1894+
  6.1895+"
  6.1896+
  6.1897+;; For illustration, the LST for DriveInfo looks like this:
  6.1898+;; (
  6.1899+;;  ("Name" "(Property) readonly public System.String")
  6.1900+;;  ("DriveType" "(Property) readonly public System.IO.DriveType")
  6.1901+;;  ("DriveFormat" "(Property) readonly public System.String")
  6.1902+;;  ("IsReady" "(Property) readonly public System.Boolean")
  6.1903+;;  ("AvailableFreeSpace" "(Property) readonly public System.Int64")
  6.1904+;;  ("TotalFreeSpace" "(Property) readonly public System.Int64")
  6.1905+;;  ("TotalSize" "(Property) readonly public System.Int64")
  6.1906+;;  ("RootDirectory" "(Property) readonly public System.IO.DirectoryInfo")
  6.1907+;;  ("VolumeLabel" "(Property) public System.String")
  6.1908+;;  ("Equals" "(Method) public  (System.Object)  returns System.Boolean")
  6.1909+;;  ("GetDrives" "(Method) public static  ()  returns System.IO.DriveInfo[]")
  6.1910+;;  ("GetHashCode" "(Method) public  ()  returns System.Int32")
  6.1911+;;  ("GetType" "(Method) public  ()  returns System.Type")
  6.1912+;;  ("ToString" "(Method) public  ()  returns System.String")
  6.1913+;;  )
  6.1914+
  6.1915+
  6.1916+  (let ((result nil))
  6.1917+    (while lst
  6.1918+      (let* ((candidate (car lst))
  6.1919+             (member-name (car candidate))
  6.1920+             (descrip (cadr candidate))
  6.1921+             (is-static (string-match " static " descrip))
  6.1922+             (is-match  (and
  6.1923+                         (if static is-static (not is-static))
  6.1924+                         (if exact-match
  6.1925+                             (string= fragment member-name)
  6.1926+                           (equal 0 (string-match fragment member-name))))))
  6.1927+
  6.1928+        (cscomp-log 3 "cscomp-find-all-type-completions, looking at %s %s"
  6.1929+                  (prin1-to-string candidate)
  6.1930+                  (if is-match "MATCH" ""))
  6.1931+
  6.1932+      (if is-match
  6.1933+            (setq result (append (list candidate) result))))
  6.1934+
  6.1935+      (setq lst (cdr lst)))
  6.1936+
  6.1937+    (cscomp-log 3 "cscomp-find-all-type-completions, result: %s"
  6.1938+                (prin1-to-string result))
  6.1939+      ;;(print result (get-buffer "*Messages*"))
  6.1940+
  6.1941+    (setq cscomp-current-fragment fragment)
  6.1942+    (cscomp-sort-completion-list result)
  6.1943+    ))
  6.1944+
  6.1945+
  6.1946+
  6.1947+
  6.1948+
  6.1949+
  6.1950+(defvar cscomp-primitive-types
  6.1951+  (list
  6.1952+   '("string" "System.String")
  6.1953+   '("byte"   "System.Byte")
  6.1954+   '("sbyte"  "System.SByte")
  6.1955+   '("char"   "System.Char")
  6.1956+   '("double" "System.Double")
  6.1957+   '("float"  "System.Float")
  6.1958+   '("bool"   "System.Boolean")
  6.1959+   '("int"    "System.Int32")
  6.1960+   '("long"   "System.Int64")
  6.1961+   '("short"  "System.Int16")
  6.1962+   '("uint"    "System.UInt32")
  6.1963+   '("ulong"   "System.UInt64")
  6.1964+   '("ushort"  "System.UInt16")
  6.1965+   )
  6.1966+
  6.1967+  "a list that maps primitive C# types to their unboxed types.")
  6.1968+
  6.1969+
  6.1970+
  6.1971+(defun cscomp-map-primitive-type (type)
  6.1972+"Maps the type to the expanded name of the  type, and returns that
  6.1973+expanded name. For example, bool => System.Boolean
  6.1974+If type is not a primitive type, the result is nil."
  6.1975+  (if (member type (mapcar 'car cscomp-primitive-types))
  6.1976+    (let ((result nil)
  6.1977+          (lst cscomp-primitive-types)
  6.1978+          item )
  6.1979+    (while lst
  6.1980+      (setq item (car lst))
  6.1981+      (if (string= type (car item))
  6.1982+          (and
  6.1983+           (setq result (cadr item))
  6.1984+           (setq lst nil))
  6.1985+        ;else
  6.1986+        (setq lst (cdr lst))))
  6.1987+    result )
  6.1988+    nil ))
  6.1989+
  6.1990+
  6.1991+
  6.1992+
  6.1993+
  6.1994+(defun cscomp-find-completion-for-split (split opoint beginning-of-token1)
  6.1995+
  6.1996+  "SPLIT is a list of (TOKEN1 TOKEN2), as returned from
  6.1997+`cscomp-split-by-dots'.
  6.1998+
  6.1999+OPOINT is the point at which the user has requested completion.
  6.2000+
  6.2001+If the user has typed something followed by a dot, followed by an
  6.2002+optional fragment after the dot, then TOKEN1 may be a C#
  6.2003+namespace or class, or a variable name, or explicitly, \"this\" .
  6.2004+TOKEN2 may be the empty string, or a fragment of a name.  The
  6.2005+goal is to find a completion for these two things.
  6.2006+
  6.2007+Example: if SPLIT is (\"System\" \"Diag\") then the returned
  6.2008+completion list will contain \"Diagnostics\".
  6.2009+
  6.2010+If the completion being requested is on a type, OPOINT is used to
  6.2011+determine whether to present type names, or actual constructors.
  6.2012+Do the latter if the new keyword precedes the
  6.2013+thing-to-be-completed.
  6.2014+
  6.2015+"
  6.2016+
  6.2017+  (cscomp-log 2 "cscomp-find-completion-for-split: A: '%s' '%s'"
  6.2018+            (car split) (cadr split))
  6.2019+
  6.2020+  ;;
  6.2021+  ;; p1 is what precedes the final dot, p2 is what follows.
  6.2022+  ;; When there is no dot, p1 is nil.
  6.2023+  ;;
  6.2024+  ;;
  6.2025+  ;; Possibilities:
  6.2026+  ;;
  6.2027+  ;; 1. p1 is a namespace like System.Xml  p2 is empty, or a fragment, like XPa.
  6.2028+  ;;    In this case we need to find types or child namespaces in the given
  6.2029+  ;;    namespace that match the given fragment.
  6.2030+  ;;
  6.2031+  ;; 2. p1 is "this" and p2 is a fragment of a name of a class field/prop/method.
  6.2032+  ;;    In this case, complete on the members of the enclosing class.
  6.2033+  ;;
  6.2034+  ;; 3. p1 is the name of a local variable, and p2 is empty or a fragment.
  6.2035+  ;;    In this case, complete with a field, prop, or method on that variable.
  6.2036+  ;;    Must know or learn the type of the variable in that case.
  6.2037+  ;;
  6.2038+  ;; 4. p1 is nil, and p2 is the partial name of a local variable.
  6.2039+  ;;    In this case, complete with the name of a local field, prop, or method
  6.2040+  ;;    that matches
  6.2041+  ;;
  6.2042+  ;; 5. p1 is the name of a type, like System.Console, and p2 is something.
  6.2043+  ;;    In this case, complete with static field, prop, and methods on
  6.2044+  ;;    that type.
  6.2045+  ;;
  6.2046+  ;; 6. p1 is the name of a primitive type, like byte or int.
  6.2047+  ;;    In this case, replace it with the expanded type, and complete as
  6.2048+  ;;    in case 5.
  6.2049+  ;;
  6.2050+  ;; 7. others?
  6.2051+  ;;
  6.2052+  ;; =============================================
  6.2053+  ;;
  6.2054+  ;; There are two sources for completion possibilities.  For known types,
  6.2055+  ;; the possibilities come from introspection, done through the CscompShell.
  6.2056+  ;; So, for System.Xml.XmlDocument, we send a message to the shell and get back
  6.2057+  ;; all the known fields/props/methods of that .NET type.
  6.2058+  ;;
  6.2059+  ;; For unknown types - currently the only "unknown" qualifier is "this." -
  6.2060+  ;; use the parse results from semantic to find fields/props/methods.
  6.2061+  ;;
  6.2062+
  6.2063+  (let* ((p1 (car split))
  6.2064+         (p2 (cadr split))
  6.2065+         (is-primitive    (cscomp-map-primitive-type p1))
  6.2066+         (is-local-var    (cscomp-qualify-local-var p1 opoint))
  6.2067+         (is-instance-var (cscomp-qualify-instance-var p1))
  6.2068+         (is-func         (string-match "($" p2))  ;; open-paren
  6.2069+         (is-ctor         (and                     ;; constructor
  6.2070+                           (null p1)
  6.2071+                           (string-match "^\\([ \t\n\r\f\v]*new[ \t\n\r\f\v]+\\)\\(.+\\)$" p2)))
  6.2072+         p1-flavor
  6.2073+         p1-type
  6.2074+         is-static
  6.2075+         r)
  6.2076+
  6.2077+    (if is-ctor
  6.2078+        ;; reset the beginning marker
  6.2079+        (progn
  6.2080+          (set-marker cscomp-current-beginning
  6.2081+                      (+ cscomp-current-beginning
  6.2082+                         (match-end 1)))
  6.2083+
  6.2084+          ;;(string-match "^\\([ \t]*new[ \t]+\\)\\(.+\\)$" p2)
  6.2085+          ;; rely on most recent string-match context being for is-ctor
  6.2086+          (setq p2 (substring p2 (match-beginning 2)))))
  6.2087+
  6.2088+
  6.2089+
  6.2090+
  6.2091+    ;; figure out what we're completing on.
  6.2092+
  6.2093+    (cond
  6.2094+     (is-primitive
  6.2095+      ;; A static method/prop/field on a byte, int, char, etc.
  6.2096+      (cscomp-log 3 "cscomp-find-completion-for-split: is-primitive")
  6.2097+      (setq p1-flavor "type"
  6.2098+            p1-type is-primitive
  6.2099+            is-static t)) ;; get static methods/props/fields on System.Byte, etc
  6.2100+
  6.2101+     (is-local-var
  6.2102+      ;; method, property, or field on  a local variable.
  6.2103+      (cscomp-log 3 "cscomp-find-completion-for-split: is-local-var")
  6.2104+      (setq p1-flavor "type"
  6.2105+            p1-type (or (cscomp-map-primitive-type (car is-local-var))
  6.2106+                        (car is-local-var))))
  6.2107+
  6.2108+     (is-instance-var
  6.2109+      ;; it's an instance variable.
  6.2110+      (cscomp-log 3 "cscomp-find-completion-for-split: is-instance-var")
  6.2111+      (setq p1-flavor "type"
  6.2112+            p1-type (or (cscomp-map-primitive-type (car is-instance-var))
  6.2113+                        (car is-instance-var))))
  6.2114+
  6.2115+     ((string= "this" p1)
  6.2116+      ;; complete on instance field/prop/method
  6.2117+      (setq p1-flavor "this"))
  6.2118+
  6.2119+
  6.2120+     ((and (null p1) ;; no prefix.
  6.2121+           is-func) ;; open paren is the last char, eg  "new TimeSpan(?"
  6.2122+      (setq r (cscomp-qualify-name (substring p2 0 -1)))
  6.2123+      (cond ((listp r)
  6.2124+             (if (string= (car r) "type")
  6.2125+                 (setq p1-flavor "namespace"
  6.2126+                       p1-type (and
  6.2127+                                (string-match "^\\(.+\\)\\..+$" (cadr r))
  6.2128+                                (match-string 1 (cadr r)))
  6.2129+                       p1 p1-type)
  6.2130+               (setq p1-flavor "local")))
  6.2131+            (t
  6.2132+             (setq p1-flavor "local"))))
  6.2133+
  6.2134+
  6.2135+     (is-ctor
  6.2136+      (setq p1-flavor "mixed")
  6.2137+      (if (null p1)
  6.2138+          (setq p1 p2)))
  6.2139+
  6.2140+
  6.2141+;;     ((and (null p1)   ;; no prefix.
  6.2142+;;        (t
  6.2143+;;         ;; It's not a ctor or static method.
  6.2144+;;         ;; Maybe it's completion on a known typename or namespace.
  6.2145+;;         (setq p1-flavor "mixed"))))
  6.2146+
  6.2147+     (t
  6.2148+      (setq r (cscomp-qualify-name p1))
  6.2149+      (cond ((listp r)
  6.2150+             (progn
  6.2151+               (setq p1-flavor (car r))
  6.2152+
  6.2153+               (if (string= p1-flavor "unknown")
  6.2154+                 ;; assume p1 is an expression.  Try to infer it's type.
  6.2155+                   (let ((inferred-type
  6.2156+                         (cscomp-get-var-type-given-decl (concat "var x = " p1 ";")
  6.2157+                                                          0
  6.2158+                                                          "NoMatter"
  6.2159+                                                          ""
  6.2160+                                                          "")))
  6.2161+                         (if (string= (car inferred-type) "type")
  6.2162+                             (setq p1-type (cadr inferred-type)
  6.2163+                                   p1-flavor "type")))
  6.2164+
  6.2165+
  6.2166+               ;; name qualification was successful
  6.2167+               (setq p1-type p1
  6.2168+                     is-static t)))) ;; if it's a type, we want static f/m/p only
  6.2169+
  6.2170+            (t
  6.2171+             (error "qualify-name returns invalid results.")))))
  6.2172+
  6.2173+
  6.2174+
  6.2175+    (cscomp-log 2 "cscomp-find-completion-for-split: B: p1(%s,%s) p2(%s) flav(%s)"
  6.2176+              p1 (if p1 p1-type "--")  (prin1-to-string p2) p1-flavor)
  6.2177+
  6.2178+
  6.2179+    ;; now collect completion options depending on the "flavor" of p1:
  6.2180+    ;; type == completing on m/f/p for a type, possibly with a fragment.
  6.2181+    ;;         p1 holds the typename from the buffer, could be partially qualified.
  6.2182+    ;;         p1-type holds the fully qualified type name. p2 holds the fragment.
  6.2183+    ;; namespace == completing on a  namespace.  The result can be a child
  6.2184+    ;;         namespace or a type within a namespace.
  6.2185+    ;; this == completing on a m/f/p of the local instance
  6.2186+    ;; local == completing on a m/f/p of local variables or method args
  6.2187+    ;; mixed == could be either a typename or a namespace name. This is
  6.2188+    ;;         the case when p1 is partial, and there is no dot.
  6.2189+
  6.2190+
  6.2191+    (cond
  6.2192+
  6.2193+     ((string= p1-flavor "type")
  6.2194+      (let* ((type-info (cscomp-get-typeinfo p1-type))
  6.2195+            (full-list (cscomp-build-clist-for-type type-info)))
  6.2196+      (cond
  6.2197+
  6.2198+       (is-func ;; it's a specific function on a type. Get the list of overloads.
  6.2199+          (setq cscomp-current-list
  6.2200+                (cscomp-find-all-type-completions (substring p2 0 -1) full-list is-static))
  6.2201+          (cscomp-log 3 "cscomp-find-completion-for-split: [%s]"
  6.2202+                    (prin1-to-string cscomp-current-list)))
  6.2203+       (t ;; could be anything: method, prop, field. Build the list.
  6.2204+          (setq cscomp-current-list
  6.2205+                (cscomp-find-all-type-completions p2 full-list is-static))
  6.2206+
  6.2207+          (cscomp-log 3 "cscomp-find-completion-for-split: [%s]"
  6.2208+                    (prin1-to-string cscomp-current-list))))))
  6.2209+
  6.2210+
  6.2211+     ((string= p1-flavor "namespace")
  6.2212+      (cscomp-log 2 "cscomp-find-completion-for-split, is-func(%s) bot(%d)"
  6.2213+                is-func beginning-of-token1)
  6.2214+      (cond
  6.2215+       (is-func ;; it's a function on a type - see if a constructor
  6.2216+        (cond
  6.2217+         ((save-excursion
  6.2218+            (goto-char beginning-of-token1)
  6.2219+            (re-search-backward "\\<new[ \t\n\f\v]+" nil t))
  6.2220+          ;; it's a constructor
  6.2221+          (let* ((type-name (concat p1 "." (substring p2 0 -1)))
  6.2222+                 (ctor-info (cscomp-get-type-ctors type-name))
  6.2223+                 (full-list (cscomp-build-clist-for-ctors ctor-info)))
  6.2224+
  6.2225+            ;; present all constructors
  6.2226+            (setq cscomp-current-list full-list)))
  6.2227+
  6.2228+         (t
  6.2229+          ;; not a constructor.  Must be some other function.
  6.2230+          (error "completion on static functions is not (yet?) supported."))))
  6.2231+
  6.2232+       (t ;; complete on a type name, or child namespace
  6.2233+        (let* ((type-list (cscomp-get-completions-for-namespace p1))
  6.2234+               (full-list (cscomp-build-clist-for-ns type-list)))
  6.2235+
  6.2236+          (setq cscomp-current-list
  6.2237+                (cscomp-find-all-ns-completions p2 full-list))
  6.2238+          (cscomp-log 3 "cscomp-find-completion-for-split: [%s]"
  6.2239+                    (prin1-to-string cscomp-current-list))))))
  6.2240+
  6.2241+
  6.2242+     ((string= p1-flavor "local")
  6.2243+      (let ((instance-vars (cscomp-matching-instance-vars p2))
  6.2244+            (locals (cscomp-matching-local-vars p2)))
  6.2245+        (setq cscomp-current-list
  6.2246+                  (nconc instance-vars locals))))
  6.2247+
  6.2248+     ((string= p1-flavor "this")
  6.2249+        (setq cscomp-current-list
  6.2250+              (cscomp-matching-instance-members p2)))
  6.2251+
  6.2252+
  6.2253+     ((string= p1-flavor "mixed")
  6.2254+      (setq r (cscomp-get-matches p2))
  6.2255+      (if (listp r)
  6.2256+          (setq cscomp-current-list
  6.2257+                (mapcar '(lambda (listitem)
  6.2258+                           (list
  6.2259+                            ;; the thing to insert
  6.2260+                            (if (and p1 (string-match (concat "^" p1)
  6.2261+                                                      (cadr listitem)))
  6.2262+                                (cadr listitem)
  6.2263+                              (string-match (concat "\\.\\(" p2 ".*\\)") (cadr listitem))
  6.2264+                              (match-string 1 (cadr listitem)))
  6.2265+
  6.2266+                            ;; the description that will be visible in the menu
  6.2267+                            (concat (cadr listitem) " | (" (car listitem) ")")
  6.2268+                            ))
  6.2269+                        r))
  6.2270+        (error "Cannot complete.")))
  6.2271+
  6.2272+     (t
  6.2273+      (cscomp-log 1 "cscomp-find-completion-for-split, unknown flavor (%s)"
  6.2274+                p1-flavor)
  6.2275+      (error "Cannot complete.")))))
  6.2276+
  6.2277+
  6.2278+
  6.2279+
  6.2280+;; (defun cscomp-string-starts-with (s arg)
  6.2281+;;   "returns t if string S starts with ARG. Else nil."
  6.2282+;;   (eq 0 (string-match arg s)))
  6.2283+
  6.2284+
  6.2285+
  6.2286+(defun cscomp-yasnippet-for-arglist (method-name arglist)
  6.2287+  "Produce a snippet that's usable with ya-snippet, for the method
  6.2288+selected from the completion popup menu. The arguments are strings:
  6.2289+METHOD-NAME is the name of the method, and ARGLIST is a description
  6.2290+of the argument list for the selected method.
  6.2291+
  6.2292+The return value is a list, which, if selected from the menu, will be
  6.2293+eval'd. The first element in the list is the literal, yas/expand-snippet,
  6.2294+and subsequent elements in the return value list are simply arguments
  6.2295+to that function.
  6.2296+
  6.2297+"
  6.2298+  (let ((template "(") (str-ix 1) (arg-ix 1)
  6.2299+        (next-char (char-after))
  6.2300+        need-delete)
  6.2301+
  6.2302+    ;; Build the template for yasnippet. Each replaceable
  6.2303+    ;; param is identified with ${N:foo} where N is 1,2,3...
  6.2304+    ;; and foo is the placeholder shown in the buffer, which
  6.2305+    ;; is then "typed over" by the user.
  6.2306+    ;;
  6.2307+    ;; In this case, the placeholder contains the type and the
  6.2308+    ;; name of the argument, from the reflection results.
  6.2309+    ;;
  6.2310+    (while (string-match "\\([^ ]+\\) \\([^,)]+\\)\\([,)]\\)"
  6.2311+                         arglist str-ix)
  6.2312+      (setq template (concat template "${"
  6.2313+                             (number-to-string arg-ix)
  6.2314+                             ":"
  6.2315+                             ;; type of the arg
  6.2316+                             (substring arglist
  6.2317+                                        (match-beginning 1)
  6.2318+                                        (match-end 1))
  6.2319+                             " "
  6.2320+                             ;; name of the arg
  6.2321+                             (substring arglist
  6.2322+                                        (match-beginning 2)
  6.2323+                                        (match-end 2))
  6.2324+                             "}"
  6.2325+
  6.2326+                             ;; the following comma or closing paren
  6.2327+                             (if (string= (substring arglist
  6.2328+                                        (match-beginning 3)
  6.2329+                                        (match-end 3))
  6.2330+                                          ")")
  6.2331+                                 ;; If a close-paren is in the buffer,
  6.2332+                                 ;; cscomp will delete it, before inserting
  6.2333+                                 ;; the snippet.
  6.2334+                                 (progn
  6.2335+                                   ;; to delete the existing close paren
  6.2336+                                   (setq need-delete (eq next-char 41))
  6.2337+                                   ")")
  6.2338+                               ", "))
  6.2339+
  6.2340+            str-ix (match-end 0)
  6.2341+            arg-ix (1+ arg-ix)))
  6.2342+
  6.2343+    (if (eq (length template) 1)
  6.2344+        (setq template "()"))
  6.2345+
  6.2346+    ;; Upon selection of this item from the menu, emacs will
  6.2347+    ;; call yas/expand-snippet. If necessary, emacs will
  6.2348+    ;; delete a char just before doing so.
  6.2349+    (if need-delete
  6.2350+        (list 'progn
  6.2351+          (list 'delete-char '1)
  6.2352+          (list 'yas/expand-snippet '(point) '(point)
  6.2353+                (concat method-name template)))
  6.2354+      (list 'yas/expand-snippet '(point) '(point)
  6.2355+            (concat method-name template)))))
  6.2356+
  6.2357+
  6.2358+
  6.2359+
  6.2360+(defun cscomp-get-menu-item-for-clist-item (clist-item)
  6.2361+  "Produce a menu item for the item on the completion list.
  6.2362+
  6.2363+The incoming CLIST-ITEM is either a (NAME DESCRIP) pair, or
  6.2364+a simple NAME.
  6.2365+
  6.2366+The return value is a menu item - a thing suitable for use within
  6.2367+a popup menu.  It is a 2-member cons cell, the first member is a
  6.2368+string to be displayed, the second is the value returned when
  6.2369+that menu item is selected.
  6.2370+
  6.2371+This value is returned to logic in
  6.2372+`cscomp-popup-completion-menu', and can be anything.  That
  6.2373+fn follows a convention that if the return value is a string, the
  6.2374+string is inserted. If the return value is a list, as with
  6.2375+ya-snippet, the list is eval'd and the result is inserted.
  6.2376+
  6.2377+This fn simply transforms the simple (NAME DESCRIP) pair into
  6.2378+potentially something more interesting.
  6.2379+
  6.2380+"
  6.2381+  (if (consp clist-item)
  6.2382+      (let ((meth-or-prop-name (car clist-item))
  6.2383+            (descrip (cscomp-fix-generics-in-descrip-line (cadr clist-item))))
  6.2384+
  6.2385+        (cond
  6.2386+
  6.2387+         ((string-match "(\\(Method\\|Constructor\\))[^(]+\\(([^)]*)\\)" descrip)
  6.2388+          ;; It's a method or constructor. The value returned when this
  6.2389+          ;; menu item is selected is a cons cell that will be eval'd.
  6.2390+          ;; The cons is a call to yas/expand-snippet that will insert a
  6.2391+          ;; template for the (possibly empty) arglist of the selected
  6.2392+          ;; method or constructor.
  6.2393+          (let ((arglist (substring descrip
  6.2394+                                    (match-beginning 2)
  6.2395+                                    (match-end 2)))
  6.2396+                ;; for ctor, insert the short name.
  6.2397+                (name-to-insert (if (string= (substring descrip
  6.2398+                                                        (match-beginning 1)
  6.2399+                                                        (match-end 1))
  6.2400+                                             "Constructor")
  6.2401+                                    (if (string-match ".+\\." meth-or-prop-name)
  6.2402+                                        (substring meth-or-prop-name
  6.2403+                                                        (match-end 0))
  6.2404+                                      meth-or-prop-name)
  6.2405+                                  meth-or-prop-name)))
  6.2406+
  6.2407+            (cons (concat meth-or-prop-name " | " descrip)
  6.2408+                  (if (fboundp 'yas/expand-snippet)
  6.2409+                      (cscomp-yasnippet-for-arglist name-to-insert arglist)
  6.2410+                    (concat name-to-insert arglist)))))
  6.2411+
  6.2412+         (t
  6.2413+          ;; The completion is not a method - just
  6.2414+          ;; insert the name of the field/prop as a string.
  6.2415+          (cons (concat meth-or-prop-name " | " descrip)
  6.2416+                meth-or-prop-name))))
  6.2417+
  6.2418+    (cons clist-item clist-item)))
  6.2419+
  6.2420+
  6.2421+
  6.2422+(defun cscomp-popup-completion-menu (title)
  6.2423+  "Popup a completion menu for the object at point.  The popup
  6.2424+menu displays all of the possible completions for the object it
  6.2425+was invoked on.
  6.2426+
  6.2427+TITLE is the title presented.  The contents of the menu are provided
  6.2428+in `cscomp-current-list' .
  6.2429+
  6.2430+"
  6.2431+
  6.2432+  ;; cscomp-current-list holds the completion list.
  6.2433+  ;;
  6.2434+  ;; For a type, the clist gets methods, properties and fields.
  6.2435+  ;; Each element in the list is a list, (NAME DESCRIP), where NAME
  6.2436+  ;; is the name of the method/prop/field, and DESCRIP is a string
  6.2437+  ;; description.
  6.2438+  ;;
  6.2439+  ;; For a namespace, the clist is a list of strings.
  6.2440+  ;;
  6.2441+  ;; In each case we want to sort the list alphabetically.
  6.2442+  ;;
  6.2443+
  6.2444+  (let* ((menu-map (cons "ignored"
  6.2445+                         (mapcar 'cscomp-get-menu-item-for-clist-item
  6.2446+                                 cscomp-current-list)))
  6.2447+         (menu-result (cscomp-popup-menu
  6.2448+                       (list (or title "Completions...") menu-map))))
  6.2449+
  6.2450+    (cscomp-log 1 "menu-result:  %s" (prin1-to-string menu-result))
  6.2451+
  6.2452+    ;; now, handle the selection
  6.2453+    (cond
  6.2454+
  6.2455+     ((consp menu-result)
  6.2456+      (delete-region cscomp-current-beginning cscomp-current-end)
  6.2457+      (eval menu-result) ;; maybe a snippet expansion
  6.2458+      "")
  6.2459+
  6.2460+     ((numberp menu-result) (number-to-string menu-result))
  6.2461+
  6.2462+     ((null menu-result) "")
  6.2463+
  6.2464+     (t menu-result)))) ;; a simple string
  6.2465+
  6.2466+
  6.2467+
  6.2468+
  6.2469+
  6.2470+
  6.2471+;; To do thie yasnippet thing for methods/params:
  6.2472+;;
  6.2473+;; (defun dox ()
  6.2474+;;   "expand a template"
  6.2475+;;   (interactive)
  6.2476+;;   (let ((template
  6.2477+;;    "this is ${1:index} the expanded template ${2:foo}"
  6.2478+;;    ))
  6.2479+;;   (yas/expand-snippet (point) (point) template)))
  6.2480+
  6.2481+
  6.2482+
  6.2483+
  6.2484+(defun cscomp-selected-frame ()
  6.2485+  (if (fboundp 'window-edges)
  6.2486+      (selected-frame)
  6.2487+    (selected-window)))
  6.2488+
  6.2489+(defun cscomp-current-row ()
  6.2490+  "Return current row number in current frame."
  6.2491+  (if (fboundp 'window-edges)
  6.2492+      (+ (car (cdr (window-edges))) (count-lines (window-start) (point)))
  6.2493+    (count-lines (window-start) (point))))
  6.2494+
  6.2495+
  6.2496+(defun cscomp-get-point-pixel-pos ()
  6.2497+  "Return point position in pixels: (x, y)."
  6.2498+  (let ((mouse-pos  (mouse-position))
  6.2499+        (pixel-pos  nil)
  6.2500+        (ret        nil))
  6.2501+    (if (car (cdr mouse-pos))
  6.2502+        (progn
  6.2503+          (set-mouse-position (cscomp-selected-frame) (current-column) (cscomp-current-row))
  6.2504+          (setq pixel-pos (mouse-pixel-position))
  6.2505+          (set-mouse-position (car mouse-pos) (car (cdr mouse-pos)) (cdr (cdr mouse-pos)))
  6.2506+          (setq ret (list (car (cdr pixel-pos)) (cdr (cdr pixel-pos)))))
  6.2507+      (progn
  6.2508+        (setq ret '(0 0))))
  6.2509+    (cscomp-log 3 "mouse pos is %s" ret)
  6.2510+    ret))
  6.2511+
  6.2512+
  6.2513+(defun cscomp-posn-at-point-as-event (&optional position window dx dy)
  6.2514+  "Return pixel position of top left corner of glyph at POSITION,
  6.2515+relative to top left corner of WINDOW, as a mouse-1 click
  6.2516+event (identical to the event that would be triggered by clicking
  6.2517+mouse button 1 at the top left corner of the glyph).
  6.2518+
  6.2519+POSITION and WINDOW default to the position of point in the
  6.2520+selected window.
  6.2521+
  6.2522+DX and DY specify optional offsets from the top left of the glyph."
  6.2523+  (unless window (setq window (selected-window)))
  6.2524+  (unless position (setq position (window-point window)))
  6.2525+  (unless dx (setq dx 0))
  6.2526+  (unless dy (setq dy 0))
  6.2527+
  6.2528+  (let* ((pos (posn-at-point position window))
  6.2529+         (x-y (posn-x-y pos))
  6.2530+         (edges (window-inside-pixel-edges window))
  6.2531+         (win-x-y (window-pixel-edges window)))
  6.2532+    ;; adjust for window edges
  6.2533+    (setcar (nthcdr 2 pos)
  6.2534+            (cons (+ (car x-y) (car  edges) (- (car win-x-y))  dx)
  6.2535+                  (+ (cdr x-y) (cadr edges) (- (cadr win-x-y)) dy)))
  6.2536+    (list 'mouse-1 pos)))
  6.2537+
  6.2538+
  6.2539+(defun cscomp-popup-menu (menu-data)
  6.2540+  "Pop up the completion menu at point, using the data MENU-DATA.
  6.2541+MENU-DATA is a list of error and warning messages returned by
  6.2542+`cscomp-make-err-menu-data'."
  6.2543+  (if (featurep 'xemacs)
  6.2544+      (let* ((pos         (cscomp-get-point-pixel-pos))
  6.2545+             (x-pos       (nth 0 pos))
  6.2546+             (y-pos       (nth 1 pos))
  6.2547+             (fake-event-props  '(button 1 x 1 y 1)))
  6.2548+        (setq fake-event-props (plist-put fake-event-props 'x x-pos))
  6.2549+        (setq fake-event-props (plist-put fake-event-props 'y y-pos))
  6.2550+        (popup-menu (cscomp-make-xemacs-menu menu-data)
  6.2551+                    (make-event 'button-press fake-event-props)))
  6.2552+    (x-popup-menu (if (eval-when-compile (fboundp 'posn-at-point))
  6.2553+                      (cscomp-posn-at-point-as-event nil nil 2 20)
  6.2554+                    (list (cscomp-get-point-pixel-pos) (selected-window)))
  6.2555+                   menu-data)))
  6.2556+
  6.2557+
  6.2558+
  6.2559+
  6.2560+(defun cscomp-cycle-candidates ()
  6.2561+  "Replace the previous completion by the next one in
  6.2562+`cscomp-current-list'. Uses `cscomp-current-list-index'
  6.2563+to track the position in the list, and markers `cscomp-current-end'
  6.2564+and `cscomp-current-beginning' to track the position in the
  6.2565+buffer.
  6.2566+
  6.2567+The elements in `cscomp-current-list' can be either lists, or
  6.2568+atoms. In the case of completing on a namespace (eg, start with System.Co),
  6.2569+the completion list will contain strings. (CodeDom, Console,Collections...).
  6.2570+
  6.2571+If completing on a type or instance, the list elems are 2-element lists -
  6.2572+the car is the thing to insert, and the cadr is a description of the thing.
  6.2573+is it a property, method, field?  what is the return type?   if a method,
  6.2574+then what arguments does it require?  The cadr is used only in the menu,
  6.2575+not in the inserted text.
  6.2576+
  6.2577+On the first entry in this function, the markers record the beginning and
  6.2578+end of the fragment being completed. (eg, Co if completing on System.Co).
  6.2579+On exit, the markers record the beginning and end of what has been inserted.
  6.2580+On subsequent entry, it retains those values. On all entries, this fn
  6.2581+deletes the text between the markers, before inserting the completion.
  6.2582+
  6.2583+"
  6.2584+  (let (elem)
  6.2585+    (setq cscomp-current-list-index (1+ cscomp-current-list-index))
  6.2586+    (cscomp-log 3 "list index: %d" cscomp-current-list-index)
  6.2587+    (if (>= cscomp-current-list-index (length cscomp-current-list))
  6.2588+        (setq cscomp-current-list-index 0)) ;; rollover
  6.2589+    (setq elem (nth cscomp-current-list-index cscomp-current-list))
  6.2590+
  6.2591+    (cscomp-log 3 "complete-cycle-candidates: looking at %s" (prin1-to-string elem))
  6.2592+
  6.2593+    (cond
  6.2594+     ((listp elem)
  6.2595+      (if (car elem)
  6.2596+          (let ((thing-to-insert
  6.2597+                 (car elem))
  6.2598+                ;;(substring (car elem) (length cscomp-current-fragment)))
  6.2599+                )
  6.2600+            (delete-region cscomp-current-beginning cscomp-current-end)
  6.2601+            (insert thing-to-insert)
  6.2602+            (set-marker cscomp-current-end
  6.2603+                        (+ (marker-position
  6.2604+                            cscomp-current-beginning) (length thing-to-insert)))
  6.2605+            ;; display the description of the completioni n the minibuffer
  6.2606+            (message "cscomp: %s" (cadr elem)))
  6.2607+        (cscomp-log 1 (format "No completion at this point!(cycle)"))))
  6.2608+
  6.2609+     ;; elem is an atom
  6.2610+     (t
  6.2611+      (let ((thing-to-insert
  6.2612+             elem)
  6.2613+            ;;(substring elem (length cscomp-current-fragment)))
  6.2614+            )
  6.2615+        (delete-region cscomp-current-beginning cscomp-current-end)
  6.2616+        (insert thing-to-insert)
  6.2617+        (set-marker cscomp-current-end
  6.2618+                    (+ (marker-position cscomp-current-beginning) (length thing-to-insert) ))
  6.2619+        ;; display the description of the completioni n the minibuffer
  6.2620+        (message "cscomp: %s" elem)))
  6.2621+     )))
  6.2622+
  6.2623+
  6.2624+
  6.2625+
  6.2626+(defun cscomp-complete-at-point ()
  6.2627+  "Completes at point.  Performs completion on field, prop or
  6.2628+method names if the thing being completed is a type or instance,
  6.2629+or on namespace members - child namespaces or types - if the
  6.2630+thing being completed is a namespace.
  6.2631+
  6.2632+This function is interactive.
  6.2633+
  6.2634+Invoking this fn multiple times in succession cycles through the
  6.2635+completions.
  6.2636+
  6.2637+On first entry, it finds the completion, by calling out to the
  6.2638+CscompShell by calling `cscomp-find-completion-for-split'.
  6.2639+It then caches the resulting list of completion options into
  6.2640+`cscomp-current-list'.
  6.2641+
  6.2642+On subsequent entry, it uses the cached results. After inserting a
  6.2643+completion, this function displays the signature of a method completion
  6.2644+in the minibuffer.
  6.2645+
  6.2646+This fn starts the Cscompshell if necessary. Hence, you may
  6.2647+experience a slight delay when using this command for the first
  6.2648+time in a session or when completing a field or method of an
  6.2649+object that has many methods and fields.
  6.2650+
  6.2651+See `cscomp-complete-at-point-menu' for an alternative to this command
  6.2652+that lets you select the desired completion from a popup menu.
  6.2653+"
  6.2654+
  6.2655+  (interactive)
  6.2656+
  6.2657+;; This command uses the Cscompshell to run Csharp code that in turn uses
  6.2658+;; .NET reflection to determine the methods, properties, and fields
  6.2659+;; defined by the type of the object at point.
  6.2660+
  6.2661+  (if (and
  6.2662+       cscomp-current-list
  6.2663+       (eq last-command this-command)
  6.2664+       (markerp cscomp-current-beginning)
  6.2665+       (markerp cscomp-current-end)
  6.2666+       (marker-position cscomp-current-beginning)
  6.2667+       (marker-position cscomp-current-end)
  6.2668+       (>= (point) (marker-position cscomp-current-beginning))
  6.2669+       (eq (point) (marker-position cscomp-current-end)))
  6.2670+
  6.2671+      ;; we've got a completion list.  cycle through the items.
  6.2672+      (cscomp-cycle-candidates)
  6.2673+    ;; no completion list available. get one.
  6.2674+    (progn
  6.2675+      (let* ((parse-result (cscomp-parse-csharp-expression-before-point))
  6.2676+             (split (and parse-result (cadr parse-result))))
  6.2677+
  6.2678+        (if (not (null split))
  6.2679+            (progn
  6.2680+              ;; set markers
  6.2681+              (cscomp-log 1 "complete-at-point: reset begin,end to (%d,%d)"
  6.2682+                        (- (point) (length (cadr split)))
  6.2683+                        (point))
  6.2684+
  6.2685+              ;; beginning: right after the dot (if there is one)
  6.2686+              (set-marker cscomp-current-beginning
  6.2687+                          (- (point) (length (cadr split))))
  6.2688+
  6.2689+              (set-marker cscomp-current-end (point))
  6.2690+              (cscomp-find-completion-for-split split (point) (car parse-result))
  6.2691+              (setq cscomp-current-list-index -1)
  6.2692+              (cscomp-cycle-candidates)))))))
  6.2693+
  6.2694+
  6.2695+
  6.2696+
  6.2697+(defun cscomp-complete-at-point-menu ()
  6.2698+  "Pops up a menu with a list of completions for point.  When completing
  6.2699+on a type or instance, the menu items are the field, property and method
  6.2700+names; when completing on a namespace, the menu items are child namespaces
  6.2701+or types.
  6.2702+
  6.2703+When the user makes a  selection from the menu, the selected item is
  6.2704+inserted at point.  In the case of a method with parameters, the inserted
  6.2705+thing is a parameterized snippet, a template that can then be filled in
  6.2706+by the user.
  6.2707+
  6.2708+See `cscomp-complete-at-point' for an alternative to this function that
  6.2709+lets you cycle through the potential completions at point.
  6.2710+
  6.2711+"
  6.2712+  (interactive)
  6.2713+  (let* ((parse-result (cscomp-parse-csharp-expression-before-point))
  6.2714+         (split (and parse-result (cadr parse-result))))
  6.2715+
  6.2716+    ;; Reset the completion list - the thing that is used
  6.2717+    ;; when the "no menu" version of complete-at-pont is used.
  6.2718+    (setq cscomp-current-list nil)
  6.2719+
  6.2720+    (if (not (null split))
  6.2721+        (progn
  6.2722+          ;; set markers
  6.2723+          (set-marker cscomp-current-beginning (- (point) (length (cadr split))))
  6.2724+          (set-marker cscomp-current-end (point))
  6.2725+
  6.2726+          (cscomp-find-completion-for-split split (point) (car parse-result))
  6.2727+
  6.2728+          (if cscomp-current-list
  6.2729+              (let* ((title  (if (car split)
  6.2730+                                 (concat (car split) "."
  6.2731+                                         (cadr split) "...")
  6.2732+                               (concat (cadr split) "...")))
  6.2733+                     (selection (cscomp-popup-completion-menu title)))
  6.2734+                (if (and selection
  6.2735+                         (not (string= selection "")))
  6.2736+                    (progn
  6.2737+                      (delete-region cscomp-current-beginning cscomp-current-end)
  6.2738+                      (insert selection)
  6.2739+                      )))
  6.2740+            (message "No completion at this point.")))
  6.2741+      (message "No completion at this point."))))
  6.2742+
  6.2743+
  6.2744+
  6.2745+
  6.2746+;; ;; =======================================================
  6.2747+;; ;; Adding a new semantic tag for "namespace".
  6.2748+;; ;;
  6.2749+;; ;; This turned out to be much harder that it should be.
  6.2750+;; ;;
  6.2751+;; ;; Apparently there are special handling for tags of type 'type,
  6.2752+;; ;; So, for now, punt on doing it this way.
  6.2753+;; ;;
  6.2754+;; ;; =======================================================
  6.2755+;; ;;
  6.2756+;; (defsubst semantic-tag-new-namespace (name members &rest attributes)
  6.2757+;;   "Create a semantic tag of class 'namespace.
  6.2758+;; NAME is the name of this namespace.
  6.2759+;; MEMBERS is a list of strings or semantic tags representing the
  6.2760+;; elements that are contained within the namespace.
  6.2761+;; ATTRIBUTES is a list of additional attributes belonging to this tag."
  6.2762+;;   (apply 'semantic-tag name 'namespace
  6.2763+;;          :members members
  6.2764+;;          attributes))
  6.2765+;;
  6.2766+;;
  6.2767+;;
  6.2768+;; ;; We want this:
  6.2769+;; ;;
  6.2770+;; ;; (defun semantic-tag-components-default (tag)
  6.2771+;; ;;   "Return a list of components for TAG.
  6.2772+;; ;; Perform the described task in `semantic-tag-components'."
  6.2773+;; ;;   (cond ((semantic-tag-of-class-p tag 'type)
  6.2774+;; ;;          (semantic-tag-type-members tag))
  6.2775+;; ;;         ((semantic-tag-of-class-p tag 'namespace)
  6.2776+;; ;;          (semantic-tag-type-members tag))
  6.2777+;; ;;         ((semantic-tag-of-class-p tag 'function)
  6.2778+;; ;;          (semantic-tag-function-arguments tag))
  6.2779+;; ;;         (t nil)))
  6.2780+;;
  6.2781+;; ;; we'll settle for this:
  6.2782+;;
  6.2783+;; (defadvice semantic-tag-components-default (after
  6.2784+;;                                             cscomp-advice-1
  6.2785+;;                                             (tag)
  6.2786+;;                                             activate compile)
  6.2787+;;
  6.2788+;;   (cond ((semantic-tag-of-class-p tag 'namespace)
  6.2789+;;          (semantic-tag-type-members tag))
  6.2790+;;         (t ad-return-value)))
  6.2791+
  6.2792+
  6.2793+
  6.2794+(provide 'csharp-completion)
  6.2795+
  6.2796+
  6.2797+;;; end of csharp-completion.el
     7.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2+++ b/csharp-mode/csharp-mode.el	Wed Nov 10 15:19:03 2010 +0200
     7.3@@ -0,0 +1,2766 @@
     7.4+;;; csharp-mode.el --- C# mode derived mode
     7.5+
     7.6+;; Author     : Dylan R. E. Moonfire (original)
     7.7+;; Maintainer : Dino Chiesa <dpchiesa@hotmail.com>
     7.8+;; Created    : Feburary 2005
     7.9+;; Modified   : April 2010
    7.10+;; Version    : 0.7.6
    7.11+;; Keywords   : c# languages oop mode
    7.12+;; X-URL      : http://code.google.com/p/csharpmode/
    7.13+;; Last-saved : <2010-May-24 21:53:58>
    7.14+
    7.15+;;
    7.16+;; This program is free software; you can redistribute it and/or modify
    7.17+;; it under the terms of the GNU General Public License as published by
    7.18+;; the Free Software Foundation; either version 2 of the License, or
    7.19+;; (at your option) any later version.
    7.20+;;
    7.21+;; This program is distributed in the hope that it will be useful,
    7.22+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.23+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.24+;; GNU General Public License for more details.
    7.25+;;
    7.26+;; You should have received a copy of the GNU General Public License
    7.27+;; along with this program; see the file COPYING.  If not, write to
    7.28+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    7.29+;; Boston, MA 02111-1307, USA.
    7.30+
    7.31+;;; Commentary:
    7.32+;;
    7.33+;;    This is a separate mode to implement the C# constructs and
    7.34+;;    font-locking. It is based on the java-mode example from cc-mode.
    7.35+;;
    7.36+;;    csharp-mode requires CC Mode 5.30 or later.  It works with
    7.37+;;    cc-mode 5.31.3, which is current at this time.
    7.38+;;
    7.39+;; Features:
    7.40+;;
    7.41+;;   - font-lock and indent of C# syntax including:
    7.42+;;       all c# keywords and major syntax
    7.43+;;       attributes that decorate methods, classes, fields, properties
    7.44+;;       enum types
    7.45+;;       #if/#endif  #region/#endregion
    7.46+;;       instance initializers
    7.47+;;       anonymous functions and methods
    7.48+;;       verbatim literal strings (those that begin with @)
    7.49+;;       generics
    7.50+;;
    7.51+;;   - automagic code-doc generation when you type three slashes.
    7.52+;;
    7.53+;;   - intelligent inserttion of matched pairs of curly braces.
    7.54+;;
    7.55+;;   - sets the compiler regex for next-error, for csc.exe output.
    7.56+;;
    7.57+;;
    7.58+
    7.59+;;; To use:
    7.60+;;
    7.61+;; put this in your .emacs:
    7.62+;;
    7.63+;;   (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t)
    7.64+;;
    7.65+;; or:
    7.66+;;
    7.67+;;   (require 'csharp-mode)
    7.68+;;
    7.69+;;
    7.70+;; AND:
    7.71+;;
    7.72+;;   (setq auto-mode-alist
    7.73+;;      (append '(("\\.cs$" . csharp-mode)) auto-mode-alist))
    7.74+;;   (defun my-csharp-mode-fn ()
    7.75+;;      "function that runs when csharp-mode is initialized for a buffer."
    7.76+;;      ...insert your code here...
    7.77+;;      ...most commonly, your custom key bindings ...
    7.78+;;   )
    7.79+;;   (add-hook  'csharp-mode-hook 'my-csharp-mode-fn t)
    7.80+;;
    7.81+;;
    7.82+
    7.83+;;; Known Bugs:
    7.84+;;
    7.85+;;   Leading identifiers are no longer being fontified, for some reason.
    7.86+;;   See matchers-before.
    7.87+;;
    7.88+;;   Method names with a preceding attribute are not fontified.
    7.89+;;
    7.90+;;   The symbol followng #if is not fontified.  It should be treated like
    7.91+;;   define and get font-lock-variable-name-face .
    7.92+;;
    7.93+;;   This code doesn't seem to work when you compile it, then
    7.94+;;   load/require in the emacs file. You will get an error (error
    7.95+;;   "`c-lang-defconst' must be used in a file") which happens because
    7.96+;;   cc-mode doesn't think it is in a buffer while loading directly
    7.97+;;   from the init. However, if you call it based on a file extension,
    7.98+;;   it works properly. Interestingly enough, this doesn't happen if
    7.99+;;   you don't byte-compile cc-mode.
   7.100+;;
   7.101+;;
   7.102+;;
   7.103+;;  Todo:
   7.104+;;
   7.105+;;    Get csharp-mode.el accepted as part of the emacs standard distribution.
   7.106+;;    Must contact monnier at iro.umontreal.ca to make this happen.
   7.107+;;
   7.108+;;
   7.109+;;
   7.110+;;  Acknowledgements:
   7.111+;;
   7.112+;;    Thanks to Alan Mackenzie and Stefan Monnier for answering questions
   7.113+;;    and making suggestions. And to Trey Jackson for sharing his
   7.114+;;    knowledge of emacs lisp.
   7.115+;;
   7.116+;;
   7.117+
   7.118+;;; Versions:
   7.119+;;
   7.120+;;    0.1.0 - Initial release.
   7.121+;;    0.2.0 - Fixed the identification on the "enum" keyword.
   7.122+;;          - Fixed the font-lock on the "base" keyword
   7.123+;;    0.3.0 - Added a regex to fontify attributes. It isn't the
   7.124+;;            the best method, but it handles single-like attributes
   7.125+;;            well.
   7.126+;;          - Got "super" not to fontify as a keyword.
   7.127+;;          - Got extending classes and interfaces to fontify as something.
   7.128+;;    0.4.0 - Removed the attribute matching because it broke more than
   7.129+;;            it fixed.
   7.130+;;          - Corrected a bug with namespace not being properly identified
   7.131+;;            and treating the class level as an inner object, which screwed
   7.132+;;            up formatting.
   7.133+;;          - Added "partial" to the keywords.
   7.134+;;    0.5.0 - Found bugs with compiled cc-mode and loading from init files.
   7.135+;;          - Updated the eval-when-compile to code to let the mode be
   7.136+;;            compiled.
   7.137+;;    0.6.0 - Added the c-filter-ops patch for 5.31.1 which made that
   7.138+;;            function in cc-langs.el unavailable.
   7.139+;;          - Added a csharp-lineup-region for indention #region and
   7.140+;;            #endregion block differently.
   7.141+;;    0.7.0 - Added autoload so update-directory-autoloads works
   7.142+;;            (Thank you, Nikolaj Schumacher)
   7.143+;;          - Fontified the entire #region and #endregion lines.
   7.144+;;          - Initial work to get get, set, add, remove font-locked.
   7.145+;;    0.7.1 - Added option to indent #if/endif with code
   7.146+;;          - Fixed c-opt-cpp-prefix defn (it must not include the BOL
   7.147+;;            char (^).
   7.148+;;          - proper fontification and indent of classes that inherit
   7.149+;;            (previously the colon was confusing the parser)
   7.150+;;          - reclassified namespace as a block beginner
   7.151+;;          - removed $ as a legal symbol char - not legal in C#.
   7.152+;;          - added struct to c-class-decl-kwds so indent is correct
   7.153+;;            within a struct.
   7.154+;;    0.7.2 - Added automatic codedoc insertion.
   7.155+;;    0.7.3 - Instance initializers (new Type { ... } ) and
   7.156+;;            (new Type() { ...} ) are now indented properly.
   7.157+;;          - proper fontification and indent of enums as brace-list-*,
   7.158+;;            including special treatment for enums that explicitly
   7.159+;;            inherit from an int type. Previously the colon was
   7.160+;;            confusing the parser.
   7.161+;;          - proper fontification of verbatim literal strings,
   7.162+;;            including those that end in slash. This edge case was not
   7.163+;;            handled at all before; it is now handled correctly.
   7.164+;;          - code cleanup and organization; removed the linefeed.
   7.165+;;          - intelligent curly-brace insertion
   7.166+;;    0.7.4 - added a C# style
   7.167+;;          - using is now a keyword and gets fontified correctly
   7.168+;;          - fixed a bug that had crept into the codedoc insertion
   7.169+;;    0.7.5 - now fontify namespaces in the using statements. This is
   7.170+;;            done in the csharp value for c-basic-matchers-before .
   7.171+;;          - also fontify the name following namespace decl.
   7.172+;;            This is done in the csharp value for c-basic-matchers-after .
   7.173+;;          - turn on recognition of generic types. They are now
   7.174+;;            fontified correctly.
   7.175+;;          - <> are now treated as syntactic parens and can be jumped
   7.176+;;            over with c-forward-sexp.
   7.177+;;          - Constructors are now fontified.
   7.178+;;          - Field/Prop names inside object initializers are now fontified.
   7.179+;;
   7.180+
   7.181+
   7.182+;;
   7.183+
   7.184+
   7.185+(require 'cc-mode)
   7.186+
   7.187+(message  (concat "Loading " load-file-name))
   7.188+
   7.189+
   7.190+;; ==================================================================
   7.191+;; c# upfront stuff
   7.192+;; ==================================================================
   7.193+
   7.194+;; This is a copy of the function in cc-mode which is used to handle
   7.195+;; the eval-when-compile which is needed during other times.
   7.196+(defun c-filter-ops (ops opgroup-filter op-filter &optional xlate)
   7.197+  ;; See cc-langs.el, a direct copy.
   7.198+  (unless (listp (car-safe ops))
   7.199+    (setq ops (list ops)))
   7.200+  (cond ((eq opgroup-filter t)
   7.201+         (setq opgroup-filter (lambda (opgroup) t)))
   7.202+        ((not (functionp opgroup-filter))
   7.203+         (setq opgroup-filter `(lambda (opgroup)
   7.204+                                 (memq opgroup ',opgroup-filter)))))
   7.205+  (cond ((eq op-filter t)
   7.206+         (setq op-filter (lambda (op) t)))
   7.207+        ((stringp op-filter)
   7.208+         (setq op-filter `(lambda (op)
   7.209+                            (string-match ,op-filter op)))))
   7.210+  (unless xlate
   7.211+    (setq xlate 'identity))
   7.212+  (c-with-syntax-table (c-lang-const c-mode-syntax-table)
   7.213+    (delete-duplicates
   7.214+     (mapcan (lambda (opgroup)
   7.215+               (when (if (symbolp (car opgroup))
   7.216+                         (when (funcall opgroup-filter (car opgroup))
   7.217+                           (setq opgroup (cdr opgroup))
   7.218+                           t)
   7.219+                       t)
   7.220+                 (mapcan (lambda (op)
   7.221+                           (when (funcall op-filter op)
   7.222+                             (let ((res (funcall xlate op)))
   7.223+                               (if (listp res) res (list res)))))
   7.224+                         opgroup)))
   7.225+             ops)
   7.226+     :test 'equal)))
   7.227+
   7.228+
   7.229+
   7.230+;; These are only required at compile time to get the sources for the
   7.231+;; language constants.  (The cc-fonts require and the font-lock
   7.232+;; related constants could additionally be put inside an
   7.233+;; (eval-after-load "font-lock" ...) but then some trickery is
   7.234+;; necessary to get them compiled.)
   7.235+(eval-when-compile
   7.236+  (let ((load-path
   7.237+         (if (and (boundp 'byte-compile-dest-file)
   7.238+                  (stringp byte-compile-dest-file))
   7.239+             (cons (file-name-directory byte-compile-dest-file) load-path)
   7.240+           load-path)))
   7.241+    (load "cc-mode" nil t)
   7.242+    (load "cc-fonts" nil t)
   7.243+    (load "cc-langs" nil t)))
   7.244+
   7.245+(eval-and-compile
   7.246+  ;; Make our mode known to the language constant system.  Use Java
   7.247+  ;; mode as the fallback for the constants we don't change here.
   7.248+  ;; This needs to be done also at compile time since the language
   7.249+  ;; constants are evaluated then.
   7.250+  (c-add-language 'csharp-mode 'java-mode))
   7.251+
   7.252+;; ==================================================================
   7.253+;; end of c# upfront stuff
   7.254+;; ==================================================================
   7.255+
   7.256+
   7.257+
   7.258+
   7.259+
   7.260+;; ==================================================================
   7.261+;; csharp-mode utility and feature defuns
   7.262+;; ==================================================================
   7.263+
   7.264+
   7.265+(defun csharp-at-vsemi-p (&optional pos)
   7.266+  "Determines if there is a virtual semicolon at POS or point.
   7.267+This is the C# version of the function.
   7.268+
   7.269+A vsemi is a cc-mode concept implying end-of-statement, without
   7.270+a semicolon or close-brace. This happens in 2 cases in C#:
   7.271+
   7.272+ - after an attribute that decorates a class, method, field, or
   7.273+   property.
   7.274+
   7.275+ - after an ASPNET directive, that appears in a aspx/ashx/ascx file
   7.276+
   7.277+An example of the former is  [WebMethod] or [XmlElement].
   7.278+An example of the latter is something like this:
   7.279+
   7.280+    <%@ WebHandler Language=\"C#\" Class=\"Handler\" %>
   7.281+
   7.282+Providing this function allows the indenting in csharp-mode
   7.283+to work properly with code that includes attributes and ASPNET
   7.284+directives.
   7.285+
   7.286+Returns t if at a position where a virtual-semicolon is.
   7.287+Otherwise nil.
   7.288+"
   7.289+
   7.290+  (save-excursion
   7.291+    (let ((pos-or-point (progn (if pos (goto-char pos)) (point))))
   7.292+
   7.293+      (cond
   7.294+
   7.295+       ;; put a vsemi after an ASPNET directive, like
   7.296+       ;; <%@ WebHandler Language="C#" Class="Handler" %>
   7.297+       ((looking-back (concat csharp-aspnet-directive-re "$") nil t)
   7.298+        t)
   7.299+
   7.300+       ;; put a vsemi after an attribute, as with
   7.301+       ;;   [XmlElement]
   7.302+       ((c-safe (backward-sexp) t)
   7.303+        (cond
   7.304+           ((re-search-forward
   7.305+             (concat
   7.306+              "\\(\\["
   7.307+              "[ \t\n\r\f\v]*"
   7.308+              "\\("
   7.309+              "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
   7.310+              "[A-Za-z_][[:alnum:]]*"
   7.311+              "\\)"
   7.312+              "[^]]*\\]\\)"
   7.313+              )
   7.314+             (1+ pos-or-point) t)
   7.315+
   7.316+             (c-safe (backward-sexp))
   7.317+             (c-backward-syntactic-ws)
   7.318+             (cond
   7.319+
   7.320+              ((eq (char-before) 93) ;; close sq brace
   7.321+               (csharp-at-vsemi-p (point)))
   7.322+
   7.323+              ((or
   7.324+                (eq (char-before) 59) ;; semicolon
   7.325+                (eq (char-before) 123) ;; open curly
   7.326+                (eq (char-before) 125)) ;; close curly
   7.327+               t)
   7.328+
   7.329+              (t nil)))
   7.330+
   7.331+           (t nil)))
   7.332+
   7.333+        (t nil))
   7.334+      )))
   7.335+
   7.336+
   7.337+
   7.338+
   7.339+(defun csharp-lineup-region (langelem)
   7.340+  "Indent all #region and #endregion blocks inline with code while
   7.341+retaining normal column-zero indention for #if and the other
   7.342+processing blocks.
   7.343+
   7.344+To use this indenting just put the following in your emacs file:
   7.345+   (c-set-offset 'cpp-macro 'csharp-lineup-region)
   7.346+
   7.347+An alternative is to use `csharp-lineup-if-and-region'.
   7.348+"
   7.349+
   7.350+  (save-excursion
   7.351+    (back-to-indentation)
   7.352+    (if (re-search-forward "#\\(end\\)?region" (c-point 'eol) [0]) 0  [0])))
   7.353+
   7.354+
   7.355+
   7.356+(defun csharp-lineup-if-and-region (langelem)
   7.357+
   7.358+"Indent all #region/endregion blocks and #if/endif blocks inline
   7.359+with code while retaining normal column-zero indention for any
   7.360+other processing blocks.
   7.361+
   7.362+To use this indenting just put the following in your emacs file:
   7.363+  (c-set-offset 'cpp-macro 'csharp-lineup-if-and-region)
   7.364+
   7.365+Another option is to use `csharp-lineup-region'.
   7.366+
   7.367+"
   7.368+  (save-excursion
   7.369+    (back-to-indentation)
   7.370+    (if (re-search-forward "#\\(\\(end\\)?\\(if\\|region\\)\\|else\\)" (c-point 'eol) [0]) 0  [0])))
   7.371+
   7.372+
   7.373+
   7.374+
   7.375+
   7.376+(defun csharp-insert-open-brace ()
   7.377+  "Intelligently insert a pair of curly braces. This fn is most
   7.378+    often bound to the open-curly brace, with
   7.379+
   7.380+        (local-set-key (kbd \"{\") 'csharp-insert-open-brace)
   7.381+
   7.382+    The default binding for an open curly brace in cc-modes is often
   7.383+    `c-electric-brace' or `skeleton-pair-insert-maybe'.  The former
   7.384+    can be configured to insert newlines around braces in various
   7.385+    syntactic positions.  The latter inserts a pair of braces and
   7.386+    then does not insert a newline, and does not indent.
   7.387+
   7.388+    This fn provides another option, with some additional
   7.389+    intelligence for csharp-mode.  When you type an open curly, the
   7.390+    appropriate pair of braces appears, with spacing and indent set
   7.391+    in a context-sensitive manner.
   7.392+
   7.393+    Within a string literal, you just get a pair of braces, and
   7.394+    point is set between them. Following an equals sign, you get
   7.395+    a pair of braces, with a semincolon appended. Otherwise, you
   7.396+    get the open brace on a new line, followed by an empty line
   7.397+    and the closing brace on the line following, with point on
   7.398+    the empty line.
   7.399+
   7.400+    There may be another way to get this to happen appropriately just
   7.401+    within emacs, but I could not figure out how to do it.  So I
   7.402+    wrote this alternative.
   7.403+
   7.404+    "
   7.405+  (interactive)
   7.406+  (let
   7.407+      (tpoint
   7.408+       (in-string (string= (csharp-in-literal) "string"))
   7.409+       (preceding3
   7.410+        (save-excursion
   7.411+          (and
   7.412+           (skip-chars-backward " \t")
   7.413+           (> (- (point) 2) (point-min))
   7.414+           (buffer-substring-no-properties (point) (- (point) 3)))))
   7.415+       (one-word-back
   7.416+        (save-excursion
   7.417+          (backward-word 2)
   7.418+          (thing-at-point 'word))))
   7.419+
   7.420+    (cond
   7.421+
   7.422+     ;; Case 1: inside a string literal?
   7.423+     ;; --------------------------------------------
   7.424+     ;; If so, then just insert a pair of braces and put the point
   7.425+     ;; between them.  The most common case is a format string for
   7.426+     ;; String.Format() or Console.WriteLine().
   7.427+     (in-string
   7.428+      (self-insert-command 1)
   7.429+      (insert "}")
   7.430+      (backward-char))
   7.431+
   7.432+     ;; Case 2: the open brace starts an array initializer.
   7.433+     ;; --------------------------------------------
   7.434+     ;; When the last non-space was an equals sign or square brackets,
   7.435+     ;; then it's an initializer.
   7.436+     ((save-excursion
   7.437+        (and (c-safe (backward-sexp) t)
   7.438+             (looking-at "\\(\\w+\\b *=\\|[[]]+\\)")))
   7.439+      (self-insert-command 1)
   7.440+      (insert "  };")
   7.441+      (backward-char 3))
   7.442+
   7.443+     ;; Case 3: the open brace starts an instance initializer
   7.444+     ;; --------------------------------------------
   7.445+     ;; If one-word-back was "new", then it's an object initializer.
   7.446+     ((string= one-word-back "new")
   7.447+      (save-excursion
   7.448+        (message "object initializer")
   7.449+        (setq tpoint (point)) ;; prepare to indent-region later
   7.450+        (newline)
   7.451+        (self-insert-command 1)
   7.452+        (newline-and-indent)
   7.453+        (newline)
   7.454+        (insert "};")
   7.455+        (c-indent-region tpoint (point))
   7.456+        (previous-line)
   7.457+        (indent-according-to-mode)
   7.458+        (end-of-line)
   7.459+        (setq tpoint (point)))
   7.460+      (goto-char tpoint))
   7.461+
   7.462+     ;; Case 4: a lambda initialier.
   7.463+     ;; --------------------------------------------
   7.464+     ;; If the open curly follows =>, then it's a lambda initializer.
   7.465+     ((string= (substring preceding3 -2) "=>")
   7.466+      (message "lambda init")
   7.467+      (self-insert-command 1)
   7.468+      (insert "  }")
   7.469+      (backward-char 2))
   7.470+
   7.471+     ;; else, it's a new scope. (if, while, class, etc)
   7.472+     (t
   7.473+      (save-excursion
   7.474+        (message "new scope")
   7.475+        (set-mark (point)) ;; prepare to indent-region later
   7.476+        ;; check if the prior sexp is on the same line
   7.477+        (if (save-excursion
   7.478+              (let ((curline (line-number-at-pos))
   7.479+                    (aftline (progn
   7.480+                               (if (c-safe (backward-sexp) t)
   7.481+                                   (line-number-at-pos)
   7.482+                                 -1))))
   7.483+                (= curline aftline)))
   7.484+            (newline-and-indent))
   7.485+        (self-insert-command 1)
   7.486+        (c-indent-line-or-region)
   7.487+        (end-of-line)
   7.488+        (newline)
   7.489+        (insert "}")
   7.490+        ;;(c-indent-command) ;; not sure of the difference here
   7.491+        (c-indent-line-or-region)
   7.492+        (previous-line)
   7.493+        (end-of-line)
   7.494+        (newline-and-indent)
   7.495+        ;; point ends up on an empty line, within the braces, properly indented
   7.496+        (setq tpoint (point)))
   7.497+
   7.498+      (goto-char tpoint)))))
   7.499+
   7.500+
   7.501+;; ==================================================================
   7.502+;; end of csharp-mode utility and feature defuns
   7.503+;; ==================================================================
   7.504+
   7.505+
   7.506+
   7.507+
   7.508+
   7.509+
   7.510+;; ==================================================================
   7.511+;; c# values for "language constants" defined in cc-langs.el
   7.512+;; ==================================================================
   7.513+
   7.514+
   7.515+;; Java uses a series of regexes to change the font-lock for class
   7.516+;; references. The problem comes in because Java uses Pascal (leading
   7.517+;; space in names, SomeClass) for class and package names, but
   7.518+;; Camel-casing (initial lowercase, upper case in words,
   7.519+;; i.e. someVariable) for variables. The notation suggested by EMCA for C# is
   7.520+;; to use Pascal notation for everything, except inner variables. So,
   7.521+;; the Java regex and formatting produces very wrong results in C#.
   7.522+;;(error (byte-compile-dest-file))
   7.523+;;(error (c-get-current-file))
   7.524+
   7.525+(defconst csharp-aspnet-directive-re
   7.526+  "<%@.+?%>"
   7.527+  "Regex for matching directive blocks in ASP.NET files (.aspx, .ashx, .ascx)")
   7.528+
   7.529+(defconst csharp-enum-decl-re
   7.530+  (concat
   7.531+   "\\<enum[ \t\n\r\f\v]+"
   7.532+   "\\([[:alpha:]_][[:alnum:]_]*\\)"
   7.533+   "[ \t\n\r\f\v]*"
   7.534+   "\\(:[ \t\n\r\f\v]*"
   7.535+   "\\("
   7.536+   (c-make-keywords-re nil
   7.537+     (list "sbyte" "byte" "short" "ushort" "int" "uint" "long" "ulong"))
   7.538+   "\\)"
   7.539+   "\\)?")
   7.540+  "Regex that captures an enum declaration in C#"
   7.541+  )
   7.542+
   7.543+
   7.544+
   7.545+;; 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+
   7.546+
   7.547+;; vsemi's allow proper indentation of code that includes inline
   7.548+;; attributes and ASPNET directives. These are c#-specific things that
   7.549+;; need custom treatment.
   7.550+(c-lang-defconst c-at-vsemi-p-fn
   7.551+  csharp 'csharp-at-vsemi-p)
   7.552+
   7.553+
   7.554+;; This c-opt-after-id-concat-key is a regexp that matches
   7.555+;; dot.  In other words: "\\(\\.\\)"
   7.556+;; Not sure why this needs to be so complicated.
   7.557+;; This const is now internal (obsolete); need to move to
   7.558+;; c-after-id-concat-ops.  I don't yet understand the meaning
   7.559+;; of that variable, so for now. . .  .
   7.560+(c-lang-defconst c-opt-after-id-concat-key
   7.561+  csharp (if (c-lang-const c-opt-identifier-concat-key)
   7.562+             (c-lang-const c-symbol-start)))
   7.563+
   7.564+
   7.565+
   7.566+;; The matchers elements can be of many forms.  It gets pretty
   7.567+;; complicated.  Do a describe-variable on font-lock-keywords to get a
   7.568+;; description.  (Why on font-lock-keywords? I don't know, but that's
   7.569+;; where you get the help.)
   7.570+;;
   7.571+;; Aside from the provided documentation, the other option of course, is
   7.572+;; to look in the source code as an example for what to do.  The source
   7.573+;; in cc-fonts uses a defun c-make-font-lock-search-function to produce
   7.574+;; most of the matchers.  Called this way:
   7.575+;;
   7.576+;;   (c-make-font-lock-search-function  regexp '(A B c))
   7.577+;;
   7.578+;; The REGEXP is used in re-search-forward, and if there's a match, the
   7.579+;; A B and C are three forms that are called in a weird combination.
   7.580+;;
   7.581+;; Anyway the c-make-font-lock-search-function works for a single regex,
   7.582+;; but more complicated scenarios such as those intended to match and
   7.583+;; fontify object initializers, call for a hand-crafted lambda.
   7.584+;;
   7.585+;; The object initializer is special because, matching on it must
   7.586+;; allow nesting.
   7.587+;;
   7.588+;; In c#, the object initializer block is used directly after a
   7.589+;; constructor, like this:
   7.590+;;
   7.591+;;     new MyType {
   7.592+;;        Prop1 = "foo"
   7.593+;;     }
   7.594+;;
   7.595+;; csharp-mode needs to fontify the properties in the
   7.596+;; initializer block in font-lock-variable-name-face. The key thing is
   7.597+;; to set the text property on the open curly, using type c-type and
   7.598+;; value c-decl-id-start. This apparently allows `parse-partial-sexp' to
   7.599+;; do the right thing, later.
   7.600+;;
   7.601+;; This simple case is easy to handle in a regex, using the basic
   7.602+;; `c-make-font-lock-search-function' form.  But the general syntax for a
   7.603+;; constructor + object initializer in C# is more complex:
   7.604+;;
   7.605+;;     new MyType(..arglist..) {
   7.606+;;        Prop1 = "foo"
   7.607+;;     }
   7.608+;;
   7.609+;; A simple regex match won't satisfy here, because the ..arglist.. can
   7.610+;; be anything, including calls to other constructors, potentially with
   7.611+;; object initializer blocks. This may nest arbitrarily deeply, and the
   7.612+;; regex in emacs doesn't support balanced matching.  Therefore there's
   7.613+;; no way to match on the "outside" pair of parens, to find the relevant
   7.614+;; open curly.  What's necessary is to do the match on "new MyType" then
   7.615+;; skip over the sexp defined by the parens, then set the text property on
   7.616+;; the appropriate open-curly.
   7.617+;;
   7.618+;; To make that happen, it's good to have insight into what the matcher
   7.619+;; really does.  The output of `c-make-font-lock-search-function' before
   7.620+;; byte-compiling, is:
   7.621+;;
   7.622+;; (lambda (limit)
   7.623+;;   (let ((parse-sexp-lookup-properties
   7.624+;;          (cc-eval-when-compile
   7.625+;;            (boundp 'parse-sexp-lookup-properties))))
   7.626+;;     (while (re-search-forward REGEX limit t)
   7.627+;;       (unless
   7.628+;;           (progn
   7.629+;;             (goto-char (match-beginning 0))
   7.630+;;             (c-skip-comments-and-strings limit))
   7.631+;;         (goto-char (match-end 0))
   7.632+;;         (progn
   7.633+;;           B
   7.634+;;           (save-match-data A)
   7.635+;;           C ))))
   7.636+;;   nil)
   7.637+;;
   7.638+;; csharp-mode uses this hand-crafted form of a matcher to handle the
   7.639+;; general case for constructor + object initializer, within
   7.640+;; `c-basic-matchers-after' .
   7.641+;;
   7.642+
   7.643+
   7.644+
   7.645+
   7.646+;; (defun c-make-font-lock-search-function (regexp &rest highlights)
   7.647+;;     ;; This function makes a byte compiled function that works much like
   7.648+;;     ;; a matcher element in `font-lock-keywords'.  It cuts out a little
   7.649+;;     ;; bit of the overhead compared to a real matcher.  The main reason
   7.650+;;     ;; is however to pass the real search limit to the anchored
   7.651+;;     ;; matcher(s), since most (if not all) font-lock implementations
   7.652+;;     ;; arbitrarily limits anchored matchers to the same line, and also
   7.653+;;     ;; to insulate against various other irritating differences between
   7.654+;;     ;; the different (X)Emacs font-lock packages.
   7.655+;;     ;;
   7.656+;;     ;; REGEXP is the matcher, which must be a regexp.  Only matches
   7.657+;;     ;; where the beginning is outside any comment or string literal are
   7.658+;;     ;; significant.
   7.659+;;     ;;
   7.660+;;     ;; HIGHLIGHTS is a list of highlight specs, just like in
   7.661+;;     ;; `font-lock-keywords', with these limitations: The face is always
   7.662+;;     ;; overridden (no big disadvantage, since hits in comments etc are
   7.663+;;     ;; filtered anyway), there is no "laxmatch", and an anchored matcher
   7.664+;;     ;; is always a form which must do all the fontification directly.
   7.665+;;     ;; `limit' is a variable bound to the real limit in the context of
   7.666+;;     ;; the anchored matcher forms.
   7.667+;;     ;;
   7.668+;;     ;; This function does not do any hidden buffer changes, but the
   7.669+;;     ;; generated functions will.  (They are however used in places
   7.670+;;     ;; covered by the font-lock context.)
   7.671+;;
   7.672+;;     ;; Note: Replace `byte-compile' with `eval' to debug the generated
   7.673+;;     ;; lambda easier.
   7.674+;;     (byte-compile
   7.675+;;      `(lambda (limit)
   7.676+;;         (let (;; The font-lock package in Emacs is known to clobber
   7.677+;;               ;; `parse-sexp-lookup-properties' (when it exists).
   7.678+;;               (parse-sexp-lookup-properties
   7.679+;;                (cc-eval-when-compile
   7.680+;;                  (boundp 'parse-sexp-lookup-properties))))
   7.681+;;           (while (re-search-forward ,regexp limit t)
   7.682+;;             (unless (progn
   7.683+;;                       (goto-char (match-beginning 0))
   7.684+;;                       (c-skip-comments-and-strings limit))
   7.685+;;               (goto-char (match-end 0))
   7.686+;;               ,@(mapcar
   7.687+;;                  (lambda (highlight)
   7.688+;;                    (if (integerp (car highlight))
   7.689+;;                        (progn
   7.690+;;                          (unless (eq (nth 2 highlight) t)
   7.691+;;                            (error
   7.692+;;                             "The override flag must currently be t in %s"
   7.693+;;                             highlight))
   7.694+;;                          (when (nth 3 highlight)
   7.695+;;                            (error
   7.696+;;                             "The laxmatch flag may currently not be set in %s"
   7.697+;;                             highlight))
   7.698+;;                          `(save-match-data
   7.699+;;                             (c-put-font-lock-face
   7.700+;;                              (match-beginning ,(car highlight))
   7.701+;;                              (match-end ,(car highlight))
   7.702+;;                              ,(elt highlight 1))))
   7.703+;;                      (when (nth 3 highlight)
   7.704+;;                        (error "Match highlights currently not supported in %s"
   7.705+;;                               highlight))
   7.706+;;                      `(progn
   7.707+;;                         ,(nth 1 highlight)
   7.708+;;                         (save-match-data ,(car highlight))
   7.709+;;                         ,(nth 2 highlight))))
   7.710+;;                  highlights))))
   7.711+;;         nil))
   7.712+;;     )
   7.713+
   7.714+
   7.715+(c-lang-defconst c-basic-matchers-before
   7.716+  csharp `(
   7.717+           ;;;; Font-lock the attributes by searching for the
   7.718+           ;;;; appropriate regex and marking it as TODO.
   7.719+           ;;,`(,(concat "\\(" csharp-attribute-regex "\\)")
   7.720+           ;;   0 font-lock-function-name-face)
   7.721+
   7.722+           ;; Put a warning face on the opener of unclosed strings that
   7.723+           ;; can't span lines.  Later font
   7.724+           ;; lock packages have a `font-lock-syntactic-face-function' for
   7.725+           ;; this, but it doesn't give the control we want since any
   7.726+           ;; fontification done inside the function will be
   7.727+           ;; unconditionally overridden.
   7.728+           ,(c-make-font-lock-search-function
   7.729+             ;; Match a char before the string starter to make
   7.730+             ;; `c-skip-comments-and-strings' work correctly.
   7.731+             (concat ".\\(" c-string-limit-regexp "\\)")
   7.732+             '((c-font-lock-invalid-string)))
   7.733+
   7.734+
   7.735+           ;; Fontify keyword constants.
   7.736+           ,@(when (c-lang-const c-constant-kwds)
   7.737+               (let ((re (c-make-keywords-re nil
   7.738+                           (c-lang-const c-constant-kwds))))
   7.739+                 `((eval . (list ,(concat "\\<\\(" re "\\)\\>")
   7.740+                                 1 c-constant-face-name)))))
   7.741+
   7.742+
   7.743+           ;; Fontify the namespaces that follow using statements.
   7.744+           ;; This regex handles the optional alias, but does not fontify it.
   7.745+           ,`("\\<\\(using\\)\s+\\(?:[A-Za-z_][[:alnum:]]*\s*=\s*\\)?\\(\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*[A-Za-z_][[:alnum:]]*\\)\s*;"
   7.746+               2 font-lock-constant-face)
   7.747+
   7.748+
   7.749+           ;; Fontify all keywords except the primitive types.
   7.750+           ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp))
   7.751+              1 font-lock-keyword-face)
   7.752+
   7.753+
   7.754+           ;; Fontify leading identifiers in fully qualified names like
   7.755+           ;; "Foo.Bar".
   7.756+           ,@(when (c-lang-const c-opt-identifier-concat-key)
   7.757+               `((,(byte-compile
   7.758+                    `(lambda (limit)
   7.759+                       (while (re-search-forward
   7.760+                               ,(concat "\\(\\<" ; 1
   7.761+                                        "\\(" (c-lang-const c-symbol-key)
   7.762+                                        "\\)" ; 2
   7.763+                                        "[ \t\n\r\f\v]*"
   7.764+                                        (c-lang-const
   7.765+                                         c-opt-identifier-concat-key)
   7.766+                                        "[ \t\n\r\f\v]+"
   7.767+                                        "\\)"
   7.768+                                        "\\("
   7.769+                                        (c-lang-const
   7.770+                                         c-opt-after-id-concat-key)
   7.771+                                        "\\)")
   7.772+                               limit t)
   7.773+                         (unless (progn
   7.774+                                   (goto-char (match-beginning 0))
   7.775+                                   (c-skip-comments-and-strings limit))
   7.776+                           (or (get-text-property (match-beginning 2) 'face)
   7.777+                               (c-put-font-lock-face (match-beginning 2)
   7.778+                                                     (match-end 2)
   7.779+                                                     c-reference-face-name))
   7.780+                           (goto-char (match-end 1)))))))))
   7.781+
   7.782+           ))
   7.783+
   7.784+
   7.785+
   7.786+(c-lang-defconst c-basic-matchers-after
   7.787+  csharp `(
   7.788+
   7.789+           ;; option 1:
   7.790+           ;;            ,@(when condition
   7.791+           ;;                `((,(byte-compile
   7.792+           ;;                     `(lambda (limit) ...
   7.793+           ;;
   7.794+           ;; option 2:
   7.795+           ;;            ,`((lambda (limit) ...
   7.796+           ;;
   7.797+           ;; I don't know how to avoid the (when condition ...) in the
   7.798+           ;; byte-compiled version.
   7.799+           ;;
   7.800+           ;; 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+
   7.801+
   7.802+           ;; Case 1: invocation of constructor + maybe an object
   7.803+           ;; initializer.  Some possible examples that satisfy:
   7.804+           ;;
   7.805+           ;;   new Foo ();
   7.806+           ;;
   7.807+           ;;   new Foo () { };
   7.808+           ;;
   7.809+           ;;   new Foo {  };
   7.810+           ;;
   7.811+           ;;   new Foo { Prop1= 7 };
   7.812+           ;;
   7.813+           ;;   new Foo {
   7.814+           ;;     Prop1= 7
   7.815+           ;;   };
   7.816+           ;;
   7.817+           ;;   new Foo {
   7.818+           ;;     Prop1= 7,
   7.819+           ;;     Prop2= "Fred"
   7.820+           ;;   };
   7.821+           ;;
   7.822+           ;;   new Foo {
   7.823+           ;;      Prop1= new Bar()
   7.824+           ;;   };
   7.825+           ;;
   7.826+           ;;   new Foo {
   7.827+           ;;      Prop1= new Bar { PropA = 5.6F }
   7.828+           ;;   };
   7.829+           ;;
   7.830+
   7.831+           ,@(when t
   7.832+               `((,(byte-compile
   7.833+                    `(lambda (limit)
   7.834+                        (let ((parse-sexp-lookup-properties
   7.835+                               (cc-eval-when-compile
   7.836+                                 (boundp 'parse-sexp-lookup-properties))))
   7.837+
   7.838+                          (while (re-search-forward
   7.839+                                  ,(concat "\\<new"
   7.840+                                           "[ \t\n\r\f\v]+"
   7.841+                                           "\\(\\(?:"
   7.842+                                           (c-lang-const c-symbol-key)
   7.843+                                           "\\.\\)*"
   7.844+                                           (c-lang-const c-symbol-key)
   7.845+                                           "\\)"
   7.846+                                           )
   7.847+                                  limit t)
   7.848+                            (unless
   7.849+                                (progn
   7.850+                                  (goto-char (match-beginning 0))
   7.851+                                  (c-skip-comments-and-strings limit))
   7.852+
   7.853+                              (csharp-log 3 "ctor candidate at %d" (match-beginning 1))
   7.854+
   7.855+                              (save-match-data
   7.856+                                ;; next thing could be: [] () <> or {} or nothing (semicolon, comma).
   7.857+
   7.858+                                ;; fontify the typename
   7.859+                                (c-put-font-lock-face (match-beginning 1)
   7.860+                                                      (match-end 1)
   7.861+                                                      'font-lock-type-face)
   7.862+
   7.863+                                (goto-char (match-end 0))
   7.864+                                (c-forward-syntactic-ws)
   7.865+                                (if (eq (char-after) ?<) ;; ctor for generic type
   7.866+                                    (progn
   7.867+                                      (csharp-log 3 " - generic ctor")
   7.868+                                      ;; skip over <> safely
   7.869+                                      (c-safe (c-forward-sexp 1) t)
   7.870+                                      (c-forward-syntactic-ws)))
   7.871+
   7.872+                                ;; now, could be [] or (..) or {..} or semicolon.
   7.873+
   7.874+                                (csharp-log 3 " - looking for sexp")
   7.875+
   7.876+                                (if (or
   7.877+                                     (eq (char-after) ?{) ;; open curly
   7.878+                                     (and (eq (char-after) 91) ;; open square
   7.879+                                          (while (eq (char-after) 91)
   7.880+                                            (c-safe (c-forward-sexp 1)))
   7.881+                                          (eq (char-before) 93)) ;; close square
   7.882+                                     (and (eq (char-after) 40) ;; open paren
   7.883+                                          (c-safe (c-forward-sexp 1) t)))
   7.884+
   7.885+                                    (progn
   7.886+                                      ;; at this point we've jumped over any intervening s-exp
   7.887+                                      (c-forward-syntactic-ws)
   7.888+                                      (csharp-log 3 " - after fwd-syn-ws point(%d)" (point))
   7.889+                                      (csharp-log 3 " - next char:  %c" (char-after))
   7.890+                                      (if (eq (char-after) ?{)
   7.891+                                          (let ((start (point))
   7.892+                                                (end (if (c-safe (c-forward-sexp 1) t)
   7.893+                                                         (point) 0)))
   7.894+                                            (csharp-log 3 " - put c-decl-id-start on the open-curly at %d" start)
   7.895+                                            (c-put-char-property start
   7.896+                                                                 'c-type
   7.897+                                                                 'c-decl-id-start)
   7.898+                                            (goto-char start)
   7.899+                                            (if (> end start)
   7.900+                                                (progn
   7.901+                                                  (forward-char 1) ;; step over open curly
   7.902+                                                  (c-forward-syntactic-ws)
   7.903+                                                  (while (> end (point))
   7.904+                                                    ;; now, try to fontify/assign variables to any properties inside the curlies
   7.905+                                                    (csharp-log 3 " - inside open curly  point(%d)" (point))
   7.906+                                                    (csharp-log 3 " -   next char:  %c" (char-after))
   7.907+                                                    ;; fontify each property assignment
   7.908+                                                    (if (re-search-forward
   7.909+                                                         (concat "\\(" (c-lang-const c-symbol-key) "\\)\s*=")
   7.910+                                                         end t)
   7.911+                                                        (progn
   7.912+                                                          (csharp-log 3 " -   found variable  %d-%d"
   7.913+                                                                      (match-beginning 1)
   7.914+                                                                      (match-end 1))
   7.915+                                                          (c-put-font-lock-face (match-beginning 1)
   7.916+                                                                                (match-end 1)
   7.917+                                                                                'font-lock-variable-name-face)
   7.918+                                                          (goto-char (match-end 0))
   7.919+                                                          (c-forward-syntactic-ws)
   7.920+                                                          ;; advance to the next assignment, if possible
   7.921+                                                          (if (eq (char-after) ?@)
   7.922+                                                              (forward-char 1))
   7.923+
   7.924+                                                          (if (c-safe (c-forward-sexp 1) t)
   7.925+                                                              (progn
   7.926+                                                                (forward-char 1)
   7.927+                                                                (c-forward-syntactic-ws))))
   7.928+
   7.929+                                                      ;; else
   7.930+                                                      (csharp-log 3 " -   no more assgnmts found")
   7.931+                                                      (goto-char end)))))
   7.932+                                            )))))
   7.933+
   7.934+                              (goto-char (match-end 0))
   7.935+                              )))
   7.936+                        nil))
   7.937+                    )))
   7.938+
   7.939+
   7.940+           ;; Case 2: declaration of enum with or without an explicit
   7.941+           ;; base type.
   7.942+           ;;
   7.943+           ;; Examples:
   7.944+           ;;
   7.945+           ;;  public enum Foo { ... }
   7.946+           ;;
   7.947+           ;;  public enum Foo : uint { ... }
   7.948+           ;;
   7.949+           ,@(when t
   7.950+               `((,(byte-compile
   7.951+                    `(lambda (limit)
   7.952+                       (let ((parse-sexp-lookup-properties
   7.953+                              (cc-eval-when-compile
   7.954+                                (boundp 'parse-sexp-lookup-properties))))
   7.955+                         (while (re-search-forward
   7.956+                                 ,(concat csharp-enum-decl-re
   7.957+                                          "[ \t\n\r\f\v]*"
   7.958+                                          "{")
   7.959+                                 limit t)
   7.960+
   7.961+                           (csharp-log 3 "enum candidate at %d" (match-beginning 0))
   7.962+
   7.963+                           (unless
   7.964+                               (progn
   7.965+                                 (goto-char (match-beginning 0))
   7.966+                                 (c-skip-comments-and-strings limit))
   7.967+                             (progn
   7.968+                               (save-match-data
   7.969+                                 (goto-char (match-end 0))
   7.970+                                 (c-put-char-property (1- (point))
   7.971+                                                      'c-type
   7.972+                                                      'c-decl-id-start)
   7.973+                                 (c-forward-syntactic-ws))
   7.974+                               (save-match-data
   7.975+                                 (c-font-lock-declarators limit t nil))
   7.976+                               (goto-char (match-end 0))
   7.977+                               )
   7.978+                             )))
   7.979+                       nil))
   7.980+                  )))
   7.981+
   7.982+
   7.983+           ;; Case 3: declaration of constructor
   7.984+           ;;
   7.985+           ;; Example:
   7.986+           ;;
   7.987+           ;; private Foo(...) {...}
   7.988+           ;;
   7.989+           ,@(when t
   7.990+               `((,(byte-compile
   7.991+                    `(lambda (limit)
   7.992+                       (let ((parse-sexp-lookup-properties
   7.993+                              (cc-eval-when-compile
   7.994+                                (boundp 'parse-sexp-lookup-properties)))
   7.995+                             (found-it nil))
   7.996+                         (while (re-search-forward
   7.997+                                 ,(concat
   7.998+                                   "^[ \t\n\r\f\v]*"
   7.999+                                   "\\(\\<\\(public\\|private\\|protected\\)\\)?[ \t\n\r\f\v]+"
  7.1000+                                   "\\(@?[[:alpha:]_][[:alnum:]_]*\\)" ;; name of constructor
  7.1001+                                   "[ \t\n\r\f\v]*"
  7.1002+                                   "\\("
  7.1003+                                   "("
  7.1004+                                   "\\)")
  7.1005+                                 limit t)
  7.1006+                           (unless
  7.1007+                               (progn
  7.1008+                                 (goto-char (match-beginning 0))
  7.1009+                                 (c-skip-comments-and-strings limit))
  7.1010+
  7.1011+                             (goto-char (match-end 0))
  7.1012+
  7.1013+                             (csharp-log 3 "ctor decl candidate ending at %d" (point))
  7.1014+
  7.1015+                             (backward-char 1) ;; just left of the open paren
  7.1016+                             (save-match-data
  7.1017+                               ;; Jump over the parens, safely.
  7.1018+                               ;; If it's an unbalanced paren, no problem,
  7.1019+                               ;; do nothing.
  7.1020+                               (if (c-safe (c-forward-sexp 1) t)
  7.1021+                                   (progn
  7.1022+                                     (c-forward-syntactic-ws)
  7.1023+                                     (cond
  7.1024+
  7.1025+                                      ;; invokes base or this constructor.
  7.1026+                                      ((re-search-forward
  7.1027+                                        ,(concat
  7.1028+                                          "\\(:[ \t\n\r\f\v]*\\(base\\|this\\)\\)"
  7.1029+                                          "[ \t\n\r\f\v]*"
  7.1030+                                          "("
  7.1031+                                          )
  7.1032+                                        limit t)
  7.1033+                                       (csharp-log 3 " - ctor with dependency?")
  7.1034+
  7.1035+                                       (goto-char (match-end 0))
  7.1036+                                       (backward-char 1) ;; just left of the open paren
  7.1037+                                       (csharp-log 3 " - before paren at %d" (point))
  7.1038+
  7.1039+                                       (if (c-safe (c-forward-sexp 1) t)
  7.1040+                                           (progn
  7.1041+                                             (c-forward-syntactic-ws)
  7.1042+                                             (csharp-log 3 " - skipped over paren pair %d" (point))
  7.1043+                                             (if (eq (char-after) ?{)
  7.1044+                                                 (setq found-it t)))))
  7.1045+
  7.1046+                                      ;; open curly. no depedency on other ctor.
  7.1047+                                      ((eq (char-after) ?{)
  7.1048+                                       (csharp-log 3 " - ctor with no dependency? at %d" (point))
  7.1049+                                       (setq found-it t)))
  7.1050+
  7.1051+                                     )))
  7.1052+
  7.1053+                             (if found-it
  7.1054+                                 ;; fontify the constructor symbol
  7.1055+                                 (c-put-font-lock-face (match-beginning 3)
  7.1056+                                                       (match-end 3)
  7.1057+                                                       'font-lock-function-name-face))
  7.1058+                             (goto-char (match-end 0))
  7.1059+                             )
  7.1060+                           ))
  7.1061+                       nil))
  7.1062+                  )))
  7.1063+
  7.1064+
  7.1065+           ;; Case 4: using clause. Without this, using (..) gets fontified as a fn.
  7.1066+           ,@(when t
  7.1067+               `((,(byte-compile
  7.1068+                    `(lambda (limit)
  7.1069+                       (let ((parse-sexp-lookup-properties
  7.1070+                              (cc-eval-when-compile
  7.1071+                                (boundp 'parse-sexp-lookup-properties))))
  7.1072+                         (while (re-search-forward
  7.1073+                                 ,(concat "\\<\\(using\\)"
  7.1074+                                          "[ \t\n\r\f\v]*"
  7.1075+                                          "(")
  7.1076+                                 limit t)
  7.1077+
  7.1078+                           (csharp-log 3 "using clause at %d" (match-beginning 0))
  7.1079+
  7.1080+                           (unless
  7.1081+                               (progn
  7.1082+                                 (goto-char (match-beginning 0))
  7.1083+                                 (c-skip-comments-and-strings limit))
  7.1084+
  7.1085+                             (save-match-data
  7.1086+                               (c-put-font-lock-face (match-beginning 1)
  7.1087+                                                     (match-end 1)
  7.1088+                                                     'font-lock-keyword-face)
  7.1089+                               (goto-char (match-end 0))))))
  7.1090+                       nil))
  7.1091+                  )))
  7.1092+
  7.1093+           ;; Case 5: attributes
  7.1094+           ,`((lambda (limit)
  7.1095+                (let ((parse-sexp-lookup-properties
  7.1096+                       (cc-eval-when-compile
  7.1097+                         (boundp 'parse-sexp-lookup-properties))))
  7.1098+
  7.1099+                  (while (re-search-forward
  7.1100+                          ,(concat "[ \t\n\r\f\v]+"
  7.1101+                                   "\\(\\["
  7.1102+                                   "[ \t\n\r\f\v]*"
  7.1103+                                   "\\(?:\\(?:return\\|assembly\\)[ \t]*:[ \t]*\\)?"
  7.1104+                                   "\\("
  7.1105+                                   "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
  7.1106+                                   "[A-Za-z_][[:alnum:]]*"
  7.1107+                                   "\\)"
  7.1108+                                   "[^]]*\\]\\)"
  7.1109+                                   )
  7.1110+                          limit t)
  7.1111+
  7.1112+                    (csharp-log 3 "attribute? - %d limit(%d)" (match-beginning 1)
  7.1113+                                limit)
  7.1114+
  7.1115+                    (unless
  7.1116+                        (progn
  7.1117+                          (goto-char (match-beginning 1))
  7.1118+                          (c-skip-comments-and-strings limit))
  7.1119+
  7.1120+                      (let ((b2 (match-beginning 2))
  7.1121+                            (e2 (match-end 2))
  7.1122+                            (is-attr nil))
  7.1123+                        (csharp-log 3 " - type match: %d - %d"
  7.1124+                                    b2 e2)
  7.1125+                        (save-match-data
  7.1126+                          (c-backward-syntactic-ws)
  7.1127+                          (setq is-attr (or
  7.1128+                                         (eq (char-before) 59) ;; semicolon
  7.1129+                                         (eq (char-before) 93) ;; close square brace
  7.1130+                                         (eq (char-before) 123) ;; open curly
  7.1131+                                         (eq (char-before) 125) ;; close curly
  7.1132+                                         (save-excursion
  7.1133+                                           (c-beginning-of-statement-1)
  7.1134+                                           (looking-at
  7.1135+                                            "#\\(pragma\\|endregion\\|region\\|if\\|else\\|endif\\)"))
  7.1136+                                         )))
  7.1137+
  7.1138+                        (if is-attr
  7.1139+                            (progn
  7.1140+                              (csharp-log 3 " - attribute seems likely. type: %d - %d"
  7.1141+                                          b2 e2)
  7.1142+                              (c-put-font-lock-face b2 e2 'font-lock-type-face)))))
  7.1143+                    (goto-char (match-end 0))
  7.1144+                    ))
  7.1145+                nil))
  7.1146+
  7.1147+
  7.1148+           ;; Case 6: directive blocks for .aspx/.ashx/.ascx
  7.1149+           ,`((lambda (limit)
  7.1150+                (let ((parse-sexp-lookup-properties
  7.1151+                       (cc-eval-when-compile
  7.1152+                         (boundp 'parse-sexp-lookup-properties))))
  7.1153+
  7.1154+                  (while (re-search-forward csharp-aspnet-directive-re limit t)
  7.1155+                    (csharp-log 3 "aspnet template? - %d limit(%d)" (match-beginning 1)
  7.1156+                                limit)
  7.1157+
  7.1158+                    (unless
  7.1159+                        (progn
  7.1160+                          (goto-char (match-beginning 0))
  7.1161+                          (c-skip-comments-and-strings limit))
  7.1162+
  7.1163+                        (save-match-data
  7.1164+                          (let ((end-open (+ (match-beginning 0) 3))
  7.1165+                                (beg-close (- (match-end 0) 2)))
  7.1166+                            (c-put-font-lock-face (match-beginning 0)
  7.1167+                                                  end-open
  7.1168+                                                  'font-lock-preprocessor-face)
  7.1169+
  7.1170+                            (c-put-font-lock-face beg-close
  7.1171+                                                  (match-end 0)
  7.1172+                                                  'font-lock-preprocessor-face)
  7.1173+
  7.1174+                            ;; fontify within the directive
  7.1175+                            (while (re-search-forward
  7.1176+                                    ,(concat
  7.1177+                                      "\\("
  7.1178+                                      (c-lang-const c-symbol-key)
  7.1179+                                      "\\)"
  7.1180+                                      "=?"
  7.1181+                                      )
  7.1182+                                    beg-close t)
  7.1183+
  7.1184+                            (c-put-font-lock-face (match-beginning 1)
  7.1185+                                                  (match-end 1)
  7.1186+                                                  'font-lock-keyword-face)
  7.1187+                            (c-skip-comments-and-strings beg-close))
  7.1188+                            ))
  7.1189+                        (goto-char (match-end 0)))))
  7.1190+                nil))
  7.1191+
  7.1192+
  7.1193+;;            ;; Case 5: #if
  7.1194+;;            ,@(when t
  7.1195+;;                `((,(byte-compile
  7.1196+;;                     `(lambda (limit)
  7.1197+;;                        (let ((parse-sexp-lookup-properties
  7.1198+;;                               (cc-eval-when-compile
  7.1199+;;                                 (boundp 'parse-sexp-lookup-properties))))
  7.1200+;;                          (while (re-search-forward
  7.1201+;;                                  "\\<\\(#if\\)[ \t\n\r\f\v]+\\([A-Za-z_][[:alnum:]]*\\)"
  7.1202+;;                                  limit t)
  7.1203+;;
  7.1204+;;                            (csharp-log 3 "#if directive - %d" (match-beginning 1))
  7.1205+;;
  7.1206+;;                            (unless
  7.1207+;;                                (progn
  7.1208+;;                                  (goto-char (match-beginning 0))
  7.1209+;;                                  (c-skip-comments-and-strings limit))
  7.1210+;;
  7.1211+;;                              (save-match-data
  7.1212+;;                                (c-put-font-lock-face (match-beginning 2)
  7.1213+;;                                                      (match-end 2)
  7.1214+;;                                                      'font-lock-variable-name-face)
  7.1215+;;                                (goto-char (match-end 0))))))
  7.1216+;;                        nil))
  7.1217+;;                   )))
  7.1218+
  7.1219+
  7.1220+ ;;           ,`(,(c-make-font-lock-search-function
  7.1221+ ;;                (concat "\\<new"
  7.1222+ ;;                        "[ \t\n\r\f\v]+"
  7.1223+ ;;                        "\\(\\(?:"
  7.1224+ ;;                        (c-lang-const c-symbol-key)
  7.1225+ ;;                        "\\.\\)*"
  7.1226+ ;;                        (c-lang-const c-symbol-key)
  7.1227+ ;;                        "\\)"
  7.1228+ ;;                        "[ \t\n\r\f\v]*"
  7.1229+ ;;                        "\\(?:"
  7.1230+ ;;                        "( *)[ \t\n\r\f\v]*"          ;; optional ()
  7.1231+ ;;                        "\\)?"
  7.1232+ ;;                        "{")
  7.1233+ ;;                '((c-font-lock-declarators limit t nil)
  7.1234+ ;;                  (save-match-data
  7.1235+ ;;                    (goto-char (match-end 0))
  7.1236+ ;;                    (c-put-char-property (1- (point)) 'c-type
  7.1237+ ;;                                         'c-decl-id-start)
  7.1238+ ;;                    (c-forward-syntactic-ws))
  7.1239+ ;;                  (goto-char (match-end 0)))))
  7.1240+
  7.1241+
  7.1242+
  7.1243+
  7.1244+           ;; Fontify labels after goto etc.
  7.1245+           ,@(when (c-lang-const c-before-label-kwds)
  7.1246+               `( ;; (Got three different interpretation levels here,
  7.1247+                 ;; which makes it a bit complicated: 1) The backquote
  7.1248+                 ;; stuff is expanded when compiled or loaded, 2) the
  7.1249+                 ;; eval form is evaluated at font-lock setup (to
  7.1250+                 ;; substitute c-label-face-name correctly), and 3) the
  7.1251+                 ;; resulting structure is interpreted during
  7.1252+                 ;; fontification.)
  7.1253+                 (eval
  7.1254+                  . ,(let* ((c-before-label-re
  7.1255+                             (c-make-keywords-re nil
  7.1256+                               (c-lang-const c-before-label-kwds))))
  7.1257+                       `(list
  7.1258+                         ,(concat "\\<\\(" c-before-label-re "\\)\\>"
  7.1259+                                  "\\s *"
  7.1260+                                  "\\(" ; identifier-offset
  7.1261+                                  (c-lang-const c-symbol-key)
  7.1262+                                  "\\)")
  7.1263+                         (list ,(+ (regexp-opt-depth c-before-label-re) 2)
  7.1264+                               c-label-face-name nil t))))))
  7.1265+
  7.1266+
  7.1267+
  7.1268+           ;; Fontify the clauses after various keywords.
  7.1269+           ,@(when (or (c-lang-const c-type-list-kwds)
  7.1270+                       (c-lang-const c-ref-list-kwds)
  7.1271+                       (c-lang-const c-colon-type-list-kwds)
  7.1272+                       (c-lang-const c-paren-type-kwds))
  7.1273+               `((,(c-make-font-lock-search-function
  7.1274+                    (concat "\\<\\("
  7.1275+                            (c-make-keywords-re nil
  7.1276+                              (append (c-lang-const c-type-list-kwds)
  7.1277+                                      (c-lang-const c-ref-list-kwds)
  7.1278+                                      (c-lang-const c-colon-type-list-kwds)
  7.1279+                                      (c-lang-const c-paren-type-kwds)))
  7.1280+                            "\\)\\>")
  7.1281+                    '((c-fontify-types-and-refs ((c-promote-possible-types t))
  7.1282+                        (c-forward-keyword-clause 1)
  7.1283+                        (if (> (point) limit) (goto-char limit))))))))
  7.1284+
  7.1285+
  7.1286+           ;; Fontify the name that follows each namespace declaration
  7.1287+           ;; this needs to be done in the matchers-after because
  7.1288+           ;; otherwise the namespace names get the font-lock-type-face,
  7.1289+           ;; due to the energetic efforts of c-forward-type.
  7.1290+           ,`("\\<\\(namespace\\)[ \t\n\r\f\v]+\\(\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*[A-Za-z_][[:alnum:]]*\\)"
  7.1291+              2 font-lock-constant-face t)
  7.1292+
  7.1293+
  7.1294+           ))
  7.1295+
  7.1296+
  7.1297+;; C# does generics.  Setting this to t tells the parser to put
  7.1298+;; parenthesis syntax on angle braces that surround a comma-separated
  7.1299+;; list.
  7.1300+(c-lang-defconst c-recognize-<>-arglists
  7.1301+  csharp t)
  7.1302+
  7.1303+
  7.1304+
  7.1305+(c-lang-defconst c-identifier-key
  7.1306+  csharp (concat "\\([[:alpha:]_][[:alnum:]_]*\\)" ; 1
  7.1307+                 "\\("
  7.1308+                 "[ \t\n\r\f\v]*"
  7.1309+                 "\\(\\.\\)"             ;;(c-lang-const c-opt-identifier-concat-key)
  7.1310+                 "[ \t\n\r\f\v]*"
  7.1311+                 "\\(\\([[:alpha:]_][[:alnum:]_]*\\)\\)"
  7.1312+                 "\\)*"))
  7.1313+
  7.1314+;; C# has a few rules that are slightly different than Java for
  7.1315+;; operators. This also removed the Java's "super" and replaces it
  7.1316+;; with the C#'s "base".
  7.1317+(c-lang-defconst c-operators
  7.1318+  csharp `((prefix "base")))
  7.1319+
  7.1320+
  7.1321+;; C# uses CPP-like prefixes to mark #define, #region/endregion,
  7.1322+;; #if/else/endif, and #pragma.  This regexp matches the prefix,
  7.1323+;; not including the beginning-of-line (BOL), and not including
  7.1324+;; the term after the prefix (define, pragma, etc).  This regexp says
  7.1325+;; whitespace, followed by the prefix, followed by maybe more whitespace.
  7.1326+
  7.1327+(c-lang-defconst c-opt-cpp-prefix
  7.1328+  csharp "\\s *#\\s *")
  7.1329+
  7.1330+
  7.1331+;; there are no message directives in C#
  7.1332+(c-lang-defconst c-cpp-message-directives
  7.1333+  csharp nil)
  7.1334+
  7.1335+(c-lang-defconst c-cpp-expr-directives
  7.1336+  csharp '("if"))
  7.1337+
  7.1338+(c-lang-defconst c-opt-cpp-macro-define
  7.1339+  csharp "define")
  7.1340+
  7.1341+;; $ is not a legal char in an identifier in C#.  So we need to
  7.1342+;; create a csharp-specific definition of this constant.
  7.1343+(c-lang-defconst c-symbol-chars
  7.1344+  csharp (concat c-alnum "_"))
  7.1345+
  7.1346+
  7.1347+(c-lang-defconst c-colon-type-list-kwds
  7.1348+  csharp '("class"))
  7.1349+
  7.1350+(c-lang-defconst c-block-prefix-disallowed-chars
  7.1351+
  7.1352+  ;; Allow ':' for inherit list starters.
  7.1353+  csharp (set-difference (c-lang-const c-block-prefix-disallowed-chars)
  7.1354+                         '(?: ?,)))
  7.1355+
  7.1356+
  7.1357+(c-lang-defconst c-assignment-operators
  7.1358+  csharp '("=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|="))
  7.1359+
  7.1360+(c-lang-defconst c-primitive-type-kwds
  7.1361+  ;; ECMA-344, S8
  7.1362+  csharp '("object" "string" "sbyte" "short" "int" "long" "byte"
  7.1363+           "ushort" "uint" "ulong" "float" "double" "bool" "char"
  7.1364+           "decimal" "void"))
  7.1365+
  7.1366+;; The keywords that define that the following is a type, such as a
  7.1367+;; class definition.
  7.1368+(c-lang-defconst c-type-prefix-kwds
  7.1369+  ;; ECMA-344, S?
  7.1370+  csharp '("class" "interface" "struct"))  ;; no enum here.
  7.1371+                                           ;; we want enum to be a brace list.
  7.1372+
  7.1373+
  7.1374+;; Type modifier keywords. They appear anywhere in types, but modify
  7.1375+;; instead of create one.
  7.1376+(c-lang-defconst c-type-modifier-kwds
  7.1377+  ;; EMCA-344, S?
  7.1378+  csharp '("readonly" "const"))
  7.1379+
  7.1380+
  7.1381+;; Tue, 20 Apr 2010  16:02
  7.1382+;; need to verify that this works for lambdas...
  7.1383+(c-lang-defconst c-special-brace-lists
  7.1384+  csharp '((?{ . ?}) ))
  7.1385+
  7.1386+
  7.1387+
  7.1388+;; dinoch
  7.1389+;; Thu, 22 Apr 2010  18:54
  7.1390+;;
  7.1391+;; No idea why this isn't getting set properly in the first place.
  7.1392+;; In cc-langs.el, it is set to the union of a bunch of things, none
  7.1393+;; of which include "new", or "enum".
  7.1394+;;
  7.1395+;; But somehow both of those show up in the resulting derived regexp.
  7.1396+;; This breaks indentation of instance initializers, such as
  7.1397+;;
  7.1398+;;         var x = new Foo { ... };
  7.1399+;;
  7.1400+;; Based on my inspection, the existing c-lang-defconst should work!
  7.1401+;; I don't know how to fix this c-lang-defconst, so I am re-setting this
  7.1402+;; variable here, to provide the regex explicitly.
  7.1403+;;
  7.1404+(c-lang-defconst c-decl-block-key
  7.1405+
  7.1406+  csharp '"\\(namespace\\)\\([^[:alnum:]_]\\|$\\)\\|\\(class\\|interface\\|struct\\)\\([^[:alnum:]_]\\|$\\)"
  7.1407+  )
  7.1408+
  7.1409+
  7.1410+
  7.1411+;; Thu, 22 Apr 2010  14:29
  7.1412+;; I want this to handle    var x = new Foo[] { ... };
  7.1413+;; not sure if necessary.
  7.1414+(c-lang-defconst c-inexpr-brace-list-kwds
  7.1415+  csharp '("new"))
  7.1416+
  7.1417+
  7.1418+;; ;;(c-lang-defconst c-inexpr-class-kwds
  7.1419+;; ;; csharp '("new"))
  7.1420+
  7.1421+
  7.1422+
  7.1423+(c-lang-defconst c-class-decl-kwds
  7.1424+  ;; EMCA-344, S?
  7.1425+  csharp '("class" "interface" "struct" ))  ;; no "enum"!!
  7.1426+
  7.1427+
  7.1428+;; The various modifiers used for class and method descriptions.
  7.1429+(c-lang-defconst c-modifier-kwds
  7.1430+  csharp '("public" "partial" "private" "const" "abstract"
  7.1431+           "protected" "ref" "out" "static" "virtual"
  7.1432+           "override" "params" "internal"))
  7.1433+
  7.1434+
  7.1435+;; Thu, 22 Apr 2010  23:02
  7.1436+;; Based on inspection of the cc-mode code, the c-protection-kwds
  7.1437+;; c-lang-const is used only for objective-c.  So the value is
  7.1438+;; irrelevant for csharp.
  7.1439+(c-lang-defconst c-protection-kwds
  7.1440+  csharp nil
  7.1441+  ;; csharp '("private" "protected" "public" "internal")
  7.1442+)
  7.1443+
  7.1444+
  7.1445+;; Define the keywords that can have something following after them.
  7.1446+(c-lang-defconst c-type-list-kwds
  7.1447+  csharp '("struct" "class" "interface" "is" "as"
  7.1448+           "delegate" "event" "set" "get" "add" "remove"))
  7.1449+
  7.1450+
  7.1451+;; This allows the classes after the : in the class declartion to be
  7.1452+;; fontified.
  7.1453+(c-lang-defconst c-typeless-decl-kwds
  7.1454+  csharp '(":"))
  7.1455+
  7.1456+;; Sets up the enum to handle the list properly, and also the new
  7.1457+;; keyword to handle object initializers.  This requires a modified
  7.1458+;; c-basic-matchers-after (see above) in order to correctly fontify C#
  7.1459+;; 3.0 object initializers.
  7.1460+(c-lang-defconst c-brace-list-decl-kwds
  7.1461+  csharp '("enum" "new"))
  7.1462+
  7.1463+
  7.1464+;; Statement keywords followed directly by a substatement.
  7.1465+;; catch is not one of them.
  7.1466+(c-lang-defconst c-block-stmt-1-kwds
  7.1467+  csharp '("do" "try" "finally"))
  7.1468+
  7.1469+
  7.1470+;; Statement keywords followed by a paren sexp and then by a substatement.
  7.1471+(c-lang-defconst c-block-stmt-2-kwds
  7.1472+  csharp '("for" "if" "switch" "while" "catch" "foreach" "using"
  7.1473+           "checked" "unchecked" "lock"))
  7.1474+
  7.1475+
  7.1476+;; Statements that break out of braces
  7.1477+(c-lang-defconst c-simple-stmt-kwds
  7.1478+  csharp '("return" "continue" "break" "throw" "goto" ))
  7.1479+
  7.1480+;; Statements that allow a label
  7.1481+;; TODO?
  7.1482+(c-lang-defconst c-before-label-kwds
  7.1483+  csharp nil)
  7.1484+
  7.1485+;; Constant keywords
  7.1486+(c-lang-defconst c-constant-kwds
  7.1487+  csharp '("true" "false" "null"))
  7.1488+
  7.1489+;; Keywords that start "primary expressions."
  7.1490+(c-lang-defconst c-primary-expr-kwds
  7.1491+  csharp '("this" "base"))
  7.1492+
  7.1493+;; Treat namespace as an outer block so class indenting
  7.1494+;; works properly.
  7.1495+(c-lang-defconst c-other-block-decl-kwds
  7.1496+  csharp '("namespace"))
  7.1497+
  7.1498+(c-lang-defconst c-other-kwds
  7.1499+  csharp '("in" "sizeof" "typeof" "is" "as" "yield"
  7.1500+           "where" "select" "from"))
  7.1501+
  7.1502+(c-lang-defconst c-overloadable-operators
  7.1503+  ;; EMCA-344, S14.2.1
  7.1504+  csharp '("+" "-" "*" "/" "%" "&" "|" "^"
  7.1505+           "<<" ">>" "==" "!=" ">" "<" ">=" "<="))
  7.1506+
  7.1507+
  7.1508+;; This c-cpp-matchers stuff is used for fontification.
  7.1509+;; see cc-font.el
  7.1510+;;
  7.1511+
  7.1512+;; There's no preprocessor in C#, but there are still compiler
  7.1513+;; directives to fontify: "#pragma", #region/endregion, #define, #undef,
  7.1514+;; #if/else/endif.  (The definitions for the extra keywords above are
  7.1515+;; enough to incorporate them into the fontification regexps for types
  7.1516+;; and keywords, so no additional font-lock patterns are required for
  7.1517+;; keywords.)
  7.1518+
  7.1519+(c-lang-defconst c-cpp-matchers
  7.1520+  csharp (cons
  7.1521+      ;; Use the eval form for `font-lock-keywords' to be able to use
  7.1522+      ;; the `c-preprocessor-face-name' variable that maps to a
  7.1523+      ;; suitable face depending on the (X)Emacs version.
  7.1524+      '(eval . (list "^\\s *\\(#pragma\\|undef\\|define\\)\\>\\(.*\\)"
  7.1525+                     (list 1 c-preprocessor-face-name)
  7.1526+                     '(2 font-lock-string-face)))
  7.1527+      ;; There are some other things in `c-cpp-matchers' besides the
  7.1528+      ;; preprocessor support, so include it.
  7.1529+      (c-lang-const c-cpp-matchers)))
  7.1530+
  7.1531+(defcustom csharp-font-lock-extra-types nil
  7.1532+  "*List of extra types (aside from the type keywords) to recognize in C# mode.
  7.1533+Each list item should be a regexp matching a single identifier."
  7.1534+  :type 'list :group 'csharp)
  7.1535+
  7.1536+(defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp)
  7.1537+  "Minimal highlighting for C# mode.")
  7.1538+
  7.1539+(defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp)
  7.1540+  "Fast normal highlighting for C# mode.")
  7.1541+
  7.1542+(defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp)
  7.1543+  "Accurate normal highlighting for C# mode.")
  7.1544+
  7.1545+(defvar csharp-font-lock-keywords csharp-font-lock-keywords-3
  7.1546+  "Default expressions to highlight in C# mode.")
  7.1547+
  7.1548+(defvar csharp-mode-syntax-table nil
  7.1549+  "Syntax table used in csharp-mode buffers.")
  7.1550+(or csharp-mode-syntax-table
  7.1551+    (setq csharp-mode-syntax-table
  7.1552+          (funcall (c-lang-const c-make-mode-syntax-table csharp))))
  7.1553+
  7.1554+(defvar csharp-mode-abbrev-table nil
  7.1555+  "Abbreviation table used in csharp-mode buffers.")
  7.1556+(c-define-abbrev-table 'csharp-mode-abbrev-table
  7.1557+  ;; Keywords that if they occur first on a line might alter the
  7.1558+  ;; syntactic context, and which therefore should trig reindentation
  7.1559+  ;; when they are completed.
  7.1560+  '(("else" "else" c-electric-continued-statement 0)
  7.1561+    ("while" "while" c-electric-continued-statement 0)
  7.1562+    ("catch" "catch" c-electric-continued-statement 0)
  7.1563+    ("finally" "finally" c-electric-continued-statement 0)))
  7.1564+
  7.1565+(defvar csharp-mode-map (let ((map (c-make-inherited-keymap)))
  7.1566+                      ;; Add bindings which are only useful for C#
  7.1567+                      map)
  7.1568+  "Keymap used in csharp-mode buffers.")
  7.1569+
  7.1570+
  7.1571+;; TODO
  7.1572+;; Defines our constant for finding attributes.
  7.1573+;;(defconst csharp-attribute-regex "\\[\\([XmlType]+\\)(")
  7.1574+;;(defconst csharp-attribute-regex "\\[\\(.\\)")
  7.1575+;; This doesn't work because the string regex happens before this point
  7.1576+;; and getting the font-locking to work before and after is fairly difficult
  7.1577+;;(defconst csharp-attribute-regex
  7.1578+;;  (concat
  7.1579+;;   "\\[[a-zA-Z][ \ta-zA-Z0-9.]+"
  7.1580+;;   "\\((.*\\)?"
  7.1581+;;))
  7.1582+
  7.1583+
  7.1584+;; ==================================================================
  7.1585+;; end of c# values for "language constants" defined in cc-langs.el
  7.1586+;; ==================================================================
  7.1587+
  7.1588+
  7.1589+
  7.1590+
  7.1591+;; ==================================================================
  7.1592+;; C# code-doc insertion magic
  7.1593+;; ==================================================================
  7.1594+;;
  7.1595+;; In Visual Studio, if you type three slashes, it immediately expands into
  7.1596+;; an inline code-documentation fragment.  The following method does the
  7.1597+;; same thing.
  7.1598+;;
  7.1599+;; This is the kind of thing that could be handled by YASnippet or
  7.1600+;; another similarly flexible snippet framework. But I don't want to
  7.1601+;; introduce a dependency on yasnippet to csharp-mode. So the capability
  7.1602+;; must live within csharp-mode itself.
  7.1603+
  7.1604+(defun csharp-maybe-insert-codedoc (arg)
  7.1605+
  7.1606+  "Insert an xml code documentation template as appropriate, when
  7.1607+typing slashes.  This fn gets bound to / (the slash key), in
  7.1608+csharp-mode.  If the slash being inserted is not the third
  7.1609+consecutive slash, the slash is inserted as normal.  If it is the
  7.1610+third consecutive slash, then a xml code documentation template
  7.1611+may be inserted in some cases. For example,
  7.1612+
  7.1613+  a <summary> template is inserted if the prior line is empty,
  7.1614+        or contains only an open curly brace;
  7.1615+  a <remarks> template is inserted if the prior word
  7.1616+        closes the <summary> element;
  7.1617+  a <returns> template is inserted if the prior word
  7.1618+        closes the <remarks> element;
  7.1619+  an <example> template is inserted if the prior word closes
  7.1620+        the <returns> element;
  7.1621+  a <para> template is inserted if the prior word closes
  7.1622+        a <para> element.
  7.1623+
  7.1624+In all other cases the slash is inserted as normal.
  7.1625+
  7.1626+If you want the default cc-mode behavior, which implies no automatic
  7.1627+insertion of xml code documentation templates, then use this in
  7.1628+your `csharp-mode-hook' function:
  7.1629+
  7.1630+     (local-set-key (kbd \"/\") 'c-electric-slash)
  7.1631+
  7.1632+ "
  7.1633+  (interactive "*p")
  7.1634+  ;;(message "csharp-maybe-insert-codedoc")
  7.1635+  (let (
  7.1636+        (cur-point (point))
  7.1637+        (char last-command-char)
  7.1638+        (cb0 (char-before (- (point) 0)))
  7.1639+        (cb1 (char-before (- (point) 1)))
  7.1640+        is-first-non-whitespace
  7.1641+        did-auto-insert
  7.1642+        )
  7.1643+
  7.1644+    ;; check if two prior chars were slash
  7.1645+    (if (and
  7.1646+         (= char ?/)
  7.1647+         cb0 (= ?/ cb0)
  7.1648+         cb1 (= ?/ cb1)
  7.1649+         )
  7.1650+
  7.1651+        (progn
  7.1652+          ;;(message "yes - this is the third consecutive slash")
  7.1653+          (setq is-first-non-whitespace
  7.1654+                (save-excursion
  7.1655+                  (back-to-indentation)
  7.1656+                  (= cur-point (+ (point) 2))))
  7.1657+
  7.1658+          (if is-first-non-whitespace
  7.1659+              ;; This is a 3-slash sequence.  It is the first non-whitespace text
  7.1660+              ;; on the line. Now we need to examine the surrounding context
  7.1661+              ;; in order to determine which xml cod doc template to insert.
  7.1662+              (let (word-back char0 char1
  7.1663+                    word-fore char-0 char-1
  7.1664+                    text-to-insert         ;; text to insert in lieu of slash
  7.1665+                    fn-to-call     ;; func to call after inserting text
  7.1666+                    (preceding-line-is-empty (or
  7.1667+                                              (= (line-number-at-pos) 1)
  7.1668+                                              (save-excursion
  7.1669+                                               (previous-line)
  7.1670+                                               (beginning-of-line)
  7.1671+                                               (looking-at "[ \t]*$\\|[ \t]*{[ \t]*$"))))
  7.1672+                    (flavor 0) ;; used only for diagnostic purposes
  7.1673+                    )
  7.1674+
  7.1675+                ;;(message "starting a 3-slash comment")
  7.1676+                ;; get the prior word, and the 2 chars preceding it.
  7.1677+                (backward-word)
  7.1678+
  7.1679+                (setq word-back (thing-at-point 'word)
  7.1680+                      char0 (char-before (- (point) 0))
  7.1681+                      char1 (char-before (- (point) 1)))
  7.1682+
  7.1683+                ;; restore prior position
  7.1684+                (goto-char cur-point)
  7.1685+
  7.1686+                ;; get the following word, and the 2 chars preceding it.
  7.1687+                (forward-word)
  7.1688+                (backward-word)
  7.1689+                (setq word-fore (thing-at-point 'word)
  7.1690+                      char-0 (char-before (- (point) 0))
  7.1691+                      char-1 (char-before (- (point) 1)))
  7.1692+
  7.1693+                ;; restore prior position again
  7.1694+                (goto-char cur-point)
  7.1695+
  7.1696+                (cond
  7.1697+                 ;; The preceding line is empty, or all whitespace, or
  7.1698+                 ;; contains only an open-curly.  In this case, insert a
  7.1699+                 ;; summary element pair.
  7.1700+                 (preceding-line-is-empty
  7.1701+                  (setq text-to-insert  "/ <summary>\n///   \n/// </summary>"
  7.1702+                        flavor 1) )
  7.1703+
  7.1704+                 ;; The preceding word closed a summary element.  In this case,
  7.1705+                 ;; if the forward word does not open a remarks element, then
  7.1706+                 ;; insert a remarks element.
  7.1707+                 ((and (string-equal word-back "summary") (eq char0 ?/)  (eq char1 ?<))
  7.1708+                  (if (not (and (string-equal word-fore "remarks") (eq char-0 ?<)))
  7.1709+                      (setq text-to-insert "/ <remarks>\n///   <para>\n///     \n///   </para>\n/// </remarks>"
  7.1710+                            flavor 2)))
  7.1711+
  7.1712+                 ;; The preceding word closed the remarks section.  In this case,
  7.1713+                 ;; insert an example element.
  7.1714+                 ((and (string-equal word-back "remarks")  (eq char0 ?/)  (eq char1 ?<))
  7.1715+                  (setq text-to-insert "/ <example>\n///   \n/// </example>"
  7.1716+                        flavor 3))
  7.1717+
  7.1718+                 ;; The preceding word closed the example section.  In this
  7.1719+                 ;; case, insert an returns element.  This isn't always
  7.1720+                 ;; correct, because sometimes the xml code doc is attached to
  7.1721+                 ;; a class or a property, neither of which has a return
  7.1722+                 ;; value. A more intelligent implementation would inspect the
  7.1723+                 ;; syntax state and only inject a returns element if
  7.1724+                 ;; appropriate.
  7.1725+                 ((and (string-equal word-back "example")  (eq char0 ?/)  (eq char1 ?<))
  7.1726+                  (setq text-to-insert "/ <returns></returns>"
  7.1727+                        fn-to-call (lambda ()
  7.1728+                                     (backward-word)
  7.1729+                                     (backward-char)
  7.1730+                                     (backward-char)
  7.1731+                                     (c-indent-line-or-region)
  7.1732+                                     )
  7.1733+                        flavor 4))
  7.1734+
  7.1735+                 ;; The preceding word opened the remarks section, or it
  7.1736+                 ;; closed a para section. In this case, insert a para
  7.1737+                 ;; element, using appropriate indentation with respect to the
  7.1738+                 ;; prior tag.
  7.1739+                 ((or
  7.1740+                   (and (string-equal word-back "remarks")  (eq char0 ?<)  (or (eq char1 32) (eq char1 9)))
  7.1741+                   (and (string-equal word-back "para")     (eq char0 ?/)  (eq char1 ?<)))
  7.1742+
  7.1743+                  (let (prior-point spacer)
  7.1744+                    (save-excursion
  7.1745+                      (backward-word)
  7.1746+                      (backward-char)
  7.1747+                      (backward-char)
  7.1748+                      (setq prior-point (point))
  7.1749+                      (skip-chars-backward "\t ")
  7.1750+                      (setq spacer (buffer-substring (point) prior-point))
  7.1751+                      ;;(message (format "pt(%d) prior(%d) spacer(%s)" (point) prior-point spacer))
  7.1752+                      )
  7.1753+
  7.1754+                    (if (string-equal word-back "remarks")
  7.1755+                        (setq spacer (concat spacer "   ")))
  7.1756+
  7.1757+                    (setq text-to-insert (format "/%s<para>\n///%s  \n///%s</para>"
  7.1758+                                                 spacer spacer spacer)
  7.1759+                          flavor 6)))
  7.1760+
  7.1761+                 ;; The preceding word opened a para element.  In this case, if
  7.1762+                 ;; the forward word does not close the para element, then
  7.1763+                 ;; close the para element.
  7.1764+                 ;; --
  7.1765+                 ;; This is a nice idea but flawed.  Suppose I have a para element with some
  7.1766+                 ;; text in it. If I position the cursor at the first line, then type 3 slashes,
  7.1767+                 ;; I get a close-element, and that would be inappropriate.  Not sure I can
  7.1768+                 ;; easily solve that problem, so the best thing might be to simply punt, and
  7.1769+                 ;; require people to close their own elements.
  7.1770+                 ;;
  7.1771+                 ;;              ( (and (string-equal word-back "para")  (eq char0 60)  (or (eq char1 32) (eq char1 9)))
  7.1772+                 ;;                (if (not (and (string-equal word-fore "para") (eq char-0 47) (eq char-1 60) ))
  7.1773+                 ;;                    (setq text-to-insert "/   \n/// </para>\n///"
  7.1774+                 ;;                          fn-to-call (lambda ()
  7.1775+                 ;;                                       (previous-line)
  7.1776+                 ;;                                       (end-of-line)
  7.1777+                 ;;                                       )
  7.1778+                 ;;                          flavor 7) )
  7.1779+                 ;;                )
  7.1780+
  7.1781+                 ;; the default case - do nothing
  7.1782+                 (t nil))
  7.1783+
  7.1784+                (if text-to-insert
  7.1785+                    (progn
  7.1786+                      ;;(message (format "inserting special text (f(%d))" flavor))
  7.1787+
  7.1788+                      ;; set the flag, that we actually inserted text
  7.1789+                      (setq did-auto-insert t)
  7.1790+
  7.1791+                      ;; save point of beginning of insertion
  7.1792+                      (setq cur-point (point))
  7.1793+
  7.1794+                      ;; actually insert the text
  7.1795+                      (insert text-to-insert)
  7.1796+
  7.1797+                      ;; indent the inserted string, and re-position point, either through
  7.1798+                      ;; the case-specific fn, or via the default progn.
  7.1799+                      (if fn-to-call
  7.1800+                          (funcall fn-to-call)
  7.1801+
  7.1802+                        (let ((newline-count 0) (pos 0) ix)
  7.1803+
  7.1804+                          ;; count the number of newlines in the inserted string
  7.1805+                          (while (string-match "\n" text-to-insert pos)
  7.1806+                            (setq pos (match-end 0)
  7.1807+                                  newline-count (+ newline-count 1) )
  7.1808+                            )
  7.1809+
  7.1810+                          ;; indent what we just inserted
  7.1811+                          (c-indent-region cur-point (point) t)
  7.1812+
  7.1813+                          ;; move up n/2 lines. This assumes that the
  7.1814+                          ;; inserted text is ~symmetric about the halfway point.
  7.1815+                          ;; The assumption holds if the xml code doc uses a
  7.1816+                          ;; begin-elt and end-elt on a new line all by themselves,
  7.1817+                          ;; and a blank line in between them where the point should be.
  7.1818+                          ;; A more intelligent implementation would use a specific
  7.1819+                          ;; marker string, like @@DOT, to note the desired point.
  7.1820+                          (previous-line (/ newline-count 2))
  7.1821+                          (end-of-line)))))))))
  7.1822+
  7.1823+    (if (not did-auto-insert)
  7.1824+        (self-insert-command (prefix-numeric-value arg)))))
  7.1825+
  7.1826+;; ==================================================================
  7.1827+;; end of c# code-doc insertion magic
  7.1828+;; ==================================================================
  7.1829+
  7.1830+
  7.1831+
  7.1832+
  7.1833+;; ==================================================================
  7.1834+;; c# fontification extensions
  7.1835+;; ==================================================================
  7.1836+;; Commentary:
  7.1837+;;
  7.1838+;; The purpose of the following code is to fix font-lock for C#,
  7.1839+;; specifically for the verbatim-literal strings. C# is a cc-mode
  7.1840+;; language and strings are handled mostly like other c-based
  7.1841+;; languages. The one exception is the verbatim-literal string, which
  7.1842+;; uses the syntax @"...".
  7.1843+;;
  7.1844+;; `parse-partial-sexp' treats those strings as just regular strings,
  7.1845+;; with the @ a non-string character.  This is fine, except when the
  7.1846+;; verblit string ends in a slash, in which case, font-lock breaks from
  7.1847+;; that point onward in the buffer.
  7.1848+;;
  7.1849+;; This is an attempt to fix that.
  7.1850+;;
  7.1851+;; The idea is to scan the buffer in full for verblit strings, and apply the
  7.1852+;; appropriate syntax-table text properties for verblit strings. Also setting
  7.1853+;; `parse-sexp-lookup-properties' to t tells `parse-partial-sexp'
  7.1854+;; to use the syntax-table text properties set up by the scan as it does
  7.1855+;; its parse.
  7.1856+;;
  7.1857+;; Also need to re-scan after any changes in the buffer, but on a more
  7.1858+;; limited region.
  7.1859+;;
  7.1860+
  7.1861+
  7.1862+;; ;; I don't remember what this is supposed to do,
  7.1863+;; ;; or how I figured out the value.
  7.1864+;; ;;
  7.1865+;; (defconst csharp-font-lock-syntactic-keywords
  7.1866+;;   '(("\\(@\\)\\(\"\\)[^\"]*\\(\"\\)\\(\"\\)[^\"]*\\(\"\\)[^\"]"
  7.1867+;;      (1 '(6)) (2 '(7)) (3 '(1)) (4 '(1)) (5 '(7))
  7.1868+;;                  ))
  7.1869+;;   "Highlighting of verbatim literal strings. See also the variable
  7.1870+;;   `font-lock-keywords'.")
  7.1871+
  7.1872+
  7.1873+
  7.1874+;; The following fn allows this:
  7.1875+;;    (csharp-log 3 "scan result...'%s'" state)
  7.1876+
  7.1877+(defvar csharp-log-level 0
  7.1878+  "The current log level for CSharp-specific operations.
  7.1879+This is used in particular by the verbatim-literal
  7.1880+string scanning.
  7.1881+
  7.1882+Most other csharp functions are not instrumented.
  7.1883+0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY. ")
  7.1884+
  7.1885+(defun csharp-log (level text &rest args)
  7.1886+  "Log a message at level LEVEL.
  7.1887+If LEVEL is higher than `csharp-log-level', the message is
  7.1888+ignored.  Otherwise, it is printed using `message'.
  7.1889+TEXT is a format control string, and the remaining arguments ARGS
  7.1890+are the string substitutions (see `format')."
  7.1891+  (if (<= level csharp-log-level)
  7.1892+      (let* ((msg (apply 'format text args)))
  7.1893+        (message "C#: %s" msg))
  7.1894+    t))
  7.1895+
  7.1896+
  7.1897+
  7.1898+(defun csharp-max-beginning-of-stmt ()
  7.1899+  "Return the greater of `c-beginning-of-statement-1' and
  7.1900+`c-beginning-of-statement' .  I don't understand why both of
  7.1901+these methods are necessary or why they differ. But they do."
  7.1902+
  7.1903+  (let (dash
  7.1904+        nodash
  7.1905+        (curpos (point)))
  7.1906+
  7.1907+    ;; I think this may need a save-excursion...
  7.1908+    ;; Calling c-beginning-of-statement-1 resets the point!
  7.1909+
  7.1910+    (setq dash (progn (c-beginning-of-statement-1) (point)))
  7.1911+    (csharp-log 3 "max-bostmt dash(%d)" dash)
  7.1912+    (goto-char curpos)
  7.1913+
  7.1914+    (setq nodash (progn (c-beginning-of-statement 1) (point)))
  7.1915+    (csharp-log 3 "max-bostmt nodash(%d)" nodash)
  7.1916+    (goto-char curpos)
  7.1917+
  7.1918+    (max dash nodash)))
  7.1919+
  7.1920+
  7.1921+(defun csharp-in-literal (&optional lim detect-cpp)
  7.1922+  "Return the type of literal point is in, if any.
  7.1923+Basically this works like `c-in-literal' except it doesn't
  7.1924+use or fill the cache (`c-in-literal-cache').
  7.1925+
  7.1926+The return value is `c' if in a C-style comment, `c++' if in a C++
  7.1927+style comment, `string' if in a string literal, `pound' if DETECT-CPP
  7.1928+is non-nil and in a preprocessor line, or nil if somewhere else.
  7.1929+Optional LIM is used as the backward limit of the search.  If omitted,
  7.1930+or nil, `c-beginning-of-syntax' is used.
  7.1931+
  7.1932+Note that this function might do hidden buffer changes.  See the
  7.1933+comment at the start of cc-engine.el for more info."
  7.1934+
  7.1935+  (let ((rtn
  7.1936+        (save-excursion
  7.1937+          (let* ((pos (point))
  7.1938+                 (lim (or lim (progn
  7.1939+                                (c-beginning-of-syntax)
  7.1940+                                (point))))
  7.1941+                 (state (parse-partial-sexp lim pos)))
  7.1942+            (csharp-log 4 "parse lim(%d) state: %s" lim (prin1-to-string state))
  7.1943+            (cond
  7.1944+             ((elt state 3)
  7.1945+              (csharp-log 4 "in literal string (%d)" pos)
  7.1946+              'string)
  7.1947+             ((elt state 4)
  7.1948+              (csharp-log 4 "in literal comment (%d)" pos)
  7.1949+              (if (elt state 7) 'c++ 'c))
  7.1950+             ((and detect-cpp (c-beginning-of-macro lim)) 'pound)
  7.1951+             (t nil))))))
  7.1952+    rtn))
  7.1953+
  7.1954+
  7.1955+(defun csharp-set-vliteral-syntax-table-properties (beg end)
  7.1956+  "Scan the buffer text between BEG and END, a verbatim literal
  7.1957+string, setting and clearing syntax-table text properties where
  7.1958+necessary.
  7.1959+
  7.1960+We need to modify the default syntax-table text property in these cases:
  7.1961+  (backslash)    - is not an escape inside a verbatim literal string.
  7.1962+  (double-quote) - can be a literal quote, when doubled.
  7.1963+
  7.1964+BEG is the @ delimiter. END is the 'old' position of the ending quote.
  7.1965+
  7.1966+see http://www.sunsite.ualberta.ca/Documentation/Gnu/emacs-lisp-ref-21-2.7/html_node/elisp_592.html
  7.1967+for the list of syntax table numeric codes.
  7.1968+
  7.1969+"
  7.1970+
  7.1971+  (csharp-log 3 "set-vlit-syntax-table:  beg(%d) end(%d)" beg end)
  7.1972+
  7.1973+  (if (and (> beg 0) (> end 0))
  7.1974+
  7.1975+      (let ((curpos beg)
  7.1976+            (state 0))
  7.1977+
  7.1978+        (c-clear-char-properties beg end 'syntax-table)
  7.1979+
  7.1980+        (while (<= curpos end)
  7.1981+
  7.1982+          (cond
  7.1983+           ((= state 0)
  7.1984+            (if (= (char-after curpos) ?@)
  7.1985+                (progn
  7.1986+                  (c-put-char-property curpos 'syntax-table '(6)) ; (6) = expression prefix, (3) = symbol
  7.1987+                  ;;(message (format "set-s-t: prefix pos(%d) chr(%c)" beg (char-after beg)))
  7.1988+                  )
  7.1989+              )
  7.1990+            (setq state (+ 1 state)))
  7.1991+
  7.1992+           ((= state 1)
  7.1993+            (if (= (char-after curpos) ?\")
  7.1994+                (progn
  7.1995+                  (c-put-char-property curpos 'syntax-table '(7)) ; (7) = string quote
  7.1996+                  ;;(message (format "set-s-t: open quote pos(%d) chr(%c)"
  7.1997+                  ;; curpos (char-after curpos)))
  7.1998+                  ))
  7.1999+            (setq state (+ 1 state)))
  7.2000+
  7.2001+           ((= state 2)
  7.2002+            (cond
  7.2003+             ;; handle backslash inside the string
  7.2004+             ((= (char-after curpos) ?\\)
  7.2005+              (c-put-char-property curpos 'syntax-table '(2)) ; (1) = punctuation, (2) = word
  7.2006+              ;;(message (format "set-s-t: backslash word pos(%d) chr(%c)" curpos (char-after curpos)))
  7.2007+              )
  7.2008+
  7.2009+             ;; doubled double-quote
  7.2010+             ((and
  7.2011+               (= (char-after curpos) ?\")
  7.2012+               (= (char-after (+ 1 curpos)) ?\"))
  7.2013+              (c-put-char-property curpos 'syntax-table '(2)) ; (1) = punctuation, (2) = word
  7.2014+              (c-put-char-property (+ 1 curpos) 'syntax-table '(2)) ; (1) = punctuation
  7.2015+              ;;(message (format "set-s-t: double doublequote pos(%d) chr(%c)" curpos (char-after curpos)))
  7.2016+              (setq curpos (+ curpos 1))
  7.2017+              )
  7.2018+
  7.2019+             ;; a single double-quote, which should be a string terminator
  7.2020+             ((= (char-after curpos) ?\")
  7.2021+              (c-put-char-property curpos 'syntax-table '(7)) ; (7) = string quote
  7.2022+              ;;(message (format "set-s-t: close quote pos(%d) chr(%c)" curpos (char-after curpos)))
  7.2023+              ;;go no further
  7.2024+              (setq state (+ 1 state)))
  7.2025+
  7.2026+             ;; everything else
  7.2027+             (t
  7.2028+              ;;(message (format "set-s-t: none pos(%d) chr(%c)" curpos (char-after curpos)))
  7.2029+              nil))))
  7.2030+          ;; next char
  7.2031+          (setq curpos (+ curpos 1))))))
  7.2032+
  7.2033+
  7.2034+
  7.2035+(defun csharp-end-of-verbatim-literal-string (&optional lim)
  7.2036+  "Moves to and returns the position of the end quote of the verbatim literal
  7.2037+string.  When calling, point should be on the @ of the verblit string.
  7.2038+If it is not, then no movement is performed and `point' is returned.
  7.2039+
  7.2040+This function ignores text properties. In fact it is the
  7.2041+underlying scanner used to set the text properties in a C# buffer.
  7.2042+"
  7.2043+
  7.2044+  (csharp-log 3 "end-of-vlit-string: point(%d) c(%c)" (point) (char-after))
  7.2045+
  7.2046+  (let (curpos
  7.2047+        (max (or lim (point-max))))
  7.2048+
  7.2049+    (if (not (looking-at "@\""))
  7.2050+        (point)
  7.2051+    (forward-char 2) ;; pass up the @ sign and first quote
  7.2052+    (setq curpos (point))
  7.2053+
  7.2054+    ;; Within a verbatim literal string, a doubled double-quote
  7.2055+    ;; escapes the double-quote."
  7.2056+    (while (and                                  ;; process characters...
  7.2057+            (or                                  ;; while...
  7.2058+             (not (eq (char-after curpos) ?\"))  ;; it's not a quote
  7.2059+             (eq (char-after (+ curpos 1)) ?\")) ;; or, its a double (double) quote
  7.2060+            (< curpos max))                      ;; and we're not done yet
  7.2061+
  7.2062+      (cond
  7.2063+       ((and (eq (char-after curpos) ?\")        ;; it's a double-quote.
  7.2064+             (eq (char-after (+ curpos 1)) ?\"))
  7.2065+        (setq curpos (+ 2 curpos)))              ;; Skip 2
  7.2066+       (t                                        ;; anything else
  7.2067+        (setq curpos (+ 1 curpos)))))            ;; skip fwd 1
  7.2068+    curpos)))
  7.2069+
  7.2070+
  7.2071+
  7.2072+
  7.2073+(defun csharp-scan-for-verbatim-literals-and-set-props (&optional beg end)
  7.2074+
  7.2075+"Scans the buffer, between BEG and END, for verbatim literal
  7.2076+strings, and sets override text properties on each string to
  7.2077+allow proper syntax highlighting, indenting, and cursor movement.
  7.2078+
  7.2079+BEG and END define the limits of the scan.  When nil, they
  7.2080+default to `point-min' and `point-max' respectively.
  7.2081+
  7.2082+Setting text properties generally causes the buffer to be marked
  7.2083+as modified, but this fn suppresses that via the
  7.2084+`c-buffer-save-state' macro, for any changes in text properties
  7.2085+that it makes.  This fn also ignores the read-only setting on a
  7.2086+buffer, using the same macro.
  7.2087+
  7.2088+This fn is called when a csharp-mode buffer is loaded, with BEG
  7.2089+and END set to nil, to do a full scan.  It is also called on
  7.2090+every buffer change, with the BEG and END set to the values for
  7.2091+the change.
  7.2092+
  7.2093+The return value is nil if the buffer was not a csharp-mode
  7.2094+buffer.  Otherwise it is the last cursor position examined by the
  7.2095+scan.
  7.2096+"
  7.2097+
  7.2098+  (if (not (c-major-mode-is 'csharp-mode)) ;; don't scan if not csharp mode
  7.2099+      nil
  7.2100+    (save-excursion
  7.2101+      (c-save-buffer-state
  7.2102+          ((curpos (or beg (point-min)))
  7.2103+           (lastpos (or end (point-max)))
  7.2104+           (state 0) (start 0) (cycle 0)
  7.2105+           literal eos limits)
  7.2106+
  7.2107+        (csharp-log 3 "scan")
  7.2108+        (goto-char curpos)
  7.2109+
  7.2110+        (while (and (< curpos lastpos) (< cycle 10000))
  7.2111+          (cond
  7.2112+
  7.2113+           ;; Case 1: current char is a @ sign
  7.2114+           ;; --------------------------------------------
  7.2115+           ;; Check to see if it demarks the beginning of a verblit
  7.2116+           ;; string.
  7.2117+           ((= ?@ (char-after curpos))
  7.2118+
  7.2119+            ;; are we in a comment?   a string?  Maybe the @ is a prefix
  7.2120+            ;; to allow the use of a reserved word as a symbol. Let's find out.
  7.2121+
  7.2122+            ;; not sure why I need both of the following.
  7.2123+            (syntax-ppss-flush-cache 1)
  7.2124+            (parse-partial-sexp 1 curpos)
  7.2125+            (goto-char curpos)
  7.2126+            (setq literal (csharp-in-literal))
  7.2127+            (cond
  7.2128+
  7.2129+             ;; Case 1.A: it's a @ within a string.
  7.2130+             ;; --------------------------------------------
  7.2131+             ;; This should never happen, because this scanner hops over strings.
  7.2132+             ;; But it might happen if the scan starts at an odd place.
  7.2133+             ((eq literal 'string) nil)
  7.2134+
  7.2135+             ;; Case 1.B: The @ is within a comment.  Hop over it.
  7.2136+             ((and (memq literal '(c c++))
  7.2137+                   ;; This is a kludge for XEmacs where we use
  7.2138+                   ;; `buffer-syntactic-context', which doesn't correctly
  7.2139+                   ;; recognize "\*/" to end a block comment.
  7.2140+                   ;; `parse-partial-sexp' which is used by
  7.2141+                   ;; `c-literal-limits' will however do that in most
  7.2142+                   ;; versions, which results in that we get nil from
  7.2143+                   ;; `c-literal-limits' even when `c-in-literal' claims
  7.2144+                   ;; we're inside a comment.
  7.2145+                   ;;(setq limits (c-literal-limits start)))
  7.2146+                   (setq limits (c-literal-limits)))
  7.2147+
  7.2148+              ;; advance to the end of the comment
  7.2149+              (if limits
  7.2150+                  (progn
  7.2151+                    (csharp-log 4 "scan: jump end comment A (%d)" (cdr limits))
  7.2152+                    (setq curpos (cdr limits)))))
  7.2153+
  7.2154+
  7.2155+             ;; Case 1.B: curpos is at least 2 chars before the last
  7.2156+             ;; position to examine, and, the following char is a
  7.2157+             ;; double-quote (ASCII 34).
  7.2158+             ;; --------------------------------------------
  7.2159+             ;; This looks like the beginning of a verbatim string
  7.2160+             ;; literal.
  7.2161+             ((and (< (+ 2 curpos) lastpos)
  7.2162+                   (= ?\" (char-after (+ 1 curpos))))
  7.2163+
  7.2164+              (setq eos (csharp-end-of-verbatim-literal-string))
  7.2165+              ;; set override syntax properties on the verblit string
  7.2166+              (csharp-set-vliteral-syntax-table-properties curpos eos)
  7.2167+
  7.2168+              (csharp-log 4 "scan: jump end verblit string (%d)" eos)
  7.2169+              (setq curpos eos))))
  7.2170+
  7.2171+
  7.2172+           ;; Case 2: current char is a double-quote.
  7.2173+           ;; --------------------------------------------
  7.2174+           ;; If this is a string, we hop over it, on the assumption that
  7.2175+           ;; this scanner need not bother with regular literal strings, which
  7.2176+           ;; get the proper syntax with the generic approach.
  7.2177+           ;; If in a comment, hop over the comment.
  7.2178+           ((= ?\" (char-after curpos))
  7.2179+            (goto-char curpos)
  7.2180+            (setq literal (c-in-literal))
  7.2181+            (cond
  7.2182+
  7.2183+             ;; Case 2.A: a quote within a string
  7.2184+             ;; --------------------------------------------
  7.2185+             ;; This shouldn't happen, because we hop over strings.
  7.2186+             ;; But it might.
  7.2187+             ((eq literal 'string) nil)
  7.2188+
  7.2189+             ;; Case 2.B: a quote within a comment
  7.2190+             ;; --------------------------------------------
  7.2191+             ((and (memq literal '(c c++))
  7.2192+                   ;; This is a kludge for XEmacs where we use
  7.2193+                   ;; `buffer-syntactic-context', which doesn't correctly
  7.2194+                   ;; recognize "\*/" to end a block comment.
  7.2195+                   ;; `parse-partial-sexp' which is used by
  7.2196+                   ;; `c-literal-limits' will however do that in most
  7.2197+                   ;; versions, which results in that we get nil from
  7.2198+                   ;; `c-literal-limits' even when `c-in-literal' claims
  7.2199+                   ;; we're inside a comment.
  7.2200+                   ;;(setq limits (c-literal-limits start)))
  7.2201+                   (setq limits (c-literal-limits)))
  7.2202+
  7.2203+              ;; advance to the end of the comment
  7.2204+              (if limits
  7.2205+                  (progn
  7.2206+                    (setq curpos (cdr limits))
  7.2207+                    (csharp-log 3 "scan: jump end comment B (%s)" curpos))))
  7.2208+
  7.2209+
  7.2210+             ;; Case 2.C: Not in a comment, and not in a string.
  7.2211+             ;; --------------------------------------------
  7.2212+             ;; This is the beginning of a literal (but not verbatim) string.
  7.2213+             (t
  7.2214+              (forward-char 1) ;; pass up the quote
  7.2215+              (if (consp (setq limits (c-literal-limits)))
  7.2216+                  (progn
  7.2217+                    (csharp-log 4 "scan: jump end literal (%d)" (cdr limits))
  7.2218+                    (setq curpos (cdr limits))))))))
  7.2219+
  7.2220+          (setq cycle (+ 1 cycle))
  7.2221+          (setq curpos (+ 1 curpos))
  7.2222+          (c-safe (goto-char curpos)))))))
  7.2223+
  7.2224+
  7.2225+(defun csharp-before-font-lock (beg end old-len)
  7.2226+  "Adjust`syntax-table' properties on the region affected by the change
  7.2227+in a csharp-mode buffer.
  7.2228+
  7.2229+This function is the C# value for `c-before-font-lock-function'.
  7.2230+It intended to be called only by the cc-mode runtime.
  7.2231+
  7.2232+It prepares the buffer for font locking, hence must get called
  7.2233+before `font-lock-after-change-function'.
  7.2234+
  7.2235+It does hidden buffer changes.
  7.2236+
  7.2237+BEG, END and OLD-LEN have the same meaning here as for any
  7.2238+after-change function.
  7.2239+
  7.2240+Point is undefined both before and after this function call.
  7.2241+The return value is meaningless, and is ignored by cc-mode.
  7.2242+"
  7.2243+    (let ((start-scan (progn
  7.2244+                        (c-beginning-of-statement 1)
  7.2245+                        (point))))
  7.2246+      (csharp-scan-for-verbatim-literals-and-set-props start-scan end)))
  7.2247+
  7.2248+
  7.2249+
  7.2250+(c-lang-defconst c-before-font-lock-function
  7.2251+  csharp 'csharp-before-font-lock)
  7.2252+
  7.2253+;; ==================================================================
  7.2254+;; end of c# fontification extensions
  7.2255+;; ==================================================================
  7.2256+
  7.2257+
  7.2258+
  7.2259+
  7.2260+
  7.2261+;; ==================================================================
  7.2262+;; C#-specific optimizations of cc-mode funcs
  7.2263+;; ==================================================================
  7.2264+
  7.2265+
  7.2266+
  7.2267+;; There's never a need to move over an Obj-C directive in csharp-mode.
  7.2268+(defadvice c-forward-objc-directive (around
  7.2269+                                 csharp-mode-advice-2
  7.2270+                                 compile activate)
  7.2271+  (if (c-major-mode-is 'csharp-mode)
  7.2272+      nil
  7.2273+    ad-do-it)
  7.2274+  )
  7.2275+
  7.2276+;; ==================================================================
  7.2277+;; end of C#-specific optimizations of cc-mode funcs
  7.2278+;; ==================================================================
  7.2279+
  7.2280+
  7.2281+
  7.2282+
  7.2283+
  7.2284+
  7.2285+
  7.2286+
  7.2287+;; ==================================================================
  7.2288+;; c# - monkey-patching of basic parsing logic
  7.2289+;; ==================================================================
  7.2290+;;
  7.2291+;; The following 2 defuns redefine functions from cc-mode, to add
  7.2292+;; special cases for C#.  These primarily deal with indentation of
  7.2293+;; instance initializers, which are somewhat unique to C#.  I couldn't
  7.2294+;; figure out how to get cc-mode to do what C# needs, without modifying
  7.2295+;; these defuns.
  7.2296+;;
  7.2297+
  7.2298+(defun c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end)
  7.2299+  ;; Return non-nil if we're looking at the beginning of a block
  7.2300+  ;; inside an expression.  The value returned is actually a cons of
  7.2301+  ;; either 'inlambda, 'inexpr-statement or 'inexpr-class and the
  7.2302+  ;; position of the beginning of the construct.
  7.2303+  ;;
  7.2304+  ;; LIM limits the backward search.  CONTAINING-SEXP is the start
  7.2305+  ;; position of the closest containing list.  If it's nil, the
  7.2306+  ;; containing paren isn't used to decide whether we're inside an
  7.2307+  ;; expression or not.  If both LIM and CONTAINING-SEXP are used, LIM
  7.2308+  ;; needs to be farther back.
  7.2309+  ;;
  7.2310+  ;; If CHECK-AT-END is non-nil then extra checks at the end of the
  7.2311+  ;; brace block might be done.  It should only be used when the
  7.2312+  ;; construct can be assumed to be complete, i.e. when the original
  7.2313+  ;; starting position was further down than that.
  7.2314+  ;;
  7.2315+  ;; This function might do hidden buffer changes.
  7.2316+
  7.2317+  (save-excursion
  7.2318+    (let ((res 'maybe) passed-paren
  7.2319+          (closest-lim (or containing-sexp lim (point-min)))
  7.2320+          ;; Look at the character after point only as a last resort
  7.2321+          ;; when we can't disambiguate.
  7.2322+          (block-follows (and (eq (char-after) ?{) (point))))
  7.2323+
  7.2324+      (while (and (eq res 'maybe)
  7.2325+                  (progn (c-backward-syntactic-ws)
  7.2326+                         (> (point) closest-lim))
  7.2327+                  (not (bobp))
  7.2328+                  (progn (backward-char)
  7.2329+                         (looking-at "[\]\).]\\|\\w\\|\\s_"))
  7.2330+                  (c-safe (forward-char)
  7.2331+                          (goto-char (scan-sexps (point) -1))))
  7.2332+
  7.2333+        (setq res
  7.2334+              (if (looking-at c-keywords-regexp)
  7.2335+                  (let ((kw-sym (c-keyword-sym (match-string 1))))
  7.2336+                    (cond
  7.2337+                     ((and block-follows
  7.2338+                           (c-keyword-member kw-sym 'c-inexpr-class-kwds))
  7.2339+                      (and (not (eq passed-paren ?\[))
  7.2340+
  7.2341+                           ;; dinoch Thu, 22 Apr 2010  18:20
  7.2342+                           ;; ============================================
  7.2343+                           ;; looking at new MyType() { ... }
  7.2344+                           ;; means this is a brace list, so, return nil,
  7.2345+                           ;; implying NOT looking-at-inexpr-block
  7.2346+                           (not
  7.2347+                            (and (c-major-mode-is 'csharp-mode)
  7.2348+                                 (looking-at "new\s+\\([[:alnum:]_]+\\)\\b")))
  7.2349+
  7.2350+                           (or (not (looking-at c-class-key))
  7.2351+                               ;; If the class instantiation is at the start of
  7.2352+                               ;; a statement, we don't consider it an
  7.2353+                               ;; in-expression class.
  7.2354+                               (let ((prev (point)))
  7.2355+                                 (while (and
  7.2356+                                         (= (c-backward-token-2 1 nil closest-lim) 0)
  7.2357+                                         (eq (char-syntax (char-after)) ?w))
  7.2358+                                   (setq prev (point)))
  7.2359+                                 (goto-char prev)
  7.2360+                                 (not (c-at-statement-start-p)))
  7.2361+                               ;; Also, in Pike we treat it as an
  7.2362+                               ;; in-expression class if it's used in an
  7.2363+                               ;; object clone expression.
  7.2364+                               (save-excursion
  7.2365+                                 (and check-at-end
  7.2366+                                      (c-major-mode-is 'pike-mode)
  7.2367+                                      (progn (goto-char block-follows)
  7.2368+                                             (zerop (c-forward-token-2 1 t)))
  7.2369+                                      (eq (char-after) ?\())))
  7.2370+                           (cons 'inexpr-class (point))))
  7.2371+                     ((c-keyword-member kw-sym 'c-inexpr-block-kwds)
  7.2372+                      (when (not passed-paren)
  7.2373+                        (cons 'inexpr-statement (point))))
  7.2374+                     ((c-keyword-member kw-sym 'c-lambda-kwds)
  7.2375+                      (when (or (not passed-paren)
  7.2376+                                (eq passed-paren ?\())
  7.2377+                        (cons 'inlambda (point))))
  7.2378+                     ((c-keyword-member kw-sym 'c-block-stmt-kwds)
  7.2379+                      nil)
  7.2380+                     (t
  7.2381+                      'maybe)))
  7.2382+
  7.2383+                (if (looking-at "\\s(")
  7.2384+                    (if passed-paren
  7.2385+                        (if (and (eq passed-paren ?\[)
  7.2386+                                 (eq (char-after) ?\[))
  7.2387+                            ;; Accept several square bracket sexps for
  7.2388+                            ;; Java array initializations.
  7.2389+                            'maybe)
  7.2390+                      (setq passed-paren (char-after))
  7.2391+                      'maybe)
  7.2392+                  'maybe))))
  7.2393+
  7.2394+      (if (eq res 'maybe)
  7.2395+          (when (and c-recognize-paren-inexpr-blocks
  7.2396+                     block-follows
  7.2397+                     containing-sexp
  7.2398+                     (eq (char-after containing-sexp) ?\())
  7.2399+            (goto-char containing-sexp)
  7.2400+            (if (or (save-excursion
  7.2401+                      (c-backward-syntactic-ws lim)
  7.2402+                      (and (> (point) (or lim (point-min)))
  7.2403+                           (c-on-identifier)))
  7.2404+                    (and c-special-brace-lists
  7.2405+                         (c-looking-at-special-brace-list)))
  7.2406+                nil
  7.2407+              (cons 'inexpr-statement (point))))
  7.2408+
  7.2409+        res))))
  7.2410+
  7.2411+
  7.2412+
  7.2413+
  7.2414+
  7.2415+(defun c-inside-bracelist-p (containing-sexp paren-state)
  7.2416+  ;; return the buffer position of the beginning of the brace list
  7.2417+  ;; statement if we're inside a brace list, otherwise return nil.
  7.2418+  ;; CONTAINING-SEXP is the buffer pos of the innermost containing
  7.2419+  ;; paren.  PAREN-STATE is the remainder of the state of enclosing
  7.2420+  ;; braces
  7.2421+  ;;
  7.2422+  ;; N.B.: This algorithm can potentially get confused by cpp macros
  7.2423+  ;; placed in inconvenient locations.  It's a trade-off we make for
  7.2424+  ;; speed.
  7.2425+  ;;
  7.2426+  ;; This function might do hidden buffer changes.
  7.2427+  (or
  7.2428+   ;; This will pick up brace list declarations.
  7.2429+   (c-safe
  7.2430+    (save-excursion
  7.2431+      (goto-char containing-sexp)
  7.2432+      (c-safe (c-forward-sexp -1))
  7.2433+      (let (bracepos)
  7.2434+        (if (and (or (looking-at c-brace-list-key)
  7.2435+
  7.2436+                     (progn
  7.2437+                       (c-safe (c-forward-sexp -1))
  7.2438+                       (looking-at c-brace-list-key))
  7.2439+
  7.2440+                     ;; dinoch Thu, 22 Apr 2010  18:20
  7.2441+                     ;; ============================================
  7.2442+                     ;; looking enum Foo : int
  7.2443+                     ;; means this is a brace list, so, return nil,
  7.2444+                     ;; implying NOT looking-at-inexpr-block
  7.2445+
  7.2446+                     (and (c-major-mode-is 'csharp-mode)
  7.2447+                          (progn
  7.2448+                            (c-safe (c-forward-sexp -1))
  7.2449+                            (looking-at csharp-enum-decl-re))))
  7.2450+
  7.2451+                 (setq bracepos (c-down-list-forward (point)))
  7.2452+                 (not (c-crosses-statement-barrier-p (point)
  7.2453+                                                     (- bracepos 2))))
  7.2454+            (point)))))
  7.2455+
  7.2456+   ;; this will pick up array/aggregate init lists, even if they are nested.
  7.2457+   (save-excursion
  7.2458+     (let ((class-key
  7.2459+            ;; Pike can have class definitions anywhere, so we must
  7.2460+            ;; check for the class key here.
  7.2461+            (and (c-major-mode-is 'pike-mode)
  7.2462+                 c-decl-block-key))
  7.2463+           bufpos braceassignp lim next-containing)
  7.2464+       (while (and (not bufpos)
  7.2465+                   containing-sexp)
  7.2466+           (when paren-state
  7.2467+             (if (consp (car paren-state))
  7.2468+                 (setq lim (cdr (car paren-state))
  7.2469+                       paren-state (cdr paren-state))
  7.2470+               (setq lim (car paren-state)))
  7.2471+             (when paren-state
  7.2472+               (setq next-containing (car paren-state)
  7.2473+                     paren-state (cdr paren-state))))
  7.2474+           (goto-char containing-sexp)
  7.2475+           (if (c-looking-at-inexpr-block next-containing next-containing)
  7.2476+               ;; We're in an in-expression block of some kind.  Do not
  7.2477+               ;; check nesting.  We deliberately set the limit to the
  7.2478+               ;; containing sexp, so that c-looking-at-inexpr-block
  7.2479+               ;; doesn't check for an identifier before it.
  7.2480+               (setq containing-sexp nil)
  7.2481+             ;; see if the open brace is preceded by = or [...] in
  7.2482+             ;; this statement, but watch out for operator=
  7.2483+             (setq braceassignp 'dontknow)
  7.2484+             (c-backward-token-2 1 t lim)
  7.2485+             ;; Checks to do only on the first sexp before the brace.
  7.2486+             (when (and c-opt-inexpr-brace-list-key
  7.2487+                        (eq (char-after) ?\[))
  7.2488+               ;; In Java, an initialization brace list may follow
  7.2489+               ;; directly after "new Foo[]", so check for a "new"
  7.2490+               ;; earlier.
  7.2491+               (while (eq braceassignp 'dontknow)
  7.2492+                 (setq braceassignp
  7.2493+                       (cond ((/= (c-backward-token-2 1 t lim) 0) nil)
  7.2494+                             ((looking-at c-opt-inexpr-brace-list-key) t)
  7.2495+                             ((looking-at "\\sw\\|\\s_\\|[.[]")
  7.2496+                              ;; Carry on looking if this is an
  7.2497+                              ;; identifier (may contain "." in Java)
  7.2498+                              ;; or another "[]" sexp.
  7.2499+                              'dontknow)
  7.2500+                             (t nil)))))
  7.2501+             ;; Checks to do on all sexps before the brace, up to the
  7.2502+             ;; beginning of the statement.
  7.2503+             (while (eq braceassignp 'dontknow)
  7.2504+               (cond ((eq (char-after) ?\;)
  7.2505+                      (setq braceassignp nil))
  7.2506+                     ((and class-key
  7.2507+                           (looking-at class-key))
  7.2508+                      (setq braceassignp nil))
  7.2509+                     ((eq (char-after) ?=)
  7.2510+                      ;; We've seen a =, but must check earlier tokens so
  7.2511+                      ;; that it isn't something that should be ignored.
  7.2512+                      (setq braceassignp 'maybe)
  7.2513+                      (while (and (eq braceassignp 'maybe)
  7.2514+                                  (zerop (c-backward-token-2 1 t lim)))
  7.2515+                        (setq braceassignp
  7.2516+                              (cond
  7.2517+                               ;; Check for operator =
  7.2518+                               ((and c-opt-op-identifier-prefix
  7.2519+                                     (looking-at c-opt-op-identifier-prefix))
  7.2520+                                nil)
  7.2521+                               ;; Check for `<opchar>= in Pike.
  7.2522+                               ((and (c-major-mode-is 'pike-mode)
  7.2523+                                     (or (eq (char-after) ?`)
  7.2524+                                         ;; Special case for Pikes
  7.2525+                                         ;; `[]=, since '[' is not in
  7.2526+                                         ;; the punctuation class.
  7.2527+                                         (and (eq (char-after) ?\[)
  7.2528+                                              (eq (char-before) ?`))))
  7.2529+                                nil)
  7.2530+                               ((looking-at "\\s.") 'maybe)
  7.2531+                               ;; make sure we're not in a C++ template
  7.2532+                               ;; argument assignment
  7.2533+                               ((and
  7.2534+                                 (c-major-mode-is 'c++-mode)
  7.2535+                                 (save-excursion
  7.2536+                                   (let ((here (point))
  7.2537+                                         (pos< (progn
  7.2538+                                                 (skip-chars-backward "^<>")
  7.2539+                                                 (point))))
  7.2540+                                     (and (eq (char-before) ?<)
  7.2541+                                          (not (c-crosses-statement-barrier-p
  7.2542+                                                pos< here))
  7.2543+                                          (not (c-in-literal))
  7.2544+                                          ))))
  7.2545+                                nil)
  7.2546+                               (t t))))))
  7.2547+               (if (and (eq braceassignp 'dontknow)
  7.2548+                        (/= (c-backward-token-2 1 t lim) 0))
  7.2549+                   (setq braceassignp nil)))
  7.2550+             (if (not braceassignp)
  7.2551+                 (if (eq (char-after) ?\;)
  7.2552+                     ;; Brace lists can't contain a semicolon, so we're done.
  7.2553+                     (setq containing-sexp nil)
  7.2554+                   ;; Go up one level.
  7.2555+                   (setq containing-sexp next-containing
  7.2556+                         lim nil
  7.2557+                         next-containing nil))
  7.2558+               ;; we've hit the beginning of the aggregate list
  7.2559+               (c-beginning-of-statement-1
  7.2560+                (c-most-enclosing-brace paren-state))
  7.2561+               (setq bufpos (point))))
  7.2562+           )
  7.2563+       bufpos))
  7.2564+   ))
  7.2565+
  7.2566+;; ==================================================================
  7.2567+;; end of monkey-patching of basic parsing logic
  7.2568+;; ==================================================================
  7.2569+
  7.2570+
  7.2571+
  7.2572+
  7.2573+;;(easy-menu-define csharp-menu csharp-mode-map "C# Mode Commands"
  7.2574+;;                ;; Can use `csharp' as the language for `c-mode-menu'
  7.2575+;;                ;; since its definition covers any language.  In
  7.2576+;;                ;; this case the language is used to adapt to the
  7.2577+;;                ;; nonexistence of a cpp pass and thus removing some
  7.2578+;;                ;; irrelevant menu alternatives.
  7.2579+;;                (cons "C#" (c-lang-const c-mode-menu csharp)))
  7.2580+
  7.2581+;;; Autoload mode trigger
  7.2582+;;;###autoload
  7.2583+(add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode))
  7.2584+
  7.2585+
  7.2586+
  7.2587+(c-add-style "C#"
  7.2588+ '("Java"
  7.2589+   (c-basic-offset . 4)
  7.2590+   (c-comment-only-line-offset . (0 . 0))
  7.2591+   (c-offsets-alist . (
  7.2592+       (access-label          . -)
  7.2593+       (arglist-close         . c-lineup-arglist)
  7.2594+       (arglist-cont          . 0)
  7.2595+       (arglist-cont-nonempty . c-lineup-arglist)
  7.2596+       (arglist-intro         . c-lineup-arglist-intro-after-paren)
  7.2597+       (block-close           . 0)
  7.2598+       (block-open            . 0)
  7.2599+       (brace-entry-open      . 0)
  7.2600+       (brace-list-close      . 0)
  7.2601+       (brace-list-entry      . 0)
  7.2602+       (brace-list-intro      . +)
  7.2603+       (brace-list-open       . +)
  7.2604+       (c                     . c-lineup-C-comments)
  7.2605+       (case-label            . +)
  7.2606+       (catch-clause          . 0)
  7.2607+       (class-close           . 0)
  7.2608+       (class-open            . 0)
  7.2609+       (comment-intro         . c-lineup-comment)
  7.2610+       (cpp-macro             . 0)
  7.2611+       (cpp-macro-cont        . c-lineup-dont-change)
  7.2612+       (defun-block-intro     . +)
  7.2613+       (defun-close           . 0)
  7.2614+       (defun-open            . 0)
  7.2615+       (do-while-closure      . 0)
  7.2616+       (else-clause           . 0)
  7.2617+       (extern-lang-close     . 0)
  7.2618+       (extern-lang-open      . 0)
  7.2619+       (friend                . 0)
  7.2620+       (func-decl-cont        . +)
  7.2621+       (inclass               . +)
  7.2622+       (inexpr-class          . +)
  7.2623+       (inexpr-statement      . 0)
  7.2624+       (inextern-lang         . +)
  7.2625+       (inher-cont            . c-lineup-multi-inher)
  7.2626+       (inher-intro           . +)
  7.2627+       (inlambda              . c-lineup-inexpr-block)
  7.2628+       (inline-close          . 0)
  7.2629+       (inline-open           . 0)
  7.2630+       (innamespace           . +)
  7.2631+       (knr-argdecl           . 0)
  7.2632+       (knr-argdecl-intro     . 5)
  7.2633+       (label                 . 0)
  7.2634+       (lambda-intro-cont     . +)
  7.2635+       (member-init-cont      . c-lineup-multi-inher)
  7.2636+       (member-init-intro     . +)
  7.2637+       (namespace-close       . 0)
  7.2638+       (namespace-open        . 0)
  7.2639+       (statement             . 0)
  7.2640+       (statement-block-intro . +)
  7.2641+       (statement-case-intro  . +)
  7.2642+       (statement-case-open   . +)
  7.2643+       (statement-cont        . +)
  7.2644+       (stream-op             . c-lineup-streamop)
  7.2645+       (string                . c-lineup-dont-change)
  7.2646+       (substatement          . +)
  7.2647+       (substatement-open     . 0)
  7.2648+       (template-args-cont c-lineup-template-args +)
  7.2649+       (topmost-intro         . 0)
  7.2650+       (topmost-intro-cont    . +)
  7.2651+       ))
  7.2652+   ))
  7.2653+
  7.2654+
  7.2655+
  7.2656+
  7.2657+;; Custom variables
  7.2658+;;;###autoload
  7.2659+(defcustom csharp-mode-hook nil
  7.2660+  "*Hook called by `csharp-mode'."
  7.2661+  :type 'hook
  7.2662+  :group 'c)
  7.2663+
  7.2664+
  7.2665+
  7.2666+;;; The entry point into the mode
  7.2667+;;;###autoload
  7.2668+(defun csharp-mode ()
  7.2669+  "Major mode for editing C# code. This mode is derived from CC Mode to
  7.2670+support C#.
  7.2671+
  7.2672+The hook `c-mode-common-hook' is run with no args at mode
  7.2673+initialization, then `csharp-mode-hook'.
  7.2674+
  7.2675+This mode will automatically add a symbol and regexp to the
  7.2676+`compilation-error-regexp-alist' and `compilation-error-regexp-alist-alist'
  7.2677+respectively, for Csc.exe error and warning messages.
  7.2678+
  7.2679+Key bindings:
  7.2680+\\{csharp-mode-map}"
  7.2681+  (interactive)
  7.2682+  (kill-all-local-variables)
  7.2683+  (make-local-variable 'beginning-of-defun-function)
  7.2684+  (make-local-variable 'end-of-defun-function)
  7.2685+  (c-initialize-cc-mode t)
  7.2686+  (set-syntax-table csharp-mode-syntax-table)
  7.2687+
  7.2688+  ;; define underscore as part of a word in the Csharp syntax table
  7.2689+  (modify-syntax-entry ?_ "w" csharp-mode-syntax-table)
  7.2690+
  7.2691+  ;; define @ as an expression prefix in Csharp syntax table
  7.2692+  (modify-syntax-entry ?@ "'" csharp-mode-syntax-table)
  7.2693+
  7.2694+  (setq major-mode 'csharp-mode
  7.2695+        mode-name "C#"
  7.2696+        local-abbrev-table csharp-mode-abbrev-table
  7.2697+        abbrev-mode t)
  7.2698+  (use-local-map csharp-mode-map)
  7.2699+
  7.2700+  ;; `c-init-language-vars' is a macro that is expanded at compile
  7.2701+  ;; time to a large `setq' with all the language variables and their
  7.2702+  ;; customized values for our language.
  7.2703+  (c-init-language-vars csharp-mode)
  7.2704+
  7.2705+
  7.2706+  ;; `c-common-init' initializes most of the components of a CC Mode
  7.2707+  ;; buffer, including setup of the mode menu, font-lock, etc.
  7.2708+  ;; There's also a lower level routine `c-basic-common-init' that
  7.2709+  ;; only makes the necessary initialization to get the syntactic
  7.2710+  ;; analysis and similar things working.
  7.2711+  (c-common-init 'csharp-mode)
  7.2712+
  7.2713+  ;; csc.exe, the C# Compiler, produces errors like this:
  7.2714+  ;; file.cs(6,18): error CS1006: Name of constructor must match name of class
  7.2715+  (if (boundp 'compilation-error-regexp-alist-alist)
  7.2716+      (progn
  7.2717+        (add-to-list
  7.2718+         'compilation-error-regexp-alist-alist
  7.2719+         '(ms-csharp "^[ \t]*\\([A-Za-z0-9_][^(]*\\.cs\\)(\\([0-9]+\\)[,]\\([0-9]+\\)) ?: \\(error\\|warning\\) CS[0-9]+:" 1 2 3))
  7.2720+        (add-to-list
  7.2721+         'compilation-error-regexp-alist
  7.2722+         'ms-csharp)))
  7.2723+
  7.2724+
  7.2725+  ;; to allow next-error to work with csc.exe:
  7.2726+  (setq compilation-scroll-output t)
  7.2727+
  7.2728+
  7.2729+  (local-set-key (kbd "/") 'csharp-maybe-insert-codedoc)
  7.2730+  (local-set-key (kbd "{") 'csharp-insert-open-brace)
  7.2731+
  7.2732+
  7.2733+  ;; Need the following for parse-partial-sexp to work properly with
  7.2734+  ;; verbatim literal strings Setting this var to non-nil tells
  7.2735+  ;; `parse-partial-sexp' to pay attention to the syntax text
  7.2736+  ;; properties on the text in the buffer.  If csharp-mode attaches
  7.2737+  ;; text syntax to @"..." then, `parse-partial-sexp' will treat those
  7.2738+  ;; strings accordingly.
  7.2739+  (set (make-local-variable 'parse-sexp-lookup-properties)
  7.2740+       t)
  7.2741+
  7.2742+  ;; scan the entire buffer for verblit strings
  7.2743+  (csharp-scan-for-verbatim-literals-and-set-props nil nil)
  7.2744+
  7.2745+  (c-run-mode-hooks 'c-mode-common-hook 'csharp-mode-hook)
  7.2746+
  7.2747+  ;; Allow fill-paragraph to work on xml code doc
  7.2748+  ;; This setting gets overwritten quietly by c-run-mode-hooks,
  7.2749+  ;; so I put it afterwards to make it stick.
  7.2750+  (make-local-variable 'paragraph-separate)
  7.2751+  (setq paragraph-separate
  7.2752+       "[ \t]*\\(//+\\|\\**\\)\\([ \t]+\\|[ \t]+<.+?>\\)$\\|^\f")
  7.2753+
  7.2754+  ;;(message "C#: set paragraph-separate")
  7.2755+
  7.2756+  ;; Speedbar handling
  7.2757+  (if (fboundp 'speedbar-add-supported-extension)
  7.2758+      (speedbar-add-supported-extension '(".cs"))) ;; idempotent
  7.2759+
  7.2760+  (c-update-modeline))
  7.2761+
  7.2762+
  7.2763+
  7.2764+(message  (concat "Done loading " load-file-name))
  7.2765+
  7.2766+
  7.2767+(provide 'csharp-mode)
  7.2768+
  7.2769+;;; csharp-mode.el ends here
     8.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2+++ b/csharp-mode/csharp-shell.el	Wed Nov 10 15:19:03 2010 +0200
     8.3@@ -0,0 +1,363 @@
     8.4+;;; csharp-shell.el --- run PowerShell to assist with c# completion.
     8.5+;;
     8.6+;; Author:     Dino Chiesa <dpchiesa@hotmail.com>
     8.7+;; Created:    10 Apr 2008
     8.8+;; Modified:   May 2010
     8.9+;; Version:    0.2
    8.10+;; Keywords:   powershell C# shell
    8.11+;; X-URL:      ??
    8.12+;;
    8.13+
    8.14+;;; Commentary:
    8.15+;;
    8.16+;;   This is code that provides an emacs shell that supports C# code-completion.
    8.17+;;   It depends on Powershell.el.  It is part of cscomp.  (C# completion).
    8.18+;;
    8.19+;;
    8.20+;;   csharp-shell.el is responsible for starting a
    8.21+;;   PowerShell shell, and loading a custom utility assembly into it.
    8.22+;;   The running shell can be used as a regular, interactive powershell shell, but its
    8.23+;;   primary purpose is to connect elisp to the .NET assembly that
    8.24+;;   performs reflection.
    8.25+;;
    8.26+;;   When the user requests completion on a variable (etc), logic within
    8.27+;;   csharp-completion.el sends a command to the CscompShell, and gets the
    8.28+;;   response, in the form of a lisp s-expression.  The logic in
    8.29+;;   csharp-completion.el then evals that sexp, and does something
    8.30+;;   intelligent with the result.
    8.31+;;
    8.32+;;   The two main public interfaces for this module are:
    8.33+;;
    8.34+;;    `csharp-shell-exec-and-eval-result'
    8.35+;;    `csharp-shell-exec-and-maybe-eval-result'
    8.36+;;
    8.37+;;
    8.38+;;   Some History:
    8.39+;;   idea of CSDE, the C# Development Environment, was initially
    8.40+;;   conceived by Matt Bruce in 2001 (or so), and ported from JDE, the
    8.41+;;   Java Development Environment.
    8.42+;;
    8.43+;;   But the ambitious vision of CSDE was never completed. The latest
    8.44+;;   version is aparently still available on sourceforge, but it was
    8.45+;;   never updated or maintained.  <URL:http://www.sourceforge.com/>.
    8.46+;;
    8.47+;;   Rather than start with "everything", I thought I'd start by
    8.48+;;   producing a module that did  one thing well: code completion.
    8.49+;;   This is known as Intellisense in Microsoft's Visual Studio.
    8.50+;;
    8.51+;;   To do this, I didn't keep any of the old CSDE code. I kept only the
    8.52+;;   *idea* of code completion, relying on the use of a shell.
    8.53+;;
    8.54+;;   ------------
    8.55+;;
    8.56+;;   Please send any comments, bugs, or upgrade requests to
    8.57+;;   Dino Chiesa (dpchiesa@hotmail.com)
    8.58+;;
    8.59+
    8.60+
    8.61+(require 'powershell)
    8.62+
    8.63+(defcustom csharp-shell-location-of-util-dll  nil
    8.64+  "Folder name that contains the Cscomp DLL for C# Completion.
    8.65+Set this to nil, to load the DLL named CscompUtilities.dll from
    8.66+the same directory where csharp-shell.el is located.
    8.67+
    8.68+Otherwise, set it to a fully-qualified path of a directory that contains
    8.69+the file cscompUtilities.dll.  For example,
    8.70+
    8.71+      \"c:\\users\\fred\\elisp\\cscomp\"
    8.72+
    8.73+"
    8.74+  :group 'cscomp
    8.75+  :type 'string)
    8.76+
    8.77+(defcustom csharp-shell-startup-timeout 20
    8.78+  "*Length of time the CSharpShell waits for the shell process to startup.
    8.79+Increase the value of this variable if you get Lisp errors
    8.80+on Shell startup."
    8.81+  :group 'cscomp
    8.82+  :type 'integer)
    8.83+
    8.84+(defcustom csharp-shell-exec-timeout 9
    8.85+  "*Length of time in seconds to wait for the CscompShell to respond to commands
    8.86+before giving up and signaling an error.  This isn't the total timeout; it's
    8.87+the time to wait between chunks of response. "
    8.88+  :group 'cscomp
    8.89+  :type 'integer)
    8.90+
    8.91+(defcustom csharp-shell-buffer-name "*CscompShell*"
    8.92+  "Name of the Powershell buffer for C# completion support."
    8.93+  :group 'cscomp
    8.94+  :type 'string
    8.95+  )
    8.96+
    8.97+(defconst csharp-shell-prompt-string "CscompShell % "
    8.98+  "The prompt string used for csharp-shell.  It is also used as a regex, so this string must contain no regex-sensitive sequences. Best to just leave it alone.")
    8.99+
   8.100+
   8.101+(defvar cscomp-log-level 0
   8.102+  "The current log level for C# completion operations.  0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG. ")
   8.103+
   8.104+
   8.105+(defun cscomp-log (level text &rest args)
   8.106+  "Log a message at level LEVEL.
   8.107+If LEVEL is higher than `cscomp-log-level', the message is
   8.108+ignored.  Otherwise, it is printed using `message'.
   8.109+TEXT is a format control string, and the remaining arguments ARGS
   8.110+are the string substitutions (see `format')."
   8.111+  (if (<= level cscomp-log-level)
   8.112+      (let* ((msg (apply 'format text args)))
   8.113+        (message "%s" msg)
   8.114+        )))
   8.115+
   8.116+
   8.117+(defun csharp-shell ()
   8.118+  "Starts CsharpShell, which is an instance of Powershell that loads
   8.119+a custom assembly dedicated to supporting C# code completion in emacs.
   8.120+"
   8.121+  (interactive)
   8.122+  (csharp-shell--internal nil)
   8.123+  )
   8.124+
   8.125+
   8.126+
   8.127+(defun csharp-shell--internal (&optional display-buffer)
   8.128+  (if (not (comint-check-proc csharp-shell-buffer-name))
   8.129+      ;; then
   8.130+      (let (version)
   8.131+        (message "Starting CscompShell...")
   8.132+        (setq version (csharp-shell--start))
   8.133+        (message "CscompShell v%s is now running..." version)
   8.134+       )
   8.135+    ;; else
   8.136+    (when display-buffer
   8.137+      (message "CscompShell is already running."))
   8.138+    )
   8.139+  )
   8.140+
   8.141+
   8.142+;; (defvar csharp-shell--reply nil
   8.143+;;   "Internal use only.")
   8.144+
   8.145+
   8.146+
   8.147+(defun csharp-shell-exec-and-maybe-eval-result (expr &optional eval-return)
   8.148+  "Sends EXPR to the CscompShell.  EXPR could theoretically be
   8.149+any valid Powershell command, but this fn is invoked from
   8.150+csharp-completion, the EXPR is a call to static function in the
   8.151+CscompUtilities.dll assembly.
   8.152+
   8.153+If the shell is not already running, this function starts
   8.154+it. Collects the text output from the shell.  If the optional
   8.155+argument EVAL-RETURN is non-nil, this function returns the result
   8.156+of evaluating the output as a Lisp expression. Otherwise, the
   8.157+return value is the collected text.
   8.158+"
   8.159+  (let ((proc
   8.160+         (or (get-buffer-process csharp-shell-buffer-name)
   8.161+             (let (proc2)
   8.162+               (csharp-shell--internal)
   8.163+               (setq proc2 (get-buffer-process csharp-shell-buffer-name))
   8.164+               proc2))))
   8.165+
   8.166+    (if proc
   8.167+        (let (reply tmp)
   8.168+
   8.169+          (with-current-buffer csharp-shell-buffer-name
   8.170+            (cscomp-log 2 "csharp-shell-exec: Sending: %s" expr)
   8.171+            (setq reply
   8.172+                  (powershell-invoke-command-silently proc expr csharp-shell-exec-timeout)))
   8.173+
   8.174+
   8.175+          (if (or (null reply)
   8.176+                  (string-match "// Error:" reply))
   8.177+              (progn
   8.178+                (cscomp-log 1
   8.179+                          "csharp-shell-exec: CscompShell command error.\n  Expression: %s\n  Error: %s"
   8.180+                          expr reply)
   8.181+                (error "CscompShell eval error. See messages buffer for details.")))
   8.182+
   8.183+
   8.184+          (if eval-return
   8.185+              (if (and reply (not (string= reply "")))
   8.186+                  (progn
   8.187+                    (cscomp-log 2 "csharp-shell-exec: evaluating reply: '%s'" reply)
   8.188+
   8.189+                    (setq tmp (read reply)) ;; get one s-exp
   8.190+                    (if (not (eq tmp "CscompShell")) ;; means no response at all
   8.191+
   8.192+                        (progn
   8.193+                          (setq tmp (eval tmp))
   8.194+                          (cscomp-log 2 "csharp-shell-exec: eval result(%s)" (prin1-to-string tmp)) ;; can be nil
   8.195+                          tmp)
   8.196+                      nil))
   8.197+
   8.198+                ;; else
   8.199+                (progn
   8.200+                  (cscomp-log 1 "csharp-shell-exec: result is empty. Will not evaluate.")
   8.201+                  nil))
   8.202+
   8.203+            ;; else (no eval)
   8.204+            (progn
   8.205+              (cscomp-log 1 "csharp-shell-exec: no eval, reply: '%s'" reply)
   8.206+              reply))))))
   8.207+
   8.208+
   8.209+
   8.210+
   8.211+
   8.212+
   8.213+(defun csharp-shell-exec-and-eval-result (psh-statement)
   8.214+  "Convenience function for evaluating Powershell statements
   8.215+that return Lisp expressions as output. This function
   8.216+invokes csharp-shell-exec with the evaluate-return option set to
   8.217+t."
   8.218+  (csharp-shell-exec-and-maybe-eval-result psh-statement t))
   8.219+
   8.220+
   8.221+
   8.222+
   8.223+;; ;; dinoch - Thu, 20 May 2010  14:59
   8.224+;; ;;
   8.225+;; ;; TODO: now I cannot remember why this is here. Do I need to explicitly
   8.226+;; ;; override the shell function?  Must check this.
   8.227+;;
   8.228+;; (defun shell (&optional buffer)
   8.229+;;   "Run an inferior shell, with I/O through BUFFER (which defaults to `*shell*').
   8.230+;; Interactively, a prefix arg means to prompt for BUFFER.
   8.231+;; If BUFFER exists but shell process is not running, make new shell.
   8.232+;; If BUFFER exists and shell process is running, just switch to BUFFER.
   8.233+;; Program used comes from variable `explicit-shell-file-name',
   8.234+;;  or (if that is nil) from the ESHELL environment variable,
   8.235+;;  or (if that is nil) from `shell-file-name'.
   8.236+;; If a file `~/.emacs_SHELLNAME' exists, or `~/.emacs.d/init_SHELLNAME.sh',
   8.237+;; it is given as initial input (but this may be lost, due to a timing
   8.238+;; error, if the shell discards input when it starts up).
   8.239+;; The buffer is put in Shell mode, giving commands for sending input
   8.240+;; and controlling the subjobs of the shell.  See `shell-mode'.
   8.241+;; See also the variable `shell-prompt-pattern'.
   8.242+;;
   8.243+;; To specify a coding system for converting non-ASCII characters
   8.244+;; in the input and output to the shell, use \\[universal-coding-system-argument]
   8.245+;; before \\[shell].  You can also specify this with \\[set-buffer-process-coding-system]
   8.246+;; in the shell buffer, after you start the shell.
   8.247+;; The default comes from `process-coding-system-alist' and
   8.248+;; `default-process-coding-system'.
   8.249+;;
   8.250+;; The shell file name (sans directories) is used to make a symbol name
   8.251+;; such as `explicit-csh-args'.  If that symbol is a variable,
   8.252+;; its value is used as a list of arguments when invoking the shell.
   8.253+;; Otherwise, one argument `-i' is passed to the shell.
   8.254+;;
   8.255+;; \(Type \\[describe-mode] in the shell buffer for a list of commands.)"
   8.256+;;   (interactive
   8.257+;;    (list
   8.258+;;     (and current-prefix-arg
   8.259+;;          (read-buffer "Shell buffer: "
   8.260+;;                       (generate-new-buffer-name "*shell*")))))
   8.261+;;   (setq buffer (get-buffer-create (or buffer "*shell*")))
   8.262+;;   ;; Pop to buffer, so that the buffer's window will be correctly set
   8.263+;;   ;; when we call comint (so that comint sets the COLUMNS env var properly).
   8.264+;;   (pop-to-buffer buffer)
   8.265+;;   (unless (comint-check-proc buffer)
   8.266+;;     (let* ((prog (or explicit-shell-file-name
   8.267+;;                      (getenv "ESHELL") shell-file-name))
   8.268+;;            (name (file-name-nondirectory prog))
   8.269+;;            (startfile (concat "~/.emacs_" name))
   8.270+;;            (xargs-name (intern-soft (concat "explicit-" name "-args"))))
   8.271+;;
   8.272+;;       (unless (file-exists-p startfile)
   8.273+;;         (setq startfile (concat "~/.emacs.d/init_" name ".sh")))
   8.274+;;       (apply 'make-comint-in-buffer "shell" buffer prog
   8.275+;;              (if (file-exists-p startfile) startfile)
   8.276+;;              (if (and xargs-name (boundp xargs-name))
   8.277+;;                  (symbol-value xargs-name)
   8.278+;;                '("-i")))
   8.279+;;       (shell-mode)))
   8.280+;;   buffer)
   8.281+
   8.282+
   8.283+
   8.284+(defun csharp-shell--start ()
   8.285+  "Run a special instance of PowerShell in support of C# Completion, by invoking the `powershell' function.  The buffer containing the shell is named `csharp-shell-buffer-name'.
   8.286+"
   8.287+
   8.288+  (let* ((cscompshell-buffer (powershell
   8.289+                            csharp-shell-buffer-name
   8.290+                            csharp-shell-prompt-string))
   8.291+         (proc (get-buffer-process cscompshell-buffer))
   8.292+         (dll-location (concat
   8.293+                        (or
   8.294+                         csharp-shell-location-of-util-dll
   8.295+                         "idontknow" )
   8.296+                         "\\CscompUtilities.dll" ))
   8.297+         result
   8.298+         version)
   8.299+
   8.300+    (if proc
   8.301+        (progn
   8.302+          ;; Don't need to call save-excursion here, because
   8.303+          ;; powershell has already called pop-to-buffer .
   8.304+          ;; The CscompShell is the current buffer, and all
   8.305+          ;; the buffer-local variables are available.
   8.306+
   8.307+          ;; load the CscompUtilities DLL .
   8.308+
   8.309+          (setq result
   8.310+                (powershell-invoke-command-silently
   8.311+                 proc
   8.312+                 (concat "[System.Reflection.Assembly]::LoadFrom('" dll-location "')")
   8.313+                 6.5))
   8.314+
   8.315+          (if (string-match "^Exception .*: \"\\(.+\\)\"" result)
   8.316+              (let ((message (substring result (match-beginning 1) (match-end 1))))
   8.317+              (error (concat "error: " message))))
   8.318+
   8.319+
   8.320+          ;; get the version number
   8.321+          (setq version
   8.322+                (powershell-invoke-command-silently
   8.323+                 proc
   8.324+                 "[Ionic.Cscomp.Utilities]::Version()"
   8.325+                 2.9))
   8.326+
   8.327+          (if version
   8.328+              (setq version (substring version 1 -1)))
   8.329+
   8.330+          ;; If the user exits, we won't ask whether he wants to kill the CscompShell.
   8.331+          (set-process-query-on-exit-flag proc nil)
   8.332+
   8.333+          ;;(comint-simple-send proc "prompt\n") ;; shouldn't need this
   8.334+
   8.335+          ;; Send an initial carriage-return.  The effect is to make the
   8.336+          ;; prompt appear. I don't know why this is necessary here.
   8.337+          ;; It's called in the powershell function, but somehow it has
   8.338+          ;; no effect, when powershell is invoked from csharp-shell, so I
   8.339+          ;; also call it here.
   8.340+          (comint-send-input)
   8.341+          (accept-process-output proc)
   8.342+
   8.343+          ;; Remove the window for the shell.
   8.344+          ;; shell.el automatically pops to the shell buffer, but we
   8.345+          ;; don't want that in this case.  For Cscomp, the shell runs unseen,
   8.346+          ;; in the background. User can pop to it, if he likes.
   8.347+          (delete-window)
   8.348+
   8.349+          )
   8.350+      )
   8.351+
   8.352+    ;; return the version of the CscompUtilities.dll
   8.353+    version))
   8.354+
   8.355+
   8.356+;; Set the default DLL location at load time,
   8.357+;; if appropriate.
   8.358+(or
   8.359+ csharp-shell-location-of-util-dll
   8.360+ (setq csharp-shell-location-of-util-dll
   8.361+       (file-name-directory load-file-name)))
   8.362+
   8.363+
   8.364+(provide 'csharp-shell)
   8.365+
   8.366+;; End of csharp-shell.el
     9.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2+++ b/csharp-mode/flymake-for-csharp.el	Wed Nov 10 15:19:03 2010 +0200
     9.3@@ -0,0 +1,927 @@
     9.4+;;; flymake-for-csharp.el --- C# mode derived mode
     9.5+;;
     9.6+;; Author:     Dino Chiesa
     9.7+;; Version:    1.2
     9.8+;; Modified:   2010 May 10
     9.9+;; Keywords:   c# flymake
    9.10+;;
    9.11+;; This code is distributed under the MS-Public License.
    9.12+;; See http://opensource.org/licenses/ms-pl.html
    9.13+;;
    9.14+;; last saved
    9.15+;; Time-stamp: <2010-May-11 14:33:13>
    9.16+
    9.17+
    9.18+;; ==================================================================
    9.19+;;
    9.20+;; This module provides tweaks to the flymake minor mode, to allow it to
    9.21+;; work with csharp.
    9.22+;;
    9.23+;; Flymake is built-in to emacs.  It periodically compiles an active
    9.24+;; buffer when the minor mode is enabled, and then flags or highlights
    9.25+;; lines that cause errors or warnings during the compile as you
    9.26+;; edit. It is analogous to the red-squigglies you get in Visual Studio,
    9.27+;; highlighting syntax errors or other compile problems.
    9.28+;;
    9.29+;; This elisp module defines a set of tweaks of flymake, to allow it to
    9.30+;; work with C# on Windows.  flymake-for-csharp depends on a makefile or
    9.31+;; msbuild file of well-known name, with some well-known settings, in
    9.32+;; order to work.  These are documented below.
    9.33+;;
    9.34+;; ==================================================================
    9.35+;;
    9.36+;; To use:
    9.37+;;
    9.38+;; 1. put flymake-for-csharp.el on your load path.
    9.39+;;
    9.40+;; 2. somewhere in your .emacs, place this:
    9.41+;;       (require 'flymake-for-csharp)
    9.42+;;
    9.43+;; 3. Add this to your csharp-mode-hook function:
    9.44+;;       (flymake-mode)
    9.45+;;
    9.46+;; 4. specify how you want to use flymake, via these variables:
    9.47+;;
    9.48+;;     flymake-for-csharp-netsdk-location
    9.49+;;     flymake-for-csharp-dotnet-location
    9.50+;;     flymake-for-csharp-buildfile-alist
    9.51+;;     flymake-for-csharp-grep-pgm
    9.52+;;     flymake-for-csharp-csc-arguments
    9.53+;;
    9.54+;;
    9.55+;;    ...and by possibly adding special check-syntax targets in
    9.56+;;    your makefile or msbuild file.
    9.57+;;
    9.58+;; Full details are provided  below.
    9.59+;;
    9.60+;;
    9.61+;; Intro:
    9.62+;;
    9.63+;; Flymake is a language-neutral mode that periodically invokes a
    9.64+;; source-code compiler to check the syntax of the currently-
    9.65+;; being-edited buffer.
    9.66+;;
    9.67+;; flymake-for-csharp is a C#-specific extension of flymake-mode, and
    9.68+;; provides the logic for invoking the C# compiler to do the syntax
    9.69+;; check on the currently-being-edited buffer.
    9.70+;;
    9.71+;;
    9.72+;; When the flymake mode timer fires, it calls into the
    9.73+;; flymake-for-csharp logic.  flymake-for-csharp copies the contents of
    9.74+;; the current C# buffer to a temporary source file, then invokes the C#
    9.75+;; compiler on that temporary source file.  flymake-for-csharp can do
    9.76+;; this in one of 3 ways:
    9.77+;;
    9.78+;; - using the csc.exe compiler directly;
    9.79+;; - using a makefile and invoking nmake
    9.80+;; - using a msbuild file and invoking msbuild.exe
    9.81+;;
    9.82+;;
    9.83+;; Which option you choose depends on your requirements.  If the .cs
    9.84+;; file you're editing is a standalone module, you can compile it with a
    9.85+;; simple invocation of csc.exe.  If the module being edited must be
    9.86+;; compiled with other source modules in order to compile correctly, you
    9.87+;; will use nmake or msbuild, as you prefer.
    9.88+;;
    9.89+;; To allow flymake-for-csharp to work with either the nmake or msbuild
    9.90+;; options, you need to specify a particular well-known target in your
    9.91+;; makefile, or in your msbuild file.
    9.92+;;
    9.93+;; Now, how to select the compile option:
    9.94+;;
    9.95+;;
    9.96+;; Option A: use the csc.exe compiler directly
    9.97+;; ============================================
    9.98+;;
    9.99+;; This is the simplest option, and also the most limited. With this
   9.100+;; option, flymake-for-csharp compiles the copy of the existing buffer
   9.101+;; using the csc.exe command-line compiler, and the arguments you
   9.102+;; provide, via the `flymake-for-csharp-csc-arguments' variable.
   9.103+;; Appended to that list of arguments will be the name of a temporary
   9.104+;; .cs file, with the contents of the currently-being-edited C# buffer.
   9.105+;; You should not include the name of the current .cs file in the
   9.106+;; `flymake-for-csharp-csc-arguments' variable, but you can specify the
   9.107+;; names of other .cs files that should be compiled *with* the current
   9.108+;; one.  The `flymake-for-csharp-csc-arguments' variable is only used
   9.109+;; with the direct csc.exe build option; it is not used when
   9.110+;; flymake-for-csharp invokes nmake or msbuild to do the syntax check.
   9.111+;;
   9.112+;; If you do no special setup, the direct csc.exe build will be used.
   9.113+;;
   9.114+;; Here's why: in deciding which build option to use, flymake-for-csharp
   9.115+;; searches the list of build files in
   9.116+;; `flymake-for-csharp-buildfile-alist' to find one appropriate for use
   9.117+;; for syntax checking, and uses the first one it finds. If no
   9.118+;; appropriate build files are found, flymake-for-csharp falls back to
   9.119+;; invoking the csc.exe compiler directly.
   9.120+;;
   9.121+;; To determine if a build file is appropriate, flymake-for-csharp uses
   9.122+;; these criteria:
   9.123+;;
   9.124+;;     1. the name of the makefile or msbuild file is on the special
   9.125+;;        variable, `flymake-for-csharp-buildfile-alist'
   9.126+;;
   9.127+;;     2. the makefile or msbuild file contains a special target
   9.128+;;        by a well-known name.  check-syntax for makefiles, and
   9.129+;;        CheckSyntax for msbuild files.
   9.130+;;
   9.131+;; If you do *nothing*, then these criteria won't be satisfied, and
   9.132+;; flymake-for-csharp will try to use csc.exe to check the syntax of
   9.133+;; your C# buffer.
   9.134+;;
   9.135+;; If you want to explicitly insure that flymake-for-csharp will use
   9.136+;; csc.exe to check the syntax of your C# buffer, then set
   9.137+;; `flymake-for-csharp-buildfile-alist' to nil, OR, insure that none of
   9.138+;; the build files in that list, exist in the directory where the .cs
   9.139+;; file resides, OR if they do exist, that the required build targets
   9.140+;; are not present in those build files.
   9.141+;;
   9.142+;; The compile-directly-with-csc.exe option is limited because
   9.143+;; flymake-for-csharp will use the same arguments with all .cs buffers.
   9.144+;; Often you want to compile .cs files differently.  Each project
   9.145+;; usually requires a different set of assemblies, for instance.  If you
   9.146+;; want to use flymake in a scenario like that, you'll want to rely on
   9.147+;; the nmake.exe or msbuild.exe options for flymake-for-csharp.
   9.148+;;
   9.149+;;
   9.150+;; Option B: use nmake and a makefile.
   9.151+;; ============================================
   9.152+;; If you want to use a makefile, you must:
   9.153+;;
   9.154+;; 1. configure the `flymake-for-csharp-netsdk-location' variable to
   9.155+;;    specify the location of the bin directory that contains nmake.exe.
   9.156+;;    Usually it is in one of the following places:
   9.157+;;
   9.158+;;    - the .NET 2.0 SDK directory
   9.159+;;      example: C:\Program Files\Microsoft SDKs\Microsoft .Net\v2.0
   9.160+;;    - the Visual Studio directory, if the VS install is the source of the .NET SDK
   9.161+;;      example: c:\Program Files\Microsoft Visual Studio 9\SDK\v2.0
   9.162+;;
   9.163+;;    example:
   9.164+;;      (setq flymake-for-csharp-netsdk-location "c:\\Program Files\\Microsoft Visual Studio 9\\SDK\\v2.0")
   9.165+;;
   9.166+;;    Notice that you should not append the bin subdir on the value of
   9.167+;;    flymake-for-csharp-netsdk-location.
   9.168+;;
   9.169+;;
   9.170+;; 2. set `flymake-for-csharp-buildfile-alist' to a list of filespecs
   9.171+;;    for names of makefiles. You can use wildcards.  The name of the
   9.172+;;    makefile must have the word "makefile" in it, or should end with
   9.173+;;    .mak.  flymake-for-csharp looks for files from the alist, in the
   9.174+;;    same directory as the currently-being-edited .cs file, where the
   9.175+;;    filename fits the constraint just described.
   9.176+;;
   9.177+;;    If the makefile exists, flymake-for-csharp searches within the
   9.178+;;    file for a make target by the name of "check-syntax" .  (This fixed
   9.179+;;    name is consistent with the use of flymake for C language source
   9.180+;;    files.).  If the makefile exists and contains the check-syntax make
   9.181+;;    target, flymake-for-csharp runs nmake.exe on it to check the
   9.182+;;    syntax of the currently-being-edited .cs file.
   9.183+;;
   9.184+;;    By default, `flymake-for-csharp-buildfile-alist' contains "makefile",
   9.185+;;    "flymake.mak" and "makefile.flymake".  If you put your check-syntax
   9.186+;;    target in a file by one of those names, then you won't need to
   9.187+;;    change the value of `flymake-for-csharp-buildfile-alist' .
   9.188+;;
   9.189+;;
   9.190+;;
   9.191+;; 3. Create the check-syntax target in the makefile. In the simplest
   9.192+;;    case, you compile only a single source module at a time.  The
   9.193+;;    target block to do syntax checking would look something like so:
   9.194+;;
   9.195+;;        check-syntax:
   9.196+;;           %windir%\Microsoft.NET\Framework\v3.5\csc.exe /t:module $(FLYMAKE_CHECK)
   9.197+;;
   9.198+;;    This works for standalone source modules; those that do not depend
   9.199+;;    on any other source modules.  If your source module depends on
   9.200+;;    particular assemblies, you could insert them on the CSC command line,
   9.201+;;    using the /R option, like so:
   9.202+;;
   9.203+;;        check-syntax:
   9.204+;;           $(_CSC) /t:module /R:foo.dll $(FLYMAKE_CHECK)
   9.205+;;
   9.206+;;
   9.207+;;    The target name MUST be "check-syntax". In the command that runs
   9.208+;;    for that target, you can run whatever commands you
   9.209+;;    like. Typically, you will invoke the c# compiler as appropriate.
   9.210+;;    You can use a make variable like $(_CSC) if one is defined in your
   9.211+;;    makefile.  If you use /target:netmodule, flymake-for-csharp will
   9.212+;;    delete any temporary .netmodule files that are created as part of
   9.213+;;    the syntax check.  If you don't, if for example you want to create
   9.214+;;    a DLL or EXE for some reason, you'll need to do your own cleanup
   9.215+;;    in the command block.
   9.216+;;
   9.217+;;    Flymake invokes nmake with several nmake macros defined on the
   9.218+;;    command line:
   9.219+;;
   9.220+;;        FLYMAKE_CHECK  - the name of the file to check.  This is a source
   9.221+;;                 file with a temporary name, copied from the current
   9.222+;;                 state of the buffer.  If you are editing Module.cs, then
   9.223+;;                 the value of this macro will be  Module_flymake.cs
   9.224+;;
   9.225+;;        FLYMAKE_ORIGINAL  - the name of the original file that is being
   9.226+;;                 checked for syntax.  In the above example, it will be
   9.227+;;                 Module.cs
   9.228+;;
   9.229+;;        FLYMAKE_SYNTAX_CHECK - set to 1
   9.230+;;
   9.231+;;    That covers the simple case. In more complex cases, there are a
   9.232+;;    set of other source files in a project that get compiled to a
   9.233+;;    single DLL, for example.  When editing one of those files, you'll
   9.234+;;    need to *exclude* the FLYMAKE_ORIGINAL file, and to *include* the
   9.235+;;    FLYMAKE_CHECK file, in the check-syntax make target. This can be
   9.236+;;    done with nmake macros, and inline files.
   9.237+;;
   9.238+;;    For example, suppose you have a project that compiles 3 source
   9.239+;;    files, Fribble,cs Zambda.cs Twoolie.cs, into a DLL. Regardless
   9.240+;;    which file you are currently editing in emacs, you want to compile
   9.241+;;    *the other two* along with the temporary copy of the currently-
   9.242+;;    being-edited file into a netmodule. You can do that like so:
   9.243+;;
   9.244+;;        CS_SOURCE=Fribble.cs Zambda.cs Twoolie.cs
   9.245+;;             ....
   9.246+;;        check-syntax :
   9.247+;;                <<flymake-build.cmd  $(CS_SOURCE)
   9.248+;;            SETLOCAL ENABLEDELAYEDEXPANSION
   9.249+;;            for %%I in (%*) do if NOT %%I == $(FLYMAKE_ORIGINAL) (
   9.250+;;               set filesToBuild=!filesToBuild! %%I
   9.251+;;            )
   9.252+;;            $(_CSC) /t:module $(FLYMAKE_CHECK) !filesToBuild!
   9.253+;;            ENDLOCAL
   9.254+;;        <<
   9.255+;;
   9.256+;;
   9.257+;;    Given that target in the makefile, all files EXCLUDING the
   9.258+;;    currently-being-edited file, but INCLUDING the temporary copy of
   9.259+;;    the currently-being-edited file, are compiled into a module.  The
   9.260+;;    double-angle-bracket signifies the use of a little-known feature
   9.261+;;    of nmake called in-line files.  The above nmake snippet causes
   9.262+;;    nmake to create a temporary .cmd file, and invoke it.  The .cmd
   9.263+;;    file includes the logic to exclude the original C# file from the
   9.264+;;    build, and include the temporary C# file into the build.
   9.265+;;
   9.266+;;    Putting the $(FLYMAKE_CHECK) file first on the csc line causes
   9.267+;;    the generated .netmodule file to have a name that allows
   9.268+;;    flymake-for-csharp to find it and delete it when flymake
   9.269+;;    finishes.
   9.270+;;
   9.271+;;    If you don't want to put a check-syntax make target into your main
   9.272+;;    makefile, you can alternatively put it into an alternative
   9.273+;;    makefile, for example "makefile.flymake" or "flymake.mak". Insure
   9.274+;;    that the filename you use is included as one element in the
   9.275+;;    variable `flymake-for-csharp-buildfile-alist'.
   9.276+;;
   9.277+;;
   9.278+;;
   9.279+;; ==================================================================
   9.280+;;
   9.281+;;
   9.282+;; Option C: use msbuild
   9.283+;; ============================================
   9.284+;;
   9.285+;; If you use msbuild, rather than nmake, specify the location of
   9.286+;; msbuild.exe via the `flymake-for-csharp-dotnet-location' variable,
   9.287+;; and insure that `flymake-for-csharp-buildfile-alist' contains a spec
   9.288+;; for a buildfile that contains the well-known target, CheckSyntax.
   9.289+;;
   9.290+;; As described above, Wildcards are allowed in the elements in the alist.
   9.291+;; After wildcard expansion, for each
   9.292+;; file in the list that has a name that includes "msbuild" or ends in
   9.293+;; .xml, or .csproj, flymake-for-csharp will search the file, and check
   9.294+;; for the well-known build target of "CheckSyntax" in the file. If that
   9.295+;; target is found, then flymake-for-csharp will use that as the msbuild
   9.296+;; file to do syntax checking.
   9.297+;;
   9.298+;; flymake-for-csharp insists on finding a build file that contains a
   9.299+;; target by the name of "CheckSyntax".  Also, the target name MUST be
   9.300+;; defined on the same line as the <Target> element, immediately
   9.301+;; following the element name like so:
   9.302+;;
   9.303+;;      <Target Name="CheckSyntax"  ....
   9.304+;;
   9.305+;; The reason for this restriction: flymake-for-csharp does a
   9.306+;; text-search in the build file for that well-known target name, in
   9.307+;; that position.  If you define a target with a different name,
   9.308+;; flymake-for-csharp will conclude that it is not useful for syntax
   9.309+;; checking. If you define a target with a different text layout,
   9.310+;; flymake-for-csharp won't find it with its naive text search.
   9.311+;;
   9.312+;; To insure that you use msbuild to do the syntax checking, be sure
   9.313+;; that on the `flymake-for-csharp-buildfile-alist' list, a matching
   9.314+;; msbuild file appears before a matching makefile.  flymake-for-csharp
   9.315+;; will use the first suitable build file (either a makefile or a
   9.316+;; msbuild file) that it finds.
   9.317+;;
   9.318+;; Flymake invokes msbuild with several properties defined on the
   9.319+;; command line:
   9.320+;;
   9.321+;;     SourceFileToCheck - the name of the file to check.  This is a source
   9.322+;;                 file with a temporary name, copied from the current
   9.323+;;                 state of the buffer.  If you are editing Module.cs, then
   9.324+;;                 the value of this property will be  Module_flymake.cs
   9.325+;;
   9.326+;;     OriginalSourceFile  - the name of the original file that is being
   9.327+;;                 checked for syntax.  In the above example, it will be
   9.328+;;                 Module.cs
   9.329+;;
   9.330+;; If the source you are editing consists of small utility programs that
   9.331+;; each rely on a single source file, you can use a standard,
   9.332+;; boilerplate, build file.  Define it like this:
   9.333+;;
   9.334+;; <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
   9.335+;;         DefaultTargets="CompileAll"
   9.336+;;         ToolsVersion="3.5"
   9.337+;;       >
   9.338+;;
   9.339+;;  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   9.340+;;
   9.341+;;  <!-- specify reference assemblies for all builds in this project -->
   9.342+;;  <ItemGroup>
   9.343+;;    <Reference Include="mscorlib" />
   9.344+;;    <Reference Include="System" />
   9.345+;;    <Reference Include="System.Core" />
   9.346+;;    <Reference Include="System.Data" />
   9.347+;;    <Reference Include="System.Data.Linq" />                   <!-- LINQ -->
   9.348+;;    <!--Reference Include="System.ServiceModel" /-->           <!-- WCF -->
   9.349+;;    <!--Reference Include="System.ServiceModel.Web" /-->       <!-- WCF -->
   9.350+;;    <!--Reference Include="System.Runtime.Serialization" /-->  <!-- WCF -->
   9.351+;;  </ItemGroup>
   9.352+;;
   9.353+;;  <Target Name="CheckSyntax"
   9.354+;;          DependsOnTargets="ResolveAssemblyReferences"
   9.355+;;        >
   9.356+;;    <CSC
   9.357+;;       Sources="$(SourceFileToCheck)"
   9.358+;;       References="@(ReferencePath)"
   9.359+;;       TargetType="module"
   9.360+;;       Toolpath="$(MSBuildToolsPath)"
   9.361+;;       Nologo="true"
   9.362+;;       />
   9.363+;;  </Target>
   9.364+;;
   9.365+;; </Project>
   9.366+;;
   9.367+;; -ends-
   9.368+;;
   9.369+;; (This msbuild file will work only with .NET 3.5 and later.)  Name
   9.370+;; that build file according to the constraints described above, and put
   9.371+;; the name of the file on `flymake-for-csharp-buildfile-alist' .
   9.372+;;
   9.373+;; If there are additional assemblies you need to reference, add them as
   9.374+;; you would normally, by adding an additional <Reference> element under
   9.375+;; the <ItemGroup> element. If the assembly is inside the GAC, then use
   9.376+;; <Reference Include=""/> and specify the short name of the assembly.
   9.377+;; If the assembly is located in the filesystem, specify the path to the
   9.378+;; DLL, relative to the local directory. For example, you can specify
   9.379+;; c:\ionic\Ionic.Zip.dll if the source module references the DotNetZip
   9.380+;; assembly and if that DLL is found in the c:\ionic directory.
   9.381+;;
   9.382+;; If your projects consist of multiple source files, then you need to
   9.383+;; get fancier.  The way flymake works is, it copies the current
   9.384+;; contents of the buffer to a temporary source file, then compiles it.
   9.385+;; Therefore in the case where you are compiling multiple source files
   9.386+;; together, you need to compile all files, *including* the temporary
   9.387+;; copy of the file being edited, but *excluding* the actual source file
   9.388+;; being edited. This is easily done in msbuild with a
   9.389+;; specially-structured Exclude qualifier, referencing the
   9.390+;; OriginalSourceFile property. Your msbuild.flymake.xml file should
   9.391+;; look something like this:
   9.392+;;
   9.393+;; <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
   9.394+;;          DefaultTargets="CompileAll"
   9.395+;;          ToolsVersion="3.5"
   9.396+;;          >
   9.397+;;
   9.398+;;   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   9.399+;;
   9.400+;;    <PropertyGroup>
   9.401+;;       <Optimize>false</Optimize>
   9.402+;;       <DebugSymbols>true</DebugSymbols>
   9.403+;;       <!-- <OutputPath>.\bin\</OutputPath>  -->
   9.404+;;       <OutputPath>.\</OutputPath>
   9.405+;;       <OutDir>.\</OutDir>
   9.406+;;       <IntermediateOutputPath>.\obj\</IntermediateOutputPath>
   9.407+;;    </PropertyGroup>
   9.408+;;
   9.409+;;   <!-- specify reference assemblies for all builds in this project -->
   9.410+;;   <ItemGroup>
   9.411+;;     <Reference Include="mscorlib" />
   9.412+;;     <Reference Include="System" />
   9.413+;;     <Reference Include="System.Core" />
   9.414+;;     <Reference Include="System.Data" />
   9.415+;;     <Reference Include="System.Data.Linq" />                   <!-- LINQ -->
   9.416+;;     <!--Reference Include="System.ServiceModel" /-->           <!-- WCF -->
   9.417+;;     <!--Reference Include="System.ServiceModel.Web" /-->       <!-- WCF -->
   9.418+;;     <!--Reference Include="System.Runtime.Serialization" /-->  <!-- WCF -->
   9.419+;;   </ItemGroup>
   9.420+;;
   9.421+;;   <!-- This ItemGroup includes every .cs source file in the directory,           -->
   9.422+;;   <!-- except for the one indicated by OriginalSourceFile.  In flymake, that     -->
   9.423+;;   <!-- property indicates the currently edited file. So the result is that the   -->
   9.424+;;   <!-- ItemGroup CSFile will include all files, including the _flymake.cs clone, -->
   9.425+;;   <!-- but not including the original file.  Which is what we want.              -->
   9.426+;;   <ItemGroup>
   9.427+;;     <CSFile Include="*.cs" Exclude="$(OriginalSourceFile)" />
   9.428+;;   </ItemGroup>
   9.429+;;
   9.430+;;   <!-- Stuff the OriginalSourceFile property into an ItemGroup.                  -->
   9.431+;;   <!-- We do this so we can get at the metadata, which is available only         -->
   9.432+;;   <!-- through an item within an ItemGroup.  We want the root filename, which    -->
   9.433+;;   <!-- we use to name the output netmodule.                                      -->
   9.434+;;   <ItemGroup>
   9.435+;;     <ExcludedCSFile Include="$(OriginalSourceFile)" />
   9.436+;;   </ItemGroup>
   9.437+;;
   9.438+;;   <Target Name="CheckSyntax"
   9.439+;;           DependsOnTargets="ResolveAssemblyReferences"
   9.440+;;           >
   9.441+;;     <!-- Run the Visual C# compilation on the specified set of .cs files. -->
   9.442+;;     <CSC
   9.443+;;        Sources="@(CSFile)"
   9.444+;;        References="@(ReferencePath)"
   9.445+;;        TargetType="module"
   9.446+;;        Toolpath="$(MSBuildToolsPath)"
   9.447+;;        OutputAssembly="%(ExcludedCSFile.Filename)_flymake.netmodule"
   9.448+;;        Nologo="true"
   9.449+;;        />
   9.450+;;   </Target>
   9.451+;;
   9.452+;; </Project>
   9.453+;;
   9.454+;; -ends-
   9.455+;;
   9.456+;; (The above msbuild file also works only with .NET 3.5.)
   9.457+;;
   9.458+;; The above assumes that every .cs file in the current directory should be
   9.459+;; compiled together.  If this is not the case, then modify the msbuild file
   9.460+;; accordingly, to exclude the files as appropriate.  You can also specify
   9.461+;; additional references, and so on.
   9.462+;;
   9.463+
   9.464+
   9.465+(require 'flymake)
   9.466+
   9.467+
   9.468+
   9.469+;;(setq flymake-log-level 3)  ;; insure flymake errors get plopped into the *Messages* buffer
   9.470+;; -1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
   9.471+
   9.472+
   9.473+;; flymake-gui-warnings-enabled
   9.474+;; nil = turn off? GUI warnings, eg. when no msbuild.flymake.xml file found
   9.475+;; t = turn on? GUI warnings
   9.476+(setq flymake-gui-warnings-enabled nil)
   9.477+
   9.478+
   9.479+
   9.480+;; New variables for use with flymake-for-csharp
   9.481+(defvar flymake-for-csharp-netsdk-location "c:\\netsdk2.0"
   9.482+  "Location of .NET SDK, for finding nmake.exe.
   9.483+flymake-for-csharp looks for nmake.exe in the bin subdirectory
   9.484+of the given directory.  An example value is: c:\\Program
   9.485+Files\\Microsoft Visual Studio 8\\SDK\\v2.0 . This variable is
   9.486+referenced only if the build-file is an msbuild-compatible
   9.487+file. See `flymake-for-csharp-buildfile-alist' for details.")
   9.488+
   9.489+(defvar flymake-for-csharp-dotnet-location "c:\\.net3.5"
   9.490+  "Directory containing MSBuild.exe and csc.exe. Typically, this
   9.491+is c:\\Windows\\Microsoft.NET\\Framework\\v3.5 .  This variable
   9.492+is referenced if the build-file is an msbuild-compatible file,
   9.493+or if using csc. See `flymake-for-csharp-buildfile-alist' for
   9.494+details.")
   9.495+
   9.496+(defvar flymake-for-csharp-grep-pgm  "grep.exe"
   9.497+  "The location of the grep program on your system.  This can be
   9.498+a bare file if you want flymake-for-csharp to find grep.exe on
   9.499+the path. ")
   9.500+
   9.501+(defvar flymake-for-csharp-buildfile-alist
   9.502+  (list "makefile" "makefile.flymake" "flymake.mak" "*.flymake.xml"
   9.503+        "*.csproj")
   9.504+  "A list of build files that flymake should look for. Wildcards
   9.505+are allowed. For each filename in this list, flymake-for-csharp
   9.506+will check the existence of the file in the local directory.  If
   9.507+the file exists, it will determine if the file has the
   9.508+appropriate target, then invoke the associated build tool.  If
   9.509+the filename is 'makefile' or begins with 'makefile' or ends in
   9.510+.mak, flymake-for-csharp will try to use the file with nmake.  If
   9.511+the filename is '*.csproj' or 'msbuild.*' or ends in '.xml',
   9.512+flymake will try to use the build file with msbuild.  The build
   9.513+file you specify should have the check-syntax target contained
   9.514+within it. If none of the build files on the list seem
   9.515+appropriate, then flymake-for-csharp will resort to directly
   9.516+compiling the current file by itself, using csc.exe.
   9.517+" )
   9.518+
   9.519+
   9.520+(defvar flymake-for-csharp-csc-arguments
   9.521+  (list "/t:module" "/nologo")
   9.522+  "A list of arguments to use with the csc.exe
   9.523+compiler, when using flymake-for-csharp with a
   9.524+direct csc.exe build for syntax checking purposes.")
   9.525+
   9.526+
   9.527+
   9.528+(defvar flymake-for-csharp-most-recent-cmd  nil
   9.529+  "The most recent command line used to run flymake
   9.530+for the current csharp buffer.
   9.531+
   9.532+Use this to figure out what flymake-for-csharp decided
   9.533+to do, given your setup, variable settings, and the value
   9.534+of `flymake-for-csharp-buildfile-alist'.
   9.535+
   9.536+The value is possily nil, if flymake
   9.537+has never been run on the buffer.
   9.538+")
   9.539+
   9.540+
   9.541+
   9.542+(defun flymake-for-csharp-cleanup ()
   9.543+  "Delete the temporary .netmodule file created in syntax checking,
   9.544+then call through to flymake-simple-cleanup."
   9.545+  (flymake-log 3 "flymake-for-csharp-cleanup")
   9.546+  (if flymake-temp-source-file-name
   9.547+  (let* ((netmodule-name
   9.548+          (concat (file-name-sans-extension flymake-temp-source-file-name)
   9.549+                              ".netmodule"))
   9.550+         (expanded-netmodule-name (expand-file-name netmodule-name "."))
   9.551+         )
   9.552+    (if (file-exists-p expanded-netmodule-name)
   9.553+        (flymake-safe-delete-file expanded-netmodule-name)
   9.554+      )
   9.555+    )
   9.556+  )
   9.557+    (flymake-simple-cleanup)
   9.558+
   9.559+  )
   9.560+
   9.561+
   9.562+
   9.563+(defun flymake-for-csharp-grep-target-in-build-file (target file)
   9.564+  "run grep"
   9.565+  (interactive)
   9.566+  (save-excursion
   9.567+    (let ((buf (get-buffer-create "*flymake* csharp-grep-out"))
   9.568+          (beg 0))
   9.569+      (set-buffer buf)  ;; switch-to-buffer
   9.570+      (delete-region (point-min) (point-max))
   9.571+      (setq beg (point-min))
   9.572+      (goto-char (point-min))
   9.573+      (call-process flymake-for-csharp-grep-pgm ;; program
   9.574+                    nil        ;; infile - which file to use for input
   9.575+                    t          ;; buffer - t means current
   9.576+                    nil        ;; display - non-nil means redisplay buf as output arrives
   9.577+                    "-F"       ;; args - "-F" means treat expression as plain text
   9.578+                    target     ;;        target - what to search for.  eg, "check-syntax"
   9.579+                    file       ;;        file - the to search in
   9.580+                    "NUL"      ;;        NUL - make sure we print out the filename
   9.581+                    )
   9.582+      (goto-char (point-min))
   9.583+      (if (> (point-max) (point-min))
   9.584+          (flymake-log 4 "flymake-for-csharp-grep: f(%s) t(%s) output(%s)"
   9.585+                       file target
   9.586+                       (buffer-substring-no-properties (point-min) (1- (point-max))))
   9.587+        (flymake-log 4 "flymake-for-csharp-grep f(%s) t(%s): no output" file target))
   9.588+
   9.589+      (re-search-forward target nil t))))
   9.590+
   9.591+
   9.592+
   9.593+(defun string-starts-with (s arg)
   9.594+  "returns t if string S starts with ARG.  Else nil."
   9.595+  (cond ((>= (length s) (length arg))
   9.596+         (string-equal (substring s 0 (length arg)) arg))
   9.597+        (t nil)))
   9.598+
   9.599+
   9.600+
   9.601+(defun flymake-for-csharp-get-csc-arguments ()
   9.602+  "gets the args for csc.exe.  You might think this could just be a variable
   9.603+reference, but it's packaged as a function to allow advice to override it.
   9.604+In particular, the flymake-for-csharp-ext.el package overrides this to
   9.605+provide a list of /R arguments, corresponding to the using statements in
   9.606+the source file.  That extension ( flymake-for-csharp-ext.el) depends on
   9.607+the CSDE package, and not everybody has CSDE installed, or wants it.
   9.608+So it remains an extension, and this needs to be a function.
   9.609+
   9.610+This func also does checking to verify the /t:module is used in the arglist,
   9.611+and burps if a different /t argument is found."
   9.612+
   9.613+  (flymake-log 3 "flymake-for-csharp-get-csc-arguments: entry")
   9.614+  (let ((args flymake-for-csharp-csc-arguments)
   9.615+        arg
   9.616+        (found nil))
   9.617+    (flymake-log 3 "flymake-for-csharp-get-csc-arguments: args: %s" args)
   9.618+    (while args
   9.619+      (setq arg (car args))
   9.620+      (cond
   9.621+       ((string-equal arg "/t:module") (setq found t))
   9.622+       ((string-starts-with arg "/t:")
   9.623+        (setq found t)
   9.624+        (message "flymake-for-csharp: WARNING /t: option present, and not /t:module; fix this.")))
   9.625+
   9.626+      (setq args (cdr args)))
   9.627+    (if found
   9.628+        (progn
   9.629+          (flymake-log 3 "flymake-for-csharp-get-csc-arguments: return %s" flymake-for-csharp-csc-arguments)
   9.630+          flymake-for-csharp-csc-arguments)
   9.631+
   9.632+      (flymake-log 1 "flymake-for-csharp-get-csc-arguments: appending /t:module")
   9.633+      (setq args
   9.634+            (append flymake-for-csharp-csc-arguments (list "/t:module"))))))
   9.635+
   9.636+
   9.637+
   9.638+(defun flymake-for-csharp-figure-build ()
   9.639+"Figures the build file and type of build to run for flymake.  It
   9.640+does this by examining the `flymake-for-csharp-buildfile-alist',
   9.641+checking for existence of each file, then checking (best effort)
   9.642+for the appropriate flymake target in the buildfile. If none of those
   9.643+files exist or if they lack appropriate targets, then it backs off
   9.644+to a csc.exe build."
   9.645+  (let ((filelist
   9.646+         ;; this does wildcard-expansion of the alist, then consolidates
   9.647+         ;; to a single list
   9.648+         (apply #'append
   9.649+                (mapcar '(lambda (a) (file-expand-wildcards a t))
   9.650+                        flymake-for-csharp-buildfile-alist)))
   9.651+        (build-file nil)
   9.652+        (build-type nil))
   9.653+
   9.654+    (while filelist
   9.655+      (setq build-file (car filelist))
   9.656+      (flymake-log 4 "flymake-for-csharp-figure-build: file(%s)" build-file)
   9.657+      (if (file-exists-p build-file)
   9.658+          ;;then
   9.659+          (progn
   9.660+            (flymake-log 3 "flymake-for-csharp-figure-build: file(%s) exists" build-file)
   9.661+            (cond
   9.662+             ((or (not (null (string-match "makefile" build-file)))
   9.663+                  (not (null (string-match ".*\\.mak$" build-file))))
   9.664+              (if (flymake-for-csharp-grep-target-in-build-file "check-syntax:" build-file)
   9.665+                  (setq build-type "nmake"
   9.666+                        filelist nil)
   9.667+                (flymake-log 3 "flymake-for-csharp-figure-build: file(%s) - no suitable target"
   9.668+                             build-file)))
   9.669+
   9.670+             ((or (not (null (string-match "msbuild" build-file)))
   9.671+                  (not (null (string-match ".*\\.xml$" build-file)))
   9.672+                  (not (null (string-match ".*\\.csproj$" build-file))))
   9.673+              (if (flymake-for-csharp-grep-target-in-build-file
   9.674+                   "<Target Name=\"CheckSyntax\""  build-file)
   9.675+                  (setq build-type "msbuild"
   9.676+                        filelist nil)
   9.677+                (flymake-log 3 "flymake-for-csharp-figure-build: file(%s) - no suitable target"
   9.678+                             build-file)))
   9.679+
   9.680+             (t
   9.681+                (flymake-log 3 "flymake-for-csharp-figure-build: file(%s) - not a recognized file"
   9.682+                             build-file))))
   9.683+        ;;else
   9.684+        (flymake-log 3 "flymake-for-csharp-figure-build: file(%s) does not exist" build-file))
   9.685+
   9.686+      (if (null build-type)
   9.687+          (progn
   9.688+            (setq filelist (cdr filelist))
   9.689+            (setq build-file nil))))
   9.690+
   9.691+    (if (null build-type)
   9.692+      (setq build-type "csc"))
   9.693+
   9.694+    (list build-type build-file)))
   9.695+
   9.696+
   9.697+
   9.698+
   9.699+
   9.700+(defun flymake-for-csharp-init ()
   9.701+  (flymake-for-csharp-init-impl 'flymake-create-temp-inplace t t  'flymake-for-csharp-get-flymake-cmdline))
   9.702+
   9.703+
   9.704+(defun flymake-for-csharp-init-impl (create-temp-f use-relative-base-dir use-relative-source get-cmdline-f)
   9.705+  "Create syntax check command line for a directly checked source file.
   9.706+Use CREATE-TEMP-F for creating temp copy."
   9.707+  (let* ((args nil)
   9.708+        (temp-source-file-name  (flymake-init-create-temp-buffer-copy create-temp-f)))
   9.709+
   9.710+    (setq args (flymake-get-syntax-check-program-args temp-source-file-name "."  ;; buildfile-dir
   9.711+                                                      use-relative-base-dir use-relative-source
   9.712+                                                      get-cmdline-f))
   9.713+    (flymake-log 3 "flymake-for-csharp-init: %s" (prin1-to-string args))
   9.714+    args))
   9.715+
   9.716+
   9.717+;(debug-on-entry 'flymake-for-csharp-init)
   9.718+
   9.719+
   9.720+
   9.721+
   9.722+;;(defun flymake-get-make-cmdline (source base-dir)
   9.723+(defun flymake-for-csharp-get-flymake-cmdline (source base-dir)
   9.724+"Gets the cmd line for running a flymake session in a csharp buffer.
   9.725+ It will invoke one of three programs: csc.exe, msbuild.exe, or nmake.exe,
   9.726+ depending on the state of the filesystem.  If an appropriate build file,
   9.727+ suitable for use with either nmake or msbuild, is found on the
   9.728+ `flymake-for-csharp-buildfile-alist', then the appropriate build tool
   9.729+ (msbuild or nmake) is invoked on that build file. If no appropriate build
   9.730+ file is found, then csc.exe is invoked"
   9.731+(setq flymake-for-csharp-most-recent-cmd
   9.732+  (let* ((build (flymake-for-csharp-figure-build))
   9.733+         (flavor (car build)) ;; flavor:  "msbuild" or "nmake" or "csc"
   9.734+         (build-file (cadr build))
   9.735+        )
   9.736+    (cond
   9.737+     ((string= flavor "msbuild")
   9.738+      (list (concat  flymake-for-csharp-dotnet-location "\\msbuild.exe")
   9.739+            (list build-file
   9.740+                  ;;(concat base-dir "/" build-file)
   9.741+                  "/nologo"
   9.742+                  "/t:CheckSyntax"
   9.743+                  "/v:quiet"  ;; normal
   9.744+                  ;; use file-relative-name to remove the fully-qualified directory name
   9.745+                  (concat "/property:SourceFileToCheck=" (file-relative-name source))
   9.746+                  (concat "/property:OriginalSourceFile=" (file-relative-name buffer-file-name))
   9.747+                  )))
   9.748+     ((string= flavor "nmake")
   9.749+      (list (concat  flymake-for-csharp-netsdk-location "\\bin\\nmake.exe")
   9.750+            (list "/f"
   9.751+                  build-file
   9.752+                  ;;(concat base-dir "/" build-file)
   9.753+                  "/nologo"
   9.754+                  "FLYMAKE_SYNTAX_CHECK=1"
   9.755+                  (concat "FLYMAKE_CHECK=" source)
   9.756+                  (concat "FLYMAKE_ORIGINAL=" (file-relative-name buffer-file-name))
   9.757+                  "check-syntax")))
   9.758+     (t
   9.759+      (list (concat  flymake-for-csharp-dotnet-location "\\csc.exe")
   9.760+        (append (flymake-for-csharp-get-csc-arguments) (list source))))))))
   9.761+
   9.762+
   9.763+
   9.764+
   9.765+; This fixup sets flymake to use a different cleanup routine for c# compiles.
   9.766+; need to do this only once, not every time csharp-mode is invoked.
   9.767+
   9.768+(progn
   9.769+  (let (elt
   9.770+        (csharp-entry nil)
   9.771+        (masks flymake-allowed-file-name-masks))
   9.772+
   9.773+    ;; The "flymake-allowed-file-name-masks" variable stores a filename pattern as
   9.774+    ;; well as the make-init function, and a cleanup function.  In the case of csharp,
   9.775+    ;; the setting in flymake.el has the cleanup fn as nil, which means it gets the
   9.776+    ;; standard cleanup : the *_flymake.cs cloned source file gets deleted.  But the
   9.777+    ;; flymake-for-csharp compiles the .cs file into a module,
   9.778+    ;; which also needs to be deleted afterwards.
   9.779+    ;;
   9.780+
   9.781+    ;; Here, we remove the C# entry in the "flymake-allowed-file-name-masks"
   9.782+    ;; variable, and replace it with an entry that includes a custom csharp cleanup
   9.783+    ;; routine.  That cleanup routine deletes the .netmodule file, generated
   9.784+    ;; by a successful flymake run.
   9.785+
   9.786+    ;; I could just setq the "flymake-allowed-file-name-masks" var to the C# thing I
   9.787+    ;; want, but that would obliterate all the masks for all other languages, which
   9.788+    ;; would be bad manners.
   9.789+    ;;
   9.790+    ;; You know, come to think of it, I could just delete the generated .netmodule
   9.791+    ;; file in the msbuild or makefile.  That might be simpler.
   9.792+    ;;
   9.793+    ;; But the main point is this ought to be more easily configurable or customizable
   9.794+    ;; in flymake.el.  And also, flymake ought to do something reasonable for csharp builds,
   9.795+    ;; rather than completely punt.
   9.796+    ;;
   9.797+    ;; This fixup is really hacky, relying on the string that is used for csharp in
   9.798+    ;; flymake.el.  But it will do for now...
   9.799+
   9.800+    ;; Find the entry
   9.801+    (while (consp masks)
   9.802+      (setq elt (car masks))
   9.803+      (if (string= "\\.cs\\'" (car elt))
   9.804+          (setq csharp-entry elt)
   9.805+        )
   9.806+      (setq masks (cdr masks))
   9.807+      )
   9.808+
   9.809+    ;;  remove the original cleanup item entry ...
   9.810+    (if csharp-entry
   9.811+        (setq flymake-allowed-file-name-masks
   9.812+              (delete csharp-entry flymake-allowed-file-name-masks)))
   9.813+
   9.814+    ;; Now add a new cleanup item entry, with the custom cleanup method.
   9.815+    (setq flymake-allowed-file-name-masks
   9.816+          (cons
   9.817+           '("\\.cs\\'" flymake-for-csharp-init flymake-for-csharp-cleanup)
   9.818+           flymake-allowed-file-name-masks))
   9.819+    )
   9.820+  )
   9.821+
   9.822+
   9.823+
   9.824+
   9.825+;; =======================================================
   9.826+;;
   9.827+;; This section attempts to workaround some anomalous display ebhavior
   9.828+;; for tooltips.  It's not strictly necessary, only aesthetic.  The issue is that
   9.829+;; tooltips can get clipped.  This is the topic of Emacs bug #5908, unfixed
   9.830+;; in v23 and present in v22.
   9.831+
   9.832+(defun cheeso-reverse-string (s)
   9.833+  "Reverse a string."
   9.834+  (coerce (reverse (loop for b across s
   9.835+                         collect b))
   9.836+          'string))
   9.837+
   9.838+(defun cheeso-string-trim (s &rest chars)
   9.839+  "Trim any char in string CHARS from either end of string S.
   9.840+Often this fn is called with a literal space, as with
   9.841+(cheeso-string-trim my-string ?\ ) ."
   9.842+  (apply 'cheeso-string-trim-right
   9.843+         (apply 'cheeso-string-trim-left s chars)
   9.844+         chars))
   9.845+
   9.846+(defun cheeso-string-trim-left (s &rest chars)
   9.847+  "Trim any char in string CHARS from the left of string S."
   9.848+  (let ((idx (dotimes (i (length s))
   9.849+               (unless (member (elt s i) chars)
   9.850+                 (return i)))))
   9.851+    (if idx
   9.852+        (subseq s idx)
   9.853+      "")))
   9.854+
   9.855+(defun cheeso-string-trim-right (s &rest chars)
   9.856+  "Trim any char in string CHARS from the right of string S."
   9.857+  (cheeso-reverse-string (apply 'cheeso-string-trim-left (cheeso-reverse-string s) chars)))
   9.858+
   9.859+
   9.860+(defun cheeso-reform-string (limit arg)
   9.861+  "Reforms a single-line string ARG to a multi-line string with a max
   9.862+of LIMIT chars on a line.
   9.863+
   9.864+This is intended to solve a problem with the display of tooltip text
   9.865+in emacs on Win32 - which is that the tooltip is extended to be very very
   9.866+long, and the final line is clipped.
   9.867+
   9.868+The solution is to split the text into multiple lines, and to add a
   9.869+trailing newline to trick the tooltip logic into doing the right thing."
   9.870+  (let ((orig arg) (modified "") (curline "") word
   9.871+        (words (split-string arg " ")))
   9.872+    (while words
   9.873+      (progn
   9.874+        (setq word (car words))
   9.875+        (setq words (cdr words))
   9.876+        (if (stringp word)
   9.877+            (progn
   9.878+            (if (> (+ (length curline) (length word) 1) limit)
   9.879+                ;; then
   9.880+                (progn
   9.881+                  (setq modified (concat modified curline "\n"))
   9.882+                  (setq curline "")))
   9.883+            (setq curline (concat curline " " word)))
   9.884+
   9.885+            )))
   9.886+
   9.887+    (setq modified (concat modified curline " \n\n")))
   9.888+  )
   9.889+
   9.890+
   9.891+(defadvice tooltip-show (before
   9.892+                         flymake-for-csharp-fixup-tooltip
   9.893+                         (arg &optional use-echo-area)
   9.894+                         activate compile)
   9.895+  (progn
   9.896+    (if ;;(and (not use-echo-area) (eq major-mode 'csharp-mode))
   9.897+        (not use-echo-area)
   9.898+        (let ((orig (ad-get-arg 0)))
   9.899+          (ad-set-arg 0 (concat " " (cheeso-string-trim (cheeso-reform-string 74 orig) ?\ )))
   9.900+          ))))
   9.901+
   9.902+;; =======================================================
   9.903+
   9.904+
   9.905+(defadvice flymake-posn-at-point-as-event (before
   9.906+                                           flymake-for-csharp-advice-4
   9.907+                                           (&optional position window dx dy)
   9.908+                                           compile activate)
   9.909+  (let ((dx1 (ad-get-arg 2))
   9.910+        (dy1 (ad-get-arg 3)))
   9.911+    (if (not (null dx1))
   9.912+        (setq dx1 (+ dx1 20))
   9.913+      (setq dx1 20))
   9.914+    (if (not (null dy1))
   9.915+        (setq dy1 (+ dy1 14))
   9.916+      (setq dy1 14))
   9.917+
   9.918+    (ad-set-arg 2 dx1)
   9.919+    (ad-set-arg 3 dy1)
   9.920+
   9.921+    )
   9.922+  )
   9.923+
   9.924+
   9.925+
   9.926+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   9.927+
   9.928+(provide 'flymake-for-csharp)
   9.929+
   9.930+;;; end of flymake-for-csharp.el
    10.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2+++ b/csharp-mode/makefile	Wed Nov 10 15:19:03 2010 +0200
    10.3@@ -0,0 +1,28 @@
    10.4+_NETHOME=c:\.net3.5
    10.5+_NETSDK20=c:\netsdk2.0\bin
    10.6+_NETSDK=c:\netsdk3.5\bin
    10.7+
    10.8+_CS_DBG_FLAGS=/debug:full /optimize-
    10.9+_CS_DLL_FLAGS=/t:library $(_CS_DBG_FLAGS)
   10.10+_CS_EXE_FLAGS=/t:exe $(_CS_DBG_FLAGS)
   10.11+
   10.12+_CSC=$(_NETHOME)\csc.exe
   10.13+
   10.14+!IFNDEF CONFIG
   10.15+CONFIG=Release
   10.16+!ENDIF
   10.17+
   10.18+
   10.19+!IF "$(CONFIG)" == "Debug"
   10.20+ADDL_DEBUG_DLL=Ionic.CopyData.dll
   10.21+ADDL_REF=/R:$(ADDL_DEBUG_DLL)
   10.22+ADDL_CSC_OPTIONS=/d:UseCopyData
   10.23+!Endif
   10.24+
   10.25+
   10.26+
   10.27+default: CscompUtilities.dll
   10.28+
   10.29+CscompUtilities.dll: makefile CscompUtilities.cs $(ADDL_DEBUG_DLL)
   10.30+        $(_CSC) $(ADDL_CSC_OPTIONS) /t:library /debug:full /optimize- $(ADDL_REF) /out:$@ CscompUtilities.cs
   10.31+
    11.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2+++ b/csharp-mode/svn_location.txt	Wed Nov 10 15:19:03 2010 +0200
    11.3@@ -0,0 +1,1 @@
    11.4+svn checkout http://csharpmode.googlecode.com/svn/trunk/ csharpmode-read-only
    12.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2+++ b/csharp-mode/tfs.el	Wed Nov 10 15:19:03 2010 +0200
    12.3@@ -0,0 +1,593 @@
    12.4+;;; tfs.el --- MS Team Foundation Server commands for Emacs.
    12.5+
    12.6+;; Copyright 2009 Dino Chiesa
    12.7+;; Time-stamp: <2010-March-04 10:28:06>
    12.8+;;
    12.9+;; Author: dinoch <dpchiesa@hotmail.com>
   12.10+;; Version: 0.2.4
   12.11+;; X-URL: http://cheeso.members.winisp.net/srcview.aspx?dir=emacs&file=tfs.el
   12.12+
   12.13+;; Microsoft Public License (Ms-PL)
   12.14+;;
   12.15+;; This license governs use of the accompanying software, the tfs.el
   12.16+;; library ("the software"). If you use the software, you accept this
   12.17+;; license. If you do not accept the license, do not use the software.
   12.18+;;
   12.19+;; 1. Definitions
   12.20+;;
   12.21+;; The terms "reproduce," "reproduction," "derivative works," and
   12.22+;; "distribution" have the same meaning here as under U.S. copyright
   12.23+;; law.
   12.24+;;
   12.25+;; A "contribution" is the original software, or any additions or
   12.26+;; changes to the software.
   12.27+;;
   12.28+;; A "contributor" is any person that distributes its contribution under
   12.29+;; this license.
   12.30+;;
   12.31+;; "Licensed patents" are a contributor's patent claims that read
   12.32+;; directly on its contribution.
   12.33+;;
   12.34+;; 2. Grant of Rights
   12.35+;;
   12.36+;; (A) Copyright Grant- Subject to the terms of this license, including
   12.37+;; the license conditions and limitations in section 3, each contributor
   12.38+;; grants you a non-exclusive, worldwide, royalty-free copyright license
   12.39+;; to reproduce its contribution, prepare derivative works of its
   12.40+;; contribution, and distribute its contribution or any derivative works
   12.41+;; that you create.
   12.42+;;
   12.43+;; (B) Patent Grant- Subject to the terms of this license, including the
   12.44+;; license conditions and limitations in section 3, each contributor
   12.45+;; grants you a non-exclusive, worldwide, royalty-free license under its
   12.46+;; licensed patents to make, have made, use, sell, offer for sale,
   12.47+;; import, and/or otherwise dispose of its contribution in the software
   12.48+;; or derivative works of the contribution in the software.
   12.49+;;
   12.50+;; 3. Conditions and Limitations
   12.51+;;
   12.52+;; (A) No Trademark License- This license does not grant you rights to
   12.53+;; use any contributors' name, logo, or trademarks.
   12.54+;;
   12.55+;; (B) If you bring a patent claim against any contributor over patents
   12.56+;; that you claim are infringed by the software, your patent license
   12.57+;; from such contributor to the software ends automatically.
   12.58+;;
   12.59+;; (C) If you distribute any portion of the software, you must retain
   12.60+;; all copyright, patent, trademark, and attribution notices that are
   12.61+;; present in the software.
   12.62+;;
   12.63+;; (D) If you distribute any portion of the software in source code
   12.64+;; form, you may do so only under this license by including a complete
   12.65+;; copy of this license with your distribution. If you distribute any
   12.66+;; portion of the software in compiled or object code form, you may only
   12.67+;; do so under a license that complies with this license.
   12.68+;;
   12.69+;; (E) The software is licensed "as-is." You bear the risk of using
   12.70+;; it. The contributors give no express warranties, guarantees or
   12.71+;; conditions. You may have additional consumer rights under your local
   12.72+;; laws which this license cannot change. To the extent permitted under
   12.73+;; your local laws, the contributors exclude the implied warranties of
   12.74+;; merchantability, fitness for a particular purpose and
   12.75+;; non-infringement.
   12.76+
   12.77+;;; Commentary:
   12.78+;;
   12.79+;; Basic steps to setup:
   12.80+;;   1. Place `tfs.el' in your `load-path'.
   12.81+;;   2. In your .emacs file:
   12.82+;;        (require 'tfs)
   12.83+;;        (setq tfs/tf-exe  "c:\\vs2008\\common7\\ide\\tf.exe")
   12.84+;;        (setq tfs/login "/login:domain\\userid,password")
   12.85+;;              -or-
   12.86+;;        (setq tfs/login (getenv "TFSLOGIN"))
   12.87+;;   3. also in your .emacs file:
   12.88+;;        set local or global key bindings for tfs commands.  like so:
   12.89+;;
   12.90+;;        (global-set-key  "\C-xvo" 'tfs/checkout)
   12.91+;;        (global-set-key  "\C-xvi" 'tfs/checkin)
   12.92+;;        (global-set-key  "\C-xvp" 'tfs/properties)
   12.93+;;        (global-set-key  "\C-xvr" 'tfs/rename)
   12.94+;;        (global-set-key  "\C-xvg" 'tfs/get)
   12.95+;;        (global-set-key  "\C-xvh" 'tfs/history)
   12.96+;;        (global-set-key  "\C-xvu" 'tfs/undo)
   12.97+;;        (global-set-key  "\C-xvd" 'tfs/diff)
   12.98+;;        (global-set-key  "\C-xv-" 'tfs/delete)
   12.99+;;        (global-set-key  "\C-xv+" 'tfs/add)
  12.100+;;        (global-set-key  "\C-xvs" 'tfs/status)
  12.101+;;        (global-set-key  "\C-xva" 'tfs/annotate)
  12.102+;;        (global-set-key  "\C-xvw" 'tfs/workitem)
  12.103+;;
  12.104+;;
  12.105+
  12.106+
  12.107+(defvar tfs/tf-exe  "c:\\Program Files\\Microsoft Visual Studio 9.0\\common7\\ide\\tf.exe"
  12.108+  "location of the tf.exe command.  Defaults to \"c:\\Program Files\\Microsoft Visual Studio 9.0\\common7\\ide\\tf.exe\"")
  12.109+
  12.110+(defvar tfs/tfpt-exe  "c:\\Program Files\\Microsoft Team Foundation Server 2008 Power Tools\\TFPT.exe"
  12.111+  "location of the tfpt.exe command.  Defaults to \"c:\\Program Files\\Microsoft Team Foundation Server 2008 Power Tools\\TFPT.exe\"")
  12.112+
  12.113+(defvar tfs/login "/login:domain\\user,password"
  12.114+  "/login option for all TFS activity.")
  12.115+
  12.116+(defvar tfs/buffer-name "*TFS Messages*"
  12.117+  "name of buffer for TFS Messages")
  12.118+
  12.119+
  12.120+
  12.121+;; -------------------------------------------------------
  12.122+;; tfs/checkout
  12.123+;; performs a TFS checkout on the file being visited by the current buffer.
  12.124+(defun tfs/checkout()
  12.125+  "perform a tf checkout (edit) on the file being visited by the current buffer.  Checkout happens only if the file is non-writable now."
  12.126+  (interactive)
  12.127+  (if buffer-file-name
  12.128+      (if (not (file-writable-p buffer-file-name))
  12.129+          (let ((command (list tfs/tf-exe "checkout" buffer-file-name tfs/login ) )
  12.130+                (exitcode nil)
  12.131+                (shortname (file-name-nondirectory buffer-file-name))
  12.132+                )
  12.133+            (tfs/append-to-message-buffer (concat "checkout " shortname "\n"))
  12.134+            (setq exitcode (apply 'call-process
  12.135+                                  (car command)
  12.136+                                  nil
  12.137+                                  tfs/buffer-name
  12.138+                                  nil
  12.139+                                  (cdr command)))
  12.140+            (if (equal exitcode 0)
  12.141+                ;; get the checked-out version
  12.142+                (revert-buffer t t)
  12.143+              (error "Checkout of %s was unsuccessful (%S)" buffer-file-name exitcode)))
  12.144+        )
  12.145+    (error "tfs/checkout: No file")
  12.146+    )
  12.147+  )
  12.148+
  12.149+
  12.150+
  12.151+;; -------------------------------------------------------
  12.152+;; tfs/checkin
  12.153+;; performs a TFS checkin on the file being visited by the current buffer.
  12.154+(defun tfs/checkin()
  12.155+  "perform a tf checkin on the file being visited by the current buffer.  Checkin happens only if the file is writable now."
  12.156+  (interactive)
  12.157+  (if buffer-file-name
  12.158+      (if (file-writable-p buffer-file-name)
  12.159+          (let* (
  12.160+                 (exitcode nil)
  12.161+                 (shortname (file-name-nondirectory buffer-file-name))
  12.162+                 (comment (read-string (format "Comment for %s: " shortname) nil nil nil))
  12.163+                 (command (list tfs/tf-exe "checkin" (format "/comment:%s" comment)
  12.164+                                buffer-file-name tfs/login ) )
  12.165+                 )
  12.166+            (tfs/append-to-message-buffer (concat "checkin " shortname "\n"))
  12.167+            (setq exitcode (apply 'call-process
  12.168+                                  (car command)
  12.169+                                  nil
  12.170+                                  tfs/buffer-name
  12.171+                                  nil
  12.172+                                  (cdr command)))
  12.173+            (if (equal exitcode 0)
  12.174+                ;; revert to the (now) readonly version
  12.175+                (revert-buffer t t)
  12.176+              (error "Checkin of %s was unsuccessful (%S)" buffer-file-name exitcode)))
  12.177+
  12.178+        (error "Cannot checkin %s : the file is not writable" buffer-file-name )
  12.179+        )
  12.180+    (error "tfs/checkin: No file")
  12.181+    )
  12.182+  )
  12.183+
  12.184+
  12.185+
  12.186+;; -------------------------------------------------------
  12.187+;; tfs/rename
  12.188+;; performs a TFS rename on the file being visited by the current buffer.
  12.189+(defun tfs/rename()
  12.190+  "perform a tf rename on the file being visited by the current buffer."
  12.191+  (interactive)
  12.192+  (if buffer-file-name
  12.193+      (let* (
  12.194+             (exitcode nil)
  12.195+             (shortname (file-name-nondirectory buffer-file-name))
  12.196+             (newname (read-string (format "New name for %s: " shortname) nil nil nil))
  12.197+             (command (list tfs/tf-exe "rename" shortname newname tfs/login ))
  12.198+             )
  12.199+        (tfs/append-to-message-buffer (concat "rename " shortname " " newname "\n"))
  12.200+        (setq exitcode (apply 'call-process
  12.201+                              (car command)
  12.202+                              nil
  12.203+                              tfs/buffer-name
  12.204+                              nil
  12.205+                              (cdr command)))
  12.206+        (if (equal exitcode 0)
  12.207+            nil
  12.208+          (error "Rename of %s was unsuccessful (%S)" buffer-file-name exitcode)))
  12.209+
  12.210+    (error "tfs/rename: No file")
  12.211+    )
  12.212+  )
  12.213+
  12.214+
  12.215+
  12.216+;; -------------------------------------------------------
  12.217+;; tfs/add
  12.218+;; performs a TFS add on a file
  12.219+(defun tfs/add()
  12.220+  "perform a tf add on the file being visited by the current buffer."
  12.221+  (interactive)
  12.222+  (if buffer-file-name
  12.223+      (let* (
  12.224+             (shortname (file-name-nondirectory buffer-file-name))
  12.225+             (command  (list tfs/tf-exe "add" shortname  tfs/login ))
  12.226+             (exitcode nil)
  12.227+             )
  12.228+
  12.229+        (tfs/append-to-message-buffer (concat "add " shortname "\n"))
  12.230+        (setq exitcode (apply 'call-process
  12.231+                              (car command)
  12.232+                              nil
  12.233+                              tfs/buffer-name
  12.234+                              nil
  12.235+                              (cdr command)))
  12.236+        (if (equal exitcode 0)
  12.237+            ;; TODO: make this conditional on a verbose setting
  12.238+            ;; After using this package for a while, the Add is sort of
  12.239+            ;; opaque. Hard to know when it's done.  It's nice to get
  12.240+            ;; a confirmation message. The warm and fuzzy factor.
  12.241+            (message (format "Successful add of %s" buffer-file-name ))
  12.242+          (error "Add of %s was unsuccessful (%S)" buffer-file-name exitcode)))
  12.243+
  12.244+    (error "tfs/add: No file")
  12.245+    )
  12.246+  )
  12.247+
  12.248+
  12.249+
  12.250+
  12.251+;; -------------------------------------------------------
  12.252+;; tfs/delete
  12.253+;; performs a TFS delete on a file
  12.254+(defun tfs/delete()
  12.255+  "perform a tf delete on the file being visited by the current buffer."
  12.256+  (interactive)
  12.257+  (if buffer-file-name
  12.258+      (let ((command)
  12.259+            (exitcode nil)
  12.260+            (shortname (file-name-nondirectory buffer-file-name))
  12.261+            )
  12.262+
  12.263+        (if (y-or-n-p (concat "Really delete " shortname  "? "))
  12.264+            (progn
  12.265+              (setq command  (list tfs/tf-exe
  12.266+                                   "delete"
  12.267+                                   shortname  tfs/login ) )
  12.268+              (tfs/append-to-message-buffer (concat "delete " shortname "\n"))
  12.269+              (setq exitcode (apply 'call-process
  12.270+                                    (car command)
  12.271+                                    nil
  12.272+                                    tfs/buffer-name
  12.273+                                    nil
  12.274+                                    (cdr command)))
  12.275+              (if (equal exitcode 0)
  12.276+                  nil
  12.277+                (error "Delete of %s was unsuccessful (%S)" buffer-file-name exitcode)))
  12.278+          )
  12.279+        )
  12.280+    (error "tfs/delete: No file")
  12.281+    )
  12.282+  )
  12.283+
  12.284+
  12.285+
  12.286+
  12.287+;; -------------------------------------------------------
  12.288+;; tfs/get
  12.289+;; performs a TFS get: retrieve a readonly copy of the specified file.
  12.290+;;
  12.291+(defun tfs/get()
  12.292+  "perform a tf get on the specified file. Happens only when the file is not writable. "
  12.293+  (interactive)
  12.294+  (if buffer-file-name
  12.295+      (let ((command (list tfs/tf-exe "get" buffer-file-name tfs/login ) )
  12.296+            (exitcode nil)
  12.297+            (shortname (file-name-nondirectory buffer-file-name))
  12.298+            )
  12.299+        (if (not (file-writable-p buffer-file-name))
  12.300+            (progn
  12.301+              ;;(tfs/prep-message-buffer)
  12.302+              (tfs/append-to-message-buffer (concat "get " shortname "\n"))
  12.303+              (setq exitcode (apply 'call-process
  12.304+                                    (car command)
  12.305+                                    nil
  12.306+                                    tfs/buffer-name
  12.307+                                    nil
  12.308+                                    (cdr command)))
  12.309+              (if (equal exitcode 0)
  12.310+                  ;; get the latest version
  12.311+                  (revert-buffer t t)
  12.312+                (error "Get of %s was unsuccessful (%S)" buffer-file-name exitcode))
  12.313+              )
  12.314+
  12.315+          (error "Will not get %s : the file is writable." shortname)
  12.316+          )
  12.317+        )
  12.318+    (error "tfs/get: No file")
  12.319+    )
  12.320+  )
  12.321+
  12.322+
  12.323+;; -------------------------------------------------------
  12.324+;; tfs/undo
  12.325+;; performs a TFS undo: discards pending changes for the specified file. Happens only when writable.
  12.326+(defun tfs/undo()
  12.327+  "perform a tf undo on the specified file. Happens only when the file is writable. Confirms before discarding edits."
  12.328+  (interactive)
  12.329+  (if buffer-file-name
  12.330+      (let ((command (list tfs/tf-exe "undo" buffer-file-name tfs/login ) )
  12.331+            (exitcode nil)
  12.332+            (shortname (file-name-nondirectory buffer-file-name))
  12.333+            )
  12.334+        (if (file-writable-p buffer-file-name)
  12.335+            (if (y-or-n-p (concat "Discard current changes for " shortname  "? "))
  12.336+                (progn
  12.337+                  (tfs/append-to-message-buffer (concat "undo " shortname "\n"))
  12.338+                  (setq exitcode (apply 'call-process
  12.339+                                        (car command)
  12.340+                                        nil
  12.341+                                        tfs/buffer-name
  12.342+                                        nil
  12.343+                                        (cdr command)))
  12.344+                  (if (equal exitcode 0)
  12.345+                      ;; get the checked-out (reverted) version
  12.346+                      (revert-buffer t t)
  12.347+                    (error "undo on %s was unsuccessful (%S)" buffer-file-name exitcode)
  12.348+                    )
  12.349+                  )
  12.350+              )
  12.351+          (error "cannot undo %s : the file is not writable" shortname)
  12.352+          )
  12.353+        )
  12.354+    (error "tfs/undo: No file")
  12.355+    )
  12.356+  )
  12.357+
  12.358+
  12.359+
  12.360+;; -------------------------------------------------------
  12.361+;; tfs/history
  12.362+;; performs a TFS history: retrieve and display the TFS history of specified file
  12.363+(defun tfs/history()
  12.364+  "perform a tf history on the specified file."
  12.365+  (interactive)
  12.366+  (if buffer-file-name
  12.367+      (let* ((command (list tfs/tf-exe "history" "/format:detailed" buffer-file-name tfs/login ) )
  12.368+             (exitcode nil)
  12.369+             (history-bufname (concat "*TFS-history* " buffer-file-name ))
  12.370+             (shortname (file-name-nondirectory buffer-file-name))
  12.371+             (buffer  (get-buffer-create history-bufname))
  12.372+             )
  12.373+        (save-excursion (set-buffer buffer) (erase-buffer) )
  12.374+        (tfs/append-to-message-buffer (concat "history " shortname "\n"))
  12.375+        (setq exitcode (apply 'call-process
  12.376+                              (car command)
  12.377+                              nil
  12.378+                              history-bufname
  12.379+                              nil
  12.380+                              (cdr command)))
  12.381+        (if (equal exitcode 0)
  12.382+            (display-buffer history-bufname t)
  12.383+          (error "tf history of %s was unsuccessful (%S)" shortname exitcode))
  12.384+        )
  12.385+    (error "tfs/history: No file")
  12.386+    )
  12.387+  )
  12.388+
  12.389+
  12.390+;; -------------------------------------------------------
  12.391+;; tfs/properties
  12.392+;; gets information on the file being visited by the current buffer.
  12.393+;; displays that information in a new temp buffer.
  12.394+(defun tfs/properties()
  12.395+  "does a tf properties: gets TFS properties of the current file. "
  12.396+  (interactive)
  12.397+  (tfs/action "properties" nil)
  12.398+  )
  12.399+
  12.400+
  12.401+
  12.402+
  12.403+;; -------------------------------------------------------
  12.404+;; tfs/action
  12.405+;; gets information on the file being visited by the current buffer.
  12.406+;; diff, properties, etc
  12.407+;; displays that information in a new temp buffer.
  12.408+(defun tfs/action (verb retcode)
  12.409+  "does a tf \"action\": gets a tf query for the current file. "
  12.410+  (interactive)
  12.411+  (if buffer-file-name
  12.412+      (let* ((command (list tfs/tf-exe verb buffer-file-name tfs/login ) )
  12.413+             (exitcode nil)
  12.414+             (info-bufname (concat "*TFS-" verb "* " buffer-file-name ))
  12.415+             (buffer (get-buffer-create info-bufname))
  12.416+             (shortname (file-name-nondirectory buffer-file-name))
  12.417+             )
  12.418+        (save-excursion (set-buffer buffer) (erase-buffer) )
  12.419+        (tfs/append-to-message-buffer (concat verb  shortname "\n"))
  12.420+        (setq exitcode (apply 'call-process
  12.421+                              (car command)
  12.422+                              nil
  12.423+                              info-bufname
  12.424+                              nil
  12.425+                              (cdr command)))
  12.426+
  12.427+        (if (or (equal exitcode 0) (not (numberp retcode)) (equal exitcode retcode))
  12.428+            (display-buffer info-bufname t)
  12.429+          (error (concat "Get TFS " verb " for %s was unsuccessful (%S)") buffer-file-name exitcode))
  12.430+        )
  12.431+    (error "tfs/%s: No file" verb)
  12.432+    )
  12.433+  )
  12.434+
  12.435+
  12.436+
  12.437+;; -------------------------------------------------------
  12.438+;; tfs/annotate
  12.439+(defun tfs/annotate()
  12.440+  "Gets line-by-line annotation for the file being visited by the current buffer. Displays that information in the annotation viewer. This requires the TFPT.exe tool.  See 'tfs/tfpt-exe'."
  12.441+  (interactive)
  12.442+  (if (file-exists-p tfs/tfpt-exe)
  12.443+      (if buffer-file-name
  12.444+          (let* (
  12.445+                 (exitcode nil)
  12.446+                 (shortname (file-name-nondirectory buffer-file-name))
  12.447+                 (command (list tfs/tfpt-exe "annotate" "/noprompt" shortname tfs/login ) )
  12.448+                 (annotation-bufname  (concat "*TFS annotation* " shortname ))
  12.449+                 (buffer (get-buffer-create annotation-bufname))
  12.450+                 )
  12.451+            (save-excursion (set-buffer buffer) (erase-buffer) )
  12.452+            (message "computing...")
  12.453+            ;;(message (apply 'concat command))
  12.454+            (tfs/append-to-message-buffer (concat "annotate " shortname "\n"))
  12.455+            (setq exitcode (apply 'call-process
  12.456+                                  (car command)
  12.457+                                  nil
  12.458+                                  annotation-bufname
  12.459+                                  nil
  12.460+                                  (cdr command)))
  12.461+
  12.462+            (if (equal exitcode 0)
  12.463+                (progn
  12.464+                  (display-buffer annotation-bufname t)
  12.465+                  (beginning-of-buffer-other-window 0)
  12.466+                  )
  12.467+
  12.468+              (error "Get TFS properties for %s was unsuccessful (%S)" buffer-file-name exitcode))
  12.469+            )
  12.470+        (error "tfs/annotate: No file")
  12.471+        )
  12.472+    (error "%s does not exist. (have you set tfs/tfpt-exe?)"  tfs/tfpt-exe)
  12.473+    )
  12.474+  )
  12.475+
  12.476+
  12.477+;; -------------------------------------------------------
  12.478+;; tfs/thinginfo
  12.479+(defun tfs/thinginfo (exe thing)
  12.480+  "Gets info on a workitem or changeset. This requires the TFPT.exe tool.  See 'tfs/tfpt-exe'."
  12.481+  (interactive)
  12.482+  (if (file-exists-p exe)
  12.483+          (let* (
  12.484+                 (exitcode nil)
  12.485+                 (guess (thing-at-point 'word))
  12.486+                 (item-number (read-string (concat thing ": ")  guess nil nil ))
  12.487+                 (command (list exe thing item-number tfs/login ) )
  12.488+                 (bufname  (concat "*TFS " thing "* " item-number ))
  12.489+                 (buffer (get-buffer-create bufname))
  12.490+                 )
  12.491+            (save-excursion (set-buffer buffer) (erase-buffer) )
  12.492+            ;;(message (apply 'concat command))
  12.493+            (tfs/append-to-message-buffer (concat thing " " item-number "\n"))
  12.494+            (setq exitcode (apply 'call-process
  12.495+                                  (car command)
  12.496+                                  nil
  12.497+                                  bufname
  12.498+                                  nil
  12.499+                                  (cdr command)))
  12.500+
  12.501+            (if (equal exitcode 0)
  12.502+                (progn
  12.503+                  (display-buffer bufname t)
  12.504+                  (beginning-of-buffer-other-window 0)
  12.505+                  )
  12.506+
  12.507+              (error (concat "Get TFS " thing "%s was unsuccessful (%S)" item-number exitcode))
  12.508+            )
  12.509+            )
  12.510+
  12.511+    (error "%s does not exist. (have you set tfs/tfpt-exe or tfs/tf-exe?)"  exe)
  12.512+    )
  12.513+  )
  12.514+
  12.515+
  12.516+;; -------------------------------------------------------
  12.517+;; tfs/workitem
  12.518+(defun tfs/workitem ()
  12.519+  "Gets info on a workitem. This requires the TFPT.exe tool.  See 'tfs/tfpt-exe'."
  12.520+  (interactive)
  12.521+  (tfs/thinginfo  tfs/tfpt-exe "workitem")
  12.522+  )
  12.523+
  12.524+;; -------------------------------------------------------
  12.525+;; tfs/workitem
  12.526+(defun tfs/changeset ()
  12.527+  "Gets info on a changeset. This requires the TFPT.exe tool.  See 'tfs/tfpt-exe'."
  12.528+  (interactive)
  12.529+  (tfs/thinginfo tfs/tf-exe "changeset")
  12.530+  )
  12.531+
  12.532+
  12.533+;; -------------------------------------------------------
  12.534+;; tfs/diff
  12.535+;; diff on the file being visited by the current buffer.
  12.536+(defun tfs/diff()
  12.537+  "does a tf diff on the current file. "
  12.538+  (interactive)
  12.539+  (tfs/action "diff" 100)
  12.540+  )
  12.541+
  12.542+
  12.543+
  12.544+;; -------------------------------------------------------
  12.545+;; tfs/status
  12.546+;; tf status.
  12.547+(defun tfs/status()
  12.548+  "does a tf status. Displays the result in a buffer."
  12.549+  (interactive)
  12.550+  (let* (
  12.551+         (command (list tfs/tf-exe "status" tfs/login ) )
  12.552+         (exitcode nil)
  12.553+         (status-bufname  "*TFS-status*")
  12.554+         (buffer (get-buffer-create status-bufname))
  12.555+         )
  12.556+    (save-excursion (set-buffer buffer) (erase-buffer) )
  12.557+    (tfs/append-to-message-buffer "status\n")
  12.558+    (setq exitcode (apply 'call-process
  12.559+                          (car command)
  12.560+                          nil
  12.561+                          status-bufname
  12.562+                          nil
  12.563+                          (cdr command)))
  12.564+
  12.565+    (if (equal exitcode 0)
  12.566+        (display-buffer status-bufname t)
  12.567+      (error "Get TFS status was unsuccessful (%S)" exitcode))
  12.568+    )
  12.569+  )
  12.570+
  12.571+
  12.572+;; scrolls the TFS Messages buffer to the end, before appending content
  12.573+(defun tfs/prep-message-buffer()
  12.574+  (let ((buf (current-buffer))
  12.575+        (tfsbuffer (get-buffer-create tfs/buffer-name)))
  12.576+    (set-buffer tfsbuffer)
  12.577+    (goto-char (point-max))
  12.578+    (set-buffer buf)
  12.579+    )
  12.580+  )
  12.581+
  12.582+;; append text to the TFS Messages buffer
  12.583+(defun tfs/append-to-message-buffer(text)
  12.584+  (let ((buf (current-buffer))
  12.585+        (tfsbuffer (get-buffer-create tfs/buffer-name)))
  12.586+    (set-buffer tfsbuffer)
  12.587+    (goto-char (point-max))
  12.588+    (insert text)
  12.589+    (set-buffer buf)
  12.590+    )
  12.591+  )
  12.592+
  12.593+
  12.594+(provide 'tfs)
  12.595+
  12.596+
    13.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2+++ b/google-weather.el	Wed Nov 10 15:19:03 2010 +0200
    13.3@@ -0,0 +1,184 @@
    13.4+;;; google-weather.el --- Fetch Google Weather forecasts.
    13.5+
    13.6+;; Copyright (C) 2010 Julien Danjou
    13.7+
    13.8+;; Author: Julien Danjou <julien@danjou.info>
    13.9+;; Keywords: comm
   13.10+
   13.11+;; This file is NOT part of GNU Emacs.
   13.12+
   13.13+;; GNU Emacs is free software: you can redistribute it and/or modify
   13.14+;; it under the terms of the GNU General Public License as published by
   13.15+;; the Free Software Foundation, either version 3 of the License, or
   13.16+;; (at your option) any later version.
   13.17+
   13.18+;; GNU Emacs is distributed in the hope that it will be useful,
   13.19+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
   13.20+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13.21+;; GNU General Public License for more details.
   13.22+
   13.23+;; You should have received a copy of the GNU General Public License
   13.24+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
   13.25+
   13.26+;;; Commentary:
   13.27+;; This module allows you to fetch Google Weather forecast from the
   13.28+;; Internet.
   13.29+;;
   13.30+;;; Code:
   13.31+
   13.32+(require 'url)
   13.33+(require 'url-cache)
   13.34+(require 'xml)
   13.35+(require 'time-date)
   13.36+
   13.37+(eval-when-compile
   13.38+  (require 'cl))
   13.39+
   13.40+(defgroup google-weather nil
   13.41+  "Google Weather."
   13.42+  :group 'comm)
   13.43+
   13.44+(defconst google-weather-url
   13.45+  "http://www.google.com/ig/api"
   13.46+  "URL of the Google Weather API.")
   13.47+
   13.48+(defconst google-weather-image-url
   13.49+  "http://www.google.com"
   13.50+  "URL prefix for images.")
   13.51+
   13.52+(defcustom google-weather-unit-system-temperature-assoc
   13.53+  '(("SI" . "℃")
   13.54+    ("US" . "℉"))
   13.55+  "Find temperature symbol from unit system."
   13.56+  :group 'google-weather)
   13.57+
   13.58+(defun google-weather-cache-expired (url expire-time)
   13.59+  "Check if URL is cached for more than EXPIRE-TIME."
   13.60+  (cond (url-standalone-mode
   13.61+         (not (file-exists-p (url-cache-create-filename url))))
   13.62+        (t (let ((cache-time (url-is-cached url)))
   13.63+             (if cache-time
   13.64+                 (time-less-p
   13.65+                  (time-add
   13.66+                   cache-time
   13.67+                   (seconds-to-time expire-time))
   13.68+                  (current-time))
   13.69+               t)))))
   13.70+
   13.71+(defun google-weather-cache-fetch (url)
   13.72+  "Fetch URL from the cache."
   13.73+  (with-current-buffer (generate-new-buffer " *temp*")
   13.74+    (url-cache-extract (url-cache-create-filename url))
   13.75+    (current-buffer)))
   13.76+
   13.77+(defun google-weather-retrieve-data (url &optional expire-time)
   13.78+  "Retrieve URL and return its data as string.
   13.79+If EXPIRE-TIME is set, the data will be fetched from the cache if
   13.80+their are not older than EXPIRE-TIME seconds. Otherwise, they
   13.81+will be fetched and then cached. Therefore, setting EXPIRE-TIME
   13.82+to 0 force a cache renewal."
   13.83+  (let* ((expired (if expire-time
   13.84+                      (google-weather-cache-expired url expire-time)
   13.85+                    t))
   13.86+         (buffer (if expired
   13.87+                     (url-retrieve-synchronously url)
   13.88+                   (google-weather-cache-fetch url)))
   13.89+         data)
   13.90+    (with-current-buffer buffer
   13.91+      (goto-char (point-min))
   13.92+      (search-forward "\n\n")
   13.93+      (decode-coding-region
   13.94+       (point) (point-max)
   13.95+       (detect-coding-region (point) (point-max) t))
   13.96+      (set-buffer-multibyte t)
   13.97+      (setq data (xml-parse-region (point) (point-max)))
   13.98+      (when (and expired expire-time)
   13.99+        (url-store-in-cache (current-buffer)))
  13.100+      (kill-buffer (current-buffer))
  13.101+      data)))
  13.102+
  13.103+(defun google-weather-build-url (location &optional language)
  13.104+  "Build URL to retrieve weather for LOCATION in LANGUAGE."
  13.105+  (concat google-weather-url "?weather=" (url-hexify-string location)
  13.106+          (when language
  13.107+            (concat "&hl=" language))))
  13.108+
  13.109+(defun google-weather-get-data (location &optional language expire-time)
  13.110+  "Get weather data for LOCATION in LANGUAGE.
  13.111+See `google-weather-retrieve-data' for the use of EXPIRE-TIME."
  13.112+  (google-weather-retrieve-data
  13.113+   (google-weather-build-url location language) expire-time))
  13.114+
  13.115+(defun google-weather-data->weather (data)
  13.116+  "Return all weather information from DATA."
  13.117+  (cddr (assoc 'weather (cdr (assoc 'xml_api_reply data)))))
  13.118+
  13.119+(defun google-weather-data->forecast-information (data)
  13.120+  "Return the forecast information of DATA."
  13.121+  (cddr (assoc 'forecast_information (google-weather-data->weather data))))
  13.122+
  13.123+(defun google-weather-assoc (key data)
  13.124+  "Extract value of field KEY from DATA."
  13.125+  (cdr (assoc 'data (cadr (assoc key data)))))
  13.126+
  13.127+(defun google-weather-data->city (data)
  13.128+  "Return the city where the DATA come from."
  13.129+  (google-weather-assoc
  13.130+   'city
  13.131+   (google-weather-data->forecast-information data)))
  13.132+
  13.133+(defun google-weather-data->postal-code (data)
  13.134+  "Return the postal code where the DATA come from."
  13.135+  (google-weather-assoc
  13.136+   'postal_code
  13.137+   (google-weather-data->forecast-information data)))
  13.138+
  13.139+(defun google-weather-data->unit-system (data)
  13.140+  "Return the unit system used for DATA."
  13.141+  (google-weather-assoc
  13.142+   'unit_system
  13.143+   (google-weather-data->forecast-information data)))
  13.144+
  13.145+(defun google-weather-data->forecast-date (data)
  13.146+  "Return the unit system used for DATA."
  13.147+  (google-weather-assoc
  13.148+   'forecast_date
  13.149+   (google-weather-data->forecast-information data)))
  13.150+
  13.151+(defun google-weather-data->forecast (data)
  13.152+  "Get forecast list from DATA."
  13.153+  ;; Compute date of the forecast in the same format as `current-time'
  13.154+  (let ((date (apply 'encode-time
  13.155+                     (parse-time-string
  13.156+                      (concat (google-weather-data->forecast-date data) " 00:00:00")))))
  13.157+    (mapcar
  13.158+     (lambda (forecast)
  13.159+       (let* ((forecast-date (decode-time date))
  13.160+              (forecast-encoded-date (list (nth 4 forecast-date)
  13.161+                                           (nth 3 forecast-date)
  13.162+                                           (nth 5 forecast-date))))
  13.163+         ;; Add one day to `date'
  13.164+         (setq date (time-add date (days-to-time 1)))
  13.165+         `(,forecast-encoded-date
  13.166+           (low ,(google-weather-assoc 'low forecast))
  13.167+           (high ,(google-weather-assoc 'high forecast))
  13.168+           (icon ,(concat google-weather-image-url
  13.169+                          (google-weather-assoc 'icon forecast)))
  13.170+           (condition ,(google-weather-assoc 'condition forecast)))))
  13.171+     (loop for entry in (google-weather-data->weather data)
  13.172+           when (eq (car entry) 'forecast_conditions)
  13.173+           collect entry))))
  13.174+
  13.175+(defun google-weather-data->forecast-for-date (data date)
  13.176+  "Return forecast for DATE from DATA.
  13.177+DATE should be in the same format used by calendar,
  13.178+i.e. (MONTH DAY YEAR)."
  13.179+  (cdr (assoc date (google-weather-data->forecast data))))
  13.180+
  13.181+(defun google-weather-data->temperature-symbol (data)
  13.182+  "Return the temperature to be used according in DATA.
  13.183+It uses `google-weather-unit-system-temperature-assoc' to find a
  13.184+match."
  13.185+  (cdr (assoc (google-weather-data->unit-system data) google-weather-unit-system-temperature-assoc)))
  13.186+
  13.187+(provide 'google-weather)