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("+ ");
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)