Commits

Mike Steder committed 506dd12

Added csharp mode and changed default C/C++ indent style and switched to 4-space indents.

  • Participants
  • Parent commits 504d12e

Comments (0)

Files changed (11)

 (add-to-list 'load-path "~/emacs.d")
 (add-to-list 'load-path "~/etc/emacs.d")
 (add-to-list 'load-path "~/etc/emacs.d/color-theme-6.6.0")
+(add-to-list 'load-path "~/etc/emacs.d/CsharpToolsForEmacs")
+
 ;; Emacs config menus will write customizations
 ;; to this file:
 (setq custom-file "~/etc/emacs.d/custom.el")
 ;(load "menu.el")
 (load "remote.el")
 
+(load "csharp-mode.el")
+
 ;; Speedbar!
 ;(require 'sr-speedbar)
 

File emacs.d/CsharpToolsForEmacs/CscompUtilities.dll

Binary file added.

File emacs.d/CsharpToolsForEmacs/CscompUtilities.pdb

Binary file added.

File emacs.d/CsharpToolsForEmacs/Readme.txt

+Mon, 24 May 2010  17:21
+
+This is the readme for csharp-mode.
+
+You can use csharp-mode alone.  To do so,
+
+
+ put this in your .emacs:
+
+   (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t)
+
+ or:
+
+   (require 'csharp-mode)
+
+
+ AND:
+
+   (setq auto-mode-alist
+      (append '(("\\.cs$" . csharp-mode)) auto-mode-alist))
+   (defun my-csharp-mode-fn ()
+      "function that runs when csharp-mode is initialized for a buffer."
+      ...insert your code here...
+      ...most commonly, your custom key bindings ...
+   )
+   (add-hook  'csharp-mode-hook 'my-csharp-mode-fn t)
+
+
+=======================================================
+
+You can also take advantage of C# code completion.
+To do so, put csharp-completion.el, csharp-shell.el , and powershell.el
+on your load-path.
+
+You must also have semantic, from the CEDET package, on your load path.
+
+Put the CscompUtilities.dll in the same location as csharp-shell.el.
+
+Put this in your .emacs file:
+
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; C# code completion (requires CEDET semantic)
+
+    (setq load-path
+          (append '("~/users/dinoch/elisp/cedet/semantic"
+                    "~/users/dinoch/elisp/cedet/semantic/bovine"
+                    "~/users/dinoch/elisp/cedet/common"
+                    "~/users/dinoch/elisp/cedet/eieio"
+                    "~/users/dinoch/elisp/cedet/contrib"
+                    )  load-path ))
+
+    (load "semantic")
+    (load "semantic-load")
+    (load "wisent-csharp")
+
+    (require 'csharp-completion)
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+In your csharp-mode-hook, bind a key to the cscomp completion trigger.
+Like this:
+
+         ;; C# code completion
+         (local-set-key "\M-\\"   'cscomp-complete-at-point)
+         (local-set-key "\M-\."   'cscomp-complete-at-point-menu)
+
+
+

File emacs.d/CsharpToolsForEmacs/aspx-mode.el

+;;; aspx-mode.el --- mode for editing ASPX files
+;;
+;; Copyright (C) 2010  Dino Chiesa
+;;
+;; Author:   Dino Chiesa <dpchiesa@hotmail.com>
+;; Created:  May 2010
+;; Version:  0.1
+;; Keywords: C#, languages, extensions, files
+;; URL:      ???
+;;
+;; This is an emacs mode for editing single-file ASPX modules,
+;; which can contain HTML, javascript, C# or VB, and
+;; CSS code.
+;;
+;; It relies on multi-mode.
+;; (see http://www.loveshack.ukfsn.org/emacs )
+;;
+;; It provides context-sensitive fontification and indent in all of the
+;; various chunks o an ASPX file. Browser-side Javascript within script
+;; blocks gets fontified correctly. Server-side script blocks get
+;; fontified properly. CSS gets indented and fontified. And of course
+;; HTML.
+;;
+;; It relies on espresso for the javascript mode, css-mode for CSS,
+;; html-mode for HTML, and csharp-mode 0.7.5 or later for the
+;; server-side c# code.
+;;
+;; Bugs:
+;;
+;;  - The fontification sort of turns on and off as you cursor through
+;;    the buffer, making for a somewhat odd user experience.
+;;
+;;  - the fontification sometimes doesn't happen within a chunk, til you
+;;    modify the text within the chunk.  There's probably a fix for
+;;    this.
+;;
+;;
+;; Thu, 13 May 2010  23:44
+;;
+;; Licensed according to the Microsoft Public License (Ms-PL)
+;;
+;; This license governs use of the accompanying software. If you use
+;; the software, you accept this license. If you do not accept the
+;; license, do not use the software.
+;;
+;; 1. Definitions
+;;
+;; The terms "reproduce," "reproduction," "derivative
+;; works," and "distribution" have the same meaning here as under
+;; U.S. copyright law.
+;;
+;; A "contribution" is the original software, or any additions or
+;; changes to the software.
+;;
+;; A "contributor" is any person that distributes its contribution
+;; under this license.
+;;
+;; "Licensed patents" are a contributor's patent claims that read
+;; directly on its contribution.
+;;
+;; 2. Grant of Rights
+;;
+;; (A) Copyright Grant- Subject to the terms of this license,
+;; including the license conditions and limitations in section 3,
+;; each contributor grants you a non-exclusive, worldwide,
+;; royalty-free copyright license to reproduce its contribution,
+;; prepare derivative works of its contribution, and distribute its
+;; contribution or any derivative works that you create.
+;;
+;; (B) Patent Grant- Subject to the terms of this license, including
+;; the license conditions and limitations in section 3, each
+;; contributor grants you a non-exclusive, worldwide, royalty-free
+;; license under its licensed patents to make, have made, use, sell,
+;; offer for sale, import, and/or otherwise dispose of its
+;; contribution in the software or derivative works of the
+;; contribution in the software.
+;;
+;; 3. Conditions and Limitations
+;;
+;; (A) No Trademark License- This license does not grant you rights
+;; to use any contributors' name, logo, or trademarks.
+;;
+;; (B) If you bring a patent claim against any contributor over
+;; patents that you claim are infringed by the software, your patent
+;; license from such contributor to the software ends automatically.
+;;
+;; (C) If you distribute any portion of the software, you must
+;; retain all copyright, patent, trademark, and attribution notices
+;; that are present in the software.
+;;
+;; (D) If you distribute any portion of the software in source code
+;; form, you may do so only under this license by including a
+;; complete copy of this license with your distribution. If you
+;; distribute any portion of the software in compiled or object code
+;; form, you may only do so under a license that complies with this
+;; license.
+;;
+;; (E) The software is licensed "as-is." You bear the risk of using
+;; it. The contributors give no express warranties, guarantees or
+;; conditions. You may have additional consumer rights under your
+;; local laws which this license cannot change. To the extent
+;; permitted under your local laws, the contributors exclude the
+;; implied warranties of merchantability, fitness for a particular
+;; purpose and non-infringement.
+;;
+;;;
+
+
+(require 'multi-mode)
+(require 'csharp-mode)
+(require 'espresso "espresso.el")
+;;(require 'javascript-mode "javascript.el")
+(require 'css-mode)
+
+
+
+(defvar aspx-mode-log-level 0
+  "The current log level for operatopms specific to aspx-mode.
+0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY. ")
+
+
+(defun aspx-mode-log (level text &rest args)
+  "Log a message at level LEVEL.
+If LEVEL is higher than `aspx-mode-log-level', the message is
+ignored.  Otherwise, it is printed using `message'.
+TEXT is a format control string, and the remaining arguments ARGS
+are the string substitutions (see `format')."
+  (if (<= level aspx-mode-log-level)
+      (let* ((msg (apply 'format text args)))
+        (message "aspx-mode: %s" msg))
+    t))
+
+
+(defconst aspx-mode-server-lang-re
+  "\\([Cc]#\\|[Vv][Bb]\\)"
+  "Regex for matching on the ASPX langauge.")
+
+
+(defconst aspx-mode-server-script-start-re
+  (concat
+   "<\\(script\\|SCRIPT\\)[ \t\n\r\v\f]+"
+   "\\("
+   "language=[\"']"
+   aspx-mode-server-lang-re
+   "[\"'][ \t\n\r\v\f]+runat=[\"']server[\"']"
+   "\\|"
+   "runat=[\"']server[\"'][ \t\n\r\v\f]+language=[\"']"
+   aspx-mode-server-lang-re
+   "[\"']"
+   "\\)[ \t\n\r\v\f]*>"
+   )
+"Regex for matching the <script> tag that begins a block of
+ASPX server-side code.  It tries to match on <script language='C#' runat='server'...>
+as well as <script runat='server' language='C#' ...>
+" )
+
+
+(defconst aspx-mode-page-decl-re
+  (concat
+   "<%@"
+   "[ \t\n\r\v\f]+"
+   "\\(Page\\|Control\\)"
+   "[ \t\n\r\v\f]+"
+   )
+
+  "Regex for matching the page/control declaration"
+  )
+
+
+(defconst aspx-mode-browser-script-start-re
+  (concat
+   "<\\(script\\|SCRIPT\\)[ \t\n\r\v\f]+"
+   "\\("
+   "type=[\"']text/javascript[\"'][ \t\n\r\v\f]+language=[\"'][Jj]ava[Ss]cript[\"']"
+   "\\|"
+   "language=[\"'][Jj]ava[Ss]cript[\"'][ \t\n\r\v\f]+type=[\"']text/javascript[\"']"
+   "\\|"
+   "type=[\"']text/javascript[\"']"
+   "\\|"
+   "language=[\"'][Jj]ava[Ss]cript[\"']"
+   "\\)")
+
+"Regex for matching the <script> tag that begins a block of
+browser-side javascript code.  It tries to match on
+<script language='javascript' ...>  or
+<script type='text/javascript' ...>  or
+<script type='text/javascript' language='javascript' ...> or
+<script language='javascript' type='text/javascript' ...>
+")
+
+
+(defconst aspx-mode-css-block-start-re
+  (concat
+   "<\\(style\\|STYLE\\)"
+   "[ \t\n\r\v\f]+"
+   "type=[\"']text/css[\"']"
+   "[ \t\n\r\v\f]*"
+   ">")
+  "Regex to match the beginning of a CSS block."
+  )
+
+
+
+(defvar aspx-mode--last-chunk-result nil
+  "cached result of the last chunk analysis")
+
+(defvar aspx-mode-update-interval 1
+  "The amount of time in seconds after the last change before trying to
+re-fontify the current block.")
+
+(defvar aspx-mode-timer nil)
+
+
+
+
+
+;; When in multi-mode, I want espresso to indent to the
+;; <script> tag.  Use advice on the espresso indentation
+;; calculation, to make that happen.
+(defadvice espresso--proper-indentation (after
+                                         aspx-mode-advice-1
+                                         compile activate)
+  (if (and (boundp 'multi-mode)
+           multi-mode)
+      (if (eq ad-return-value 0)
+          (setq ad-return-value (+ ad-return-value 4)))))
+
+
+
+
+;; =======================================================
+;; dinoch - Thu, 13 May 2010  23:38
+;; factored out so that I can attach advice to it.
+;; Did this for multi-mode support in ASPX files.
+;; =======================================================
+(defun css--proper-indentation ()
+  (save-excursion
+    (back-to-indentation)
+    (let ((p (parse-partial-sexp (point-min) (point)))
+          (end-brace-p (looking-at "}")))
+      (cond
+       ((or (nth 8 p) (looking-at "/[/*]"))
+        (current-indentation))
+       ((save-excursion
+          (and (skip-chars-backward " \t\n:,")
+               (looking-at "[:,]")))
+        (save-excursion
+          (css-re-search-backward "^[ \t]*\\w")
+          (+ (current-indentation) css-indent-level)))
+       ((nth 1 p)
+        (save-excursion
+          (goto-char (nth 1 p))
+          (+ (current-indentation) (if end-brace-p 0 css-indent-level))))
+       (t
+        0)))))
+
+
+(defun css-indent-line ()
+  (interactive)
+  (let ((indent (css--proper-indentation))
+        (offset (- (current-column) (current-indentation))))
+    (indent-line-to indent)
+    (if (> offset 0) (forward-char offset))))
+
+
+
+;; Likewise with css-mode indentation.
+(defadvice css--proper-indentation (after
+                                    aspx-mode-advice-2
+                                    compile activate)
+  (if (and (boundp 'multi-mode)
+           multi-mode)
+      (if (eq ad-return-value 0)
+          (setq ad-return-value (+ ad-return-value 4)))))
+
+
+
+
+
+
+(defun aspx-mode-timer-elapsed ()
+  (aspx-mode-log 2 "timer fired.")
+  ;;(run-hooks 'aspx-mode-timer-elapsed-hook)
+  (aspx-mode-refontify-current-chunk-after-idle))
+
+
+(defun aspx-mode-restart-timer ()
+  (if (timerp aspx-mode-timer) (cancel-timer aspx-mode-timer))
+  (setq aspx-mode-timer
+        (run-with-timer aspx-mode-update-interval nil 'aspx-mode-timer-elapsed)))
+
+(defun aspx-mode-after-change-fn (begin end length)
+  (aspx-mode-maybe-invalidate-cached-chunk begin end length)
+  (if multi-mode (aspx-mode-restart-timer)))
+
+
+
+(defun aspx-mode-maybe-invalidate-cached-chunk (begin end old-length)
+  (let ((new-length (- end begin))
+        (old-end (+ begin old-length)))
+
+    ;; Invalidate if the length changed (we need to recalc the chunk limits)
+    ;; or if the change traversed the end of the chunk.
+    (if (and aspx-mode--last-chunk-result
+             (or (/= old-length new-length)
+                 (>= old-end  (nth 2 aspx-mode--last-chunk-result))))
+        (setq aspx-mode--last-chunk-result nil))))
+
+
+
+(defun aspx-mode-refontify-current-chunk-after-idle ()
+  "Fontify the current (cached) chunk.  This fn is called after a timer
+expires, when the buffer has sats idle for 2s.
+"
+  (aspx-mode-log 2 "fontifying (%d %d)"
+           (nth 1 aspx-mode--last-chunk-result)
+           (nth 2 aspx-mode--last-chunk-result))
+
+  (if aspx-mode--last-chunk-result
+      ;; Remove text props in the chunk, to force a new fontification
+      ;; later.  Do this within a save-buffer-state, because we're not
+      ;; *really* changing the buffer.
+      (c-save-buffer-state  ()
+        (set-text-properties (nth 1 aspx-mode--last-chunk-result)
+                             (nth 2 aspx-mode--last-chunk-result)
+                             nil))))
+
+
+
+
+
+
+(defun aspx-mode-determine-current-chunk (pos)
+  "Determine the type (mode) and limits of the chunk at POS.
+Return (MODE START END), where MODE is one of `csharp-mode',
+`javascript-mode', `html-mode', or `css-mode',
+and START and END are the limits of the chunk.
+
+Or, maybe return nil if not sure what mode it should be.
+I don't know. The doc is thin and the code is impenetrable.
+
+This method attempts to cache the calculated result and use it
+intelligently.  For example if the first execution determines
+that the POS is within a C# chunk, the limits of that chunk
+are cached. If a subsequent invocation of this method provides a
+POS that is within those limits, the function can safely return
+the same chunk response, without further scanning.
+
+This works as long as the buffer hasn't changed - in other words
+it's just cursor navigation.
+"
+
+  ;; If we're in the right zone, then use the cached value.
+  ;; Don't use the cache if it is HTML mode, because an HTML
+  ;; chunk can contain a javascript chunk, a CSS chunk, a
+  ;; csharp chunk.
+  (if (and aspx-mode--last-chunk-result
+           (> pos (nth 1 aspx-mode--last-chunk-result))
+           (< pos (nth 2 aspx-mode--last-chunk-result))
+           (not (eq 'html-mode (nth 0 aspx-mode--last-chunk-result))))
+      (progn
+        (aspx-mode-log 3 "determine-chunk: pos %d chunk cache %s"
+                       pos
+                       (prin1-to-string aspx-mode--last-chunk-result))
+        aspx-mode--last-chunk-result)
+
+    (let ((mode 'html-mode)
+          (start-of-block (point-min))
+          (end-of-block (point-max))
+          sp ep
+          new-result)
+
+      (save-excursion
+        (save-restriction
+          (widen)
+          (goto-char pos)
+          (cond
+
+           ;; Between <script language='javascript' ..> and </script>?
+           ((save-excursion
+              (and (and (re-search-backward aspx-mode-browser-script-start-re nil t)
+                        (setq sp (match-end 0)))
+                   (and (re-search-forward "</\\(script\\|SCRIPT\\)>" nil t)
+                        (setq ep (line-beginning-position)))
+                   (> ep pos)))
+
+            (setq
+             ;;mode 'javascript-mode
+             mode 'espresso-mode
+             start-of-block sp
+             end-of-block (1- ep) ))
+
+
+           ;; Between <style type="text/css"> and </style>?
+           ((save-excursion
+              (and (and (re-search-backward aspx-mode-css-block-start-re nil t)
+                        (setq sp (match-end 0)))
+                   (and (re-search-forward "</\\(style\\|style\\)>" nil t)
+                        (setq ep (line-beginning-position)))
+                   (> ep pos)))
+            (setq mode 'css-mode
+                  start-of-block sp
+                  end-of-block (1- ep) ))
+
+
+           ;; Between <script language='??'  runat='server'> and </script>?
+           ((save-excursion
+              (and (and (re-search-backward aspx-mode-server-script-start-re nil t)
+                        (setq sp (match-end 0)))
+                   (and (re-search-forward "</\\(script\\|SCRIPT\\)>" nil t)
+                        (setq ep (line-beginning-position)))
+                   (> ep pos)))
+
+            ;; TODO: support VBNET-mode, too.  Check the language at the
+            ;; start block.
+            (setq mode 'csharp-mode
+                  start-of-block sp
+                  end-of-block (1- ep) ))
+
+           ;; Between <%@ Page...>  and the first <html>
+           ((save-excursion
+              (and (and (re-search-forward "<\\(html\\|HTML\\)>" nil t)
+                        (setq ep (line-beginning-position)))
+                   (> ep pos)))
+
+            ;; TODO: support VBNET-mode, too.  Check the specified language at the
+            ;; start block.
+            ;; This works only because csharp-mode has smarts to fontify the
+            ;; @Page directive.
+            (setq mode 'csharp-mode
+                  start-of-block 1
+                  end-of-block (1- ep) ))
+
+
+
+           ;;              ;; Between <html..> and </html>
+           ;;              ((save-excursion
+           ;;                 (and (and (re-search-backward "<\\(HTML\\|html\\)>" nil t)
+           ;;                           (setq sp (match-beginning 0)))
+           ;;                      (and (re-search-forward "</\\(html\\|HTML\\)>" nil t)
+           ;;                           (setq ep (line-end-position)))
+           ;;                      (> ep pos)))
+           ;;               (setq mode 'html-mode
+           ;;                     start-of-block sp
+           ;;                     end-of-block (1- ep) ))
+
+           (t
+            nil))))
+
+      ;; multi-make-list does not actually make a new list.
+      ;; Instead it destructively modifies the existing list.
+      ;; The doc says it wants to avoid producing a cons cell
+      ;; in the post-command-hook.
+      ;; Therefore, to cache the result, we need to actually
+      ;; cons a distinct list.  To check that the new item is
+      ;; distinct, we need to compare each elt in the list.
+      ;; If that's the case, start a timer.
+      (setq new-result (list mode start-of-block end-of-block))
+
+      (if (or (not (eq (nth 0 new-result) (nth 0 aspx-mode--last-chunk-result)))
+              (not (eq (nth 1 new-result) (nth 1 aspx-mode--last-chunk-result)))
+              (not (eq (nth 2 new-result) (nth 2 aspx-mode--last-chunk-result))))
+          (progn
+            (aspx-mode-log 3 "new chunk, restart timer")
+            (aspx-mode-restart-timer)))
+
+      (setq aspx-mode--last-chunk-result
+            (multi-make-list mode start-of-block end-of-block))
+
+      )))
+
+
+
+(defun aspx-mode ()
+  "Mode for editing ASPX files with embedded C# script blocks,
+as well as CSS, Javascript, and HTML.
+"
+  (interactive)
+  (set (make-local-variable 'multi-mode-alist)
+       ;; This is a very odd data structure. It doesn't make sense that
+       ;; it is formatted this way. The documentation is completely
+       ;; unhelpful.
+       '(
+         (csharp-mode      . aspx-mode-determine-current-chunk)
+         (espresso-mode    . nil)  ;; javascript
+         (css-mode         . nil)
+         (html-mode        . nil)
+         ))
+  (add-hook 'after-change-functions 'aspx-mode-after-change-fn nil t)
+  (multi-mode-install-modes))
+
+
+
+
+
+(provide 'aspx-mode)

File emacs.d/CsharpToolsForEmacs/csharp-completion.el

+;;; csharp-completion.el -- Smart code completion for C#
+;;
+;; Author:     Dino Chiesa <dpchiesa@hotmail.com>
+;; Maintainer: Dino Chiesa <dpchiesa@hotmail.com>
+;; Created:    April 2010
+;; Modified:   April 2010
+;; Version:    0.1.5
+;; Keywords:   c# languages oop mode
+;; X-URL:      http://code.google.com/p/csharpmode/
+;;
+;;
+;;; Commentary:
+;;
+;;    This is a code-completion or "intellisense" package for C#.  The
+;;    scope of this module is much smaller that a full "development
+;;    envvironment".  It does smart code completion for C#, in
+;;    emacs. It does not do font-lock, indenting, debugging,
+;;    compiling, profiling, and so on.
+;;
+;;    To use it, place the cursor after a partially-completed
+;;    statement, and invoke `cscomp-complete-at-point'.  Normally this
+;;    would be bound to a particular keystroke, like M-.  This module
+;;    will insert the first completion that matches. If multiple
+;;    completions are possible, calling the completion function again
+;;    will cycle through the possibilities, similar to the way
+;;    dabbrev-mode works.
+;;
+;;    You can also call `cscomp-complete-at-point-menu', and get a popup
+;;    menu of the completion choices.
+;;
+;;    There are 2 complementary sources of information for the
+;;    completions: introspection into compiled .NET class libraries
+;;    (like the base class library), and parse analysis from the
+;;    semantic.el package, which is part of CEDET. In the typical
+;;    case, this module uses both of those sources of information,
+;;    together.
+;;
+;;    The reflection is done by an inferior powershell shell running
+;;    within emacs, that has loaded a custom .NET assembly.  The
+;;    library exposes static methods that perform type reflection,
+;;    using the capabilities of the System.Reflection namespace. These
+;;    methods then return strings which are lisp s-expressions that
+;;    can be eval'd, resulting in structures containing information
+;;    for a given type - including the available methods, fields and
+;;    properties, and the attributes on same.  This piece of the
+;;    puzzle is called the "CscompShell".
+;;
+;;    As an example, suppose your code has a local variable of type
+;;    System.Xml.XmlDocument, named doc.  Suppose the user asks for
+;;    completion on that variable.  The module uses the semantic parse
+;;    data to identify the name and type of the local variable.  It then
+;;    sends a "GetTypeInfo" command to the CscompShell, passing
+;;    System.Xml.XmlDocument. The CscompShell returns an s-expression
+;;    enumerating the fields, methods and properties for that type.
+;;    This s-expression is then used to populate the completion list.
+;;
+;;
+;; Here's a survey of the situations in which this module can offer
+;; completions:
+;;
+;;    a. names of local variables, instance variables, and method arguments.
+;;
+;;         void Method1(String longArgumentName)
+;;         {
+;;            long?
+;;         }
+;;
+;;    b. Methods, fields and properties (m/f/p) on a local variable
+;;       with known type, on method arguments of known type, or on
+;;       instance variables of known type:
+;;
+;;         String x = "this is a string";
+;;         x.?
+;;
+;;    c. M/f/p on local variables with var type:
+;;
+;;         var x = "this is a string";
+;;         x.?
+;;
+;;    d. Cascading local variable declarations of var type:
+;;
+;;         var s = "This is a string";
+;;         var length = s.Length;
+;;         var radix = length.?
+;;
+;;    e. completion on generic types:
+;;
+;;         var x = new List<String>();
+;;         x.?
+;;
+;;    f. completion on local variables that are initialized
+;;       from instance methods and variables.
+;;
+;;         void method1()
+;;         {
+;;           var length = this.InstanceMethod();
+;;           length.?
+;;         }
+;;
+;;    g. constructor completion, provide template when completing
+;;
+;;         var x = new System.String(?
+;;
+;;    h. constructor completion as above, with unqualified type.
+;;
+;;         var x = new TimeSpan(?
+;;
+;;    i. finding constructors among qualified and unqualified types
+;;
+;;         var x = new TimeS?
+;;
+;;    j. complete static methods on known types,
+;;       whether fully qualified or unqualified.
+;;
+;;         String.Jo?
+;;
+;;    k. present template fpr static methods on known types,
+;;       whether fully qualified or unqualified.
+;;
+;;         String.Join(?
+;;
+;;    l. Immediate values.
+;;
+;;         7.C?
+;;
+;;    m. other compound Expressions:
+;;
+;;         Path.GetRandomFileName().Normalize().?
+;;
+;;
+;;
+;; =======================================================
+;;
+;; Dependencies:
+;;
+;;   cc-mode 5.31.?
+;;
+;;   semantic.el 1.0pre7
+;;
+;;   optionally, yasnippet, for snippet insertion.  If the user has
+;;     yasnippet loaded, then this completion module will insert
+;;     a snippet (template) when the user selects a Method from the
+;;     completion list menu.  The method snippet will have all the
+;;     method parameters as placeholders; the developer then types over
+;;     those placeholders to supply the actual method parameters.
+;;     If yasnippet is not loaded, then the completion is just
+;;     the method name, and the developer has to fill in the
+;;     param-list himself.
+;;
+;;   PowerShell, and a separate DLL that must run in Powershell.  That
+;;     DLL is implemented in C#.
+;;
+;;
+;;
+;;
+;; Known bugs/problems :
+;;
+;;    1. The module does not do completion on anonymous (var) types in
+;;       for loops.
+;;
+;;
+;;
+;; TODO :
+;;
+;;    make an installer.
+;;
+;; Please send any comments, bugs, or upgrade requests to
+;; Dino Chiesa (dpchiesa@hotmail.com)
+;;
+
+
+(require 'csharp-shell)
+
+(require 'semantic-idle)  ;; for ... reparsing a buffer
+
+
+;; Design notes:
+;;
+;; Tue, 04 May 2010  10:47
+;;
+;; This completion depends on the semantic package for parsing a C#
+;; buffer.  That gives the module a way to interrogate the names and
+;; types of local and instance variables, in order to do completion on
+;; them.
+;;
+;; Semantic also provides the list of using statements for a C# module,
+;; which tells us which assemblies we need to search in, for
+;; completions.  These are then loaded into CscompShell for interrogation.
+;;
+
+
+
+(defvar cscomp-current-list nil
+  "The list of all the completion. Each element of the list is
+either a string, or a list which the car is the possible completion,
+and the cadr is an additional information about this completion.")
+
+(defvar cscomp-current-list-index nil
+  "An index to an element in cscomp-current-list. This is used to
+cycle the list.")
+
+(defvar cscomp-current-fragment nil
+  "The current fragment we're trying to complete. This is used to trim the thing that gets inserted.")
+
+(defvar cscomp-current-beginning (make-marker)
+  "The beginning of the region where the last completion was inserted.")
+
+(defvar cscomp-current-end (make-marker)
+  "The end of the region where the last completion was inserted.")
+
+(defvar cscomp-typeinfo-cache nil)
+
+(defcustom cscomp-typeinfo-cache-size 150
+  "The max size of completion buffer cache, in entries."
+  :group 'cscomp
+  :type 'integer)
+
+
+
+(defun cscomp-referenced-assemblies-list ()
+  "Return the list of .NET namespaces referenced in the
+current buffer via using statements. It uses the semantic parser
+table to find the 'using' statements. "
+  (interactive)
+  (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
+  (let* ((tokens  (semantic-fetch-tags))
+         ;;(usings (semantic-find-nonterminal-by-token (quote include) tokens))
+         (usings (semantic-brute-find-tag-by-class 'include tokens)))
+    (cscomp-log 3 "cscomp-referenced-assemblies-list: found using statements: '%s'" usings)
+    (mapcar 'car usings)))
+
+
+
+(defun cscomp-instance-vars ()
+  "Return the list of instance variables in a C# module.
+This uses the semantic parser table to find the variable
+declarations.
+
+The return value is a list of semantic tags.  Looks like:
+
+\((\"flavor\" variable
+             (:type \"int\")
+             (reparse-symbol class_member_declaration) #<overlay from 580 to 595 in a.cs>)
+ (\"flicky\" variable
+             (:type \"String\")
+             (reparse-symbol class_member_declaration) #<overlay from 604 to 636 in a.cs>)
+ (\"label\" variable
+            (:type \"String\")
+            (reparse-symbol class_member_declaration) #<overlay from 645 to 669 in a.cs>))
+
+"
+
+  (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
+  (semantic-fetch-tags)
+  (let* ((class  (cscomp-find-enclosing-csharp-class))        ;; the enclosing class
+         (tokens (semantic-tag-type-members class))                  ;; the members of that class
+         (vars (semantic-brute-find-tag-by-class 'variable tokens))) ;; the members that are variables
+    (cscomp-log 3 "cscomp-instance-vars: found instance vars: '%s'" vars)
+    vars))
+
+
+
+
+(defun cscomp-instance-members ()
+  "Return the list of instance members in a C# module.
+This uses the semantic parser table to find the memebr
+declarations.
+
+The return value is a list of semantic tags.  Looks like:
+
+\((\"flavor\" variable
+             (:type \"int\")
+             (reparse-symbol class_member_declaration) #<overlay from 580 to 595 in a.cs>)
+ (\"Hello\" function
+             (:type \"String\")
+             (reparse-symbol class_member_declaration) #<overlay from 604 to 636 in a.cs>)
+ (\"label\" variable
+            (:type \"String\")
+            (reparse-symbol class_member_declaration) #<overlay from 645 to 669 in a.cs>))
+
+"
+
+  (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
+  (semantic-fetch-tags)
+  (let ((class  (cscomp-find-enclosing-csharp-class))) ;; the enclosing class
+    (semantic-tag-type-members class)))                       ;; the members of that class
+
+
+
+
+(defun cscomp--find-matching-tags (name-fragment tagset &optional local)
+  "Return the list of tags from a given set, that
+match NAME-FRAGMENT.  This is used by `cscomp-matching-local-vars',
+`cscomp-matching-instance-vars',
+`cscomp-matching-instance-members'.
+"
+    (let ((var-label (if local "(Variable) " "(Field) " ))
+           result)
+
+    (if tagset
+        (progn
+        (while tagset
+          (let* ((tag (car tagset))
+                 (member-name  (semantic-tag-name tag))
+                 (member-type  (semantic-tag-type tag))
+                 (member-clazz (semantic-tag-class tag))
+                 )
+
+            (if (eq 0 (string-match name-fragment member-name))
+                (let ((descrip
+                       (cond
+                        ((string= member-clazz "variable")
+                         (concat var-label member-type))
+
+                        ((string= member-clazz "function")
+                         (let* ((arglist (semantic-tag-get-attribute tag :arguments))
+                                (modifiers (semantic-tag-modifiers tag))
+                                (arg-descrip
+                                 (if (> (length arglist) 0)
+                                     (concat "("
+                                             (mapconcat
+                                              '(lambda (x) (concat (semantic-tag-type x)
+                                                                   " "
+                                                                   (semantic-tag-name x)))
+                                              arglist  ", ")
+                                             ")")
+                                   "()")))
+
+                           (concat "(Method) "
+                                   " " (mapconcat 'identity modifiers " ") " "
+                                   arg-descrip
+                                   "  returns "
+                                   member-type)))
+
+                        (t ""))))
+
+
+                  (cscomp-log 2 "cscomp-matching-tags: found %s (%s)"
+                           member-name member-type)
+
+                  (setq result (cons (list member-name descrip) result)))))
+
+            (setq tagset (cdr tagset)))
+        (cscomp-sort-completion-list result))
+      nil)))
+
+
+
+
+(defun cscomp-matching-instance-vars (name-fragment)
+  "Return the list of instance variables in a C# module, that
+match NAME-FRAGMENT.  See also, `cscomp-matching-local-vars'.
+
+"
+  (cscomp--find-matching-tags name-fragment (cscomp-instance-vars)))
+
+
+
+
+(defun cscomp-matching-instance-members (name-fragment)
+  "Return the list of instance memebrs in a C# module, that
+match NAME-FRAGMENT.
+
+See also, `cscomp-matching-local-vars',
+`cscomp-matching-instance-vars'.
+
+"
+  (cscomp--find-matching-tags name-fragment (cscomp-instance-members)))
+
+
+
+(defun cscomp-matching-local-vars (name-fragment)
+  "Use the semantic lex/analysis results to find local variables
+that match the given NAME-FRAGMENT.
+
+See also, `cscomp-matching-instance-members',
+`cscomp-matching-instance-vars'.
+
+"
+  (cscomp-start-stripped-semantic)
+  (cscomp--find-matching-tags name-fragment (semantic-get-all-local-variables) t))
+
+
+
+(defun cscomp-find-enclosing-csharp-class (&optional posn)
+  "returns a tag of type 'type (in other words, a c# class or struct) that
+encloses POSN, or point if POSN is nil.  If there is no enclosing 'type,
+then return nil.
+"
+;; This isn't quite correct. At this time, the C# namespace defn gets
+;; parsed as a type. I couldn't figure how to get namespace to get
+;; parsed as a new 'namespace tag.  Therefore, this fn can sometimes
+;; return a tag corresponding to a namespace, as opposed to a tag
+;; corresponding to a bonafide type.
+
+(let ((nar (semantic-current-tag-of-class 'type)))
+    nar))
+
+
+
+;; (defun cscomp-find-semantic-things (tag-class)
+;;   "Search for tags in semantic parse state."
+;;   (interactive "sTag type: ")
+;;   (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
+;;   (let* ((tokens  (semantic-fetch-tags))
+;;          (matches (cscomp-find-by-class tag-class tokens t)))
+;;     (if matches
+;;         (while matches
+;;           (let ((one (car matches)))
+;;             (setq matches (cdr matches))))
+;;       nil
+;;     )))
+
+
+
+(defun cscomp-find-by-class (cls streamorbuffer &optional search-parts search-includes)
+  "Find all tags with class CLS within STREAMORBUFFER.
+CLS is a string which is the name of the class of the tags returned, such as
+include, variable, type.
+See `semantic-tag-class'.
+Optional argument SEARCH-PARTS and SEARCH-INCLUDES are passed to
+`semantic-brute-find-tag-by-function'."
+  (semantic-brute-find-tag-by-function
+   (lambda (tag)
+     (let ((class (semantic-tag-class tag)))
+       (string= class cls)))
+   streamorbuffer search-parts search-includes))
+
+
+
+;;    (lambda (tag)
+;;      (let ((class (semantic-tag-class tag)))
+;;        (if (and (listp ts)
+;;                 (or (= (length ts) 1)
+;;                     (string= (semantic-tag-class ts) type)))
+;;
+;;            (setq ts (semantic-tag-name ts)))
+;;        (equal type ts)))
+;;    streamorbuffer search-parts search-includes))
+
+
+
+(defun cscomp-debugonly-list-all-local-variables ()
+  "fiddle with local variables and semantic."
+  (interactive)
+  (cscomp-start-stripped-semantic)
+  (semantic-lex (point-min) (point-max) 100)
+  (let ((locals (semantic-get-all-local-variables)))
+    (mapcar '(lambda (x)
+               (cscomp-log 3 "local var: name(%s) type(%s) pos(%s)"
+                        (car x) (cadr (nth 2 x))
+                        (nth 4 x)))
+            locals)))
+
+
+
+;; (defun cscomp-variables-in-scope ()
+;;   "Return the list of variables currently in scope.
+;; It uses the semantic parser table to find them."
+;;   (interactive)
+;;   (if (not (semantic-active-p)) (semantic-new-buffer-fcn))
+;;   (let* ((tokens (semantic-fetch-tags))
+;;          (vars (semantic-brute-find-tag-by-class 'variable tokens)))
+;;     (cscomp-log 3 "cscomp-variables-in-scope: found variables: '%s'" vars)
+;;     (mapcar 'car vars)))
+
+
+;; (defun cscomp-valid-csharp-declaration-at (point varname)
+;;   "Verify that a POINT starts a valid csharp declaration
+;; for the VARNAME variable."
+;;   (save-excursion
+;;     (goto-char point)
+;;     (if (looking-at
+;;          (concat "\\([A-Za-z0-9_.\177-\377]+\\)[ \t\n\r]+"
+;;                  (cscomp-double-backquotes varname)
+;;                  "[ \t\n\r]*[;=]"))
+;;         (match-string 1)
+;;       nil)))
+
+
+
+
+;; (defun cscomp-double-backslashes (varname)
+;;   "Build a new string identical to VARNAME, except that every backslash
+;; `\' is doubled, so that it can be used in a regex expression.
+;; "
+;;   (let (result (idx 0) (len (length varname)) curcar)
+;;     (while (< idx len)
+;;       (setq curcar (elt varname idx))
+;;       (setq result (concat result (if (eq curcar ?\\)
+;;                                       "\\\\"
+;;                                     (make-string 1 curcar))))
+;;       (setq idx (1+ idx)))
+;;     result))
+
+
+
+
+;; (defun cscomp-declared-type-of (name)
+;;   "Find in the current buffer the csharp type of the variable NAME.  The
+;; function returns a string containing the name of the class, or nil
+;; otherwise. This function does not give the fully-qualified csharp class
+;; name, it just returns the type as it is declared."
+;;   (save-excursion
+;;     (let (found res pos orgpt resname)
+;;       (while (and (not found)
+;;                   (search-backward name nil t))
+;;         (setq pos (point))
+;;         (backward-word 1)
+;;         (setq resname (cscomp-valid-csharp-declaration-at (point) name))
+;;         (goto-char pos)
+;;         (forward-char -1)
+;;         (if resname
+;;             (progn (setq res resname)
+;;                    (setq found t))))
+;;       res)))
+
+
+;; (defun cscomp-filter-fqn (importlist)
+;;   "Filter all the fully-qualified classnames in the import list. It uses
+;; the knowledge that those classnames are at the beginning of the list,
+;; so that it can stops at the first package import (with a star `*' at
+;; the end of the declaration)."
+;;   (if importlist
+;;       (if (string= "*" (car (cdr (car importlist))))
+;;           importlist
+;;         (cscomp-filter-fqn (cdr importlist)))))
+
+
+
+(defun cscomp-escape-string-for-powershell (arg)
+  "Powershell uses the backquote for an escape char.  This fn
+escapes the backquote for a string that will eventually be sent
+to powershell (CscompShell).
+
+I think this is only necessary when the arg is submitted to
+powershell within double-quotes. If the arg is within single
+quotes, backquotes do not need to be escaped.
+
+"
+  (let ((matcho (string-match "\\(.+\\)`\\(.+\\)" arg)))
+    (if matcho
+        (concat
+         (substring arg (match-beginning 1) (match-end 1))
+         "``"
+         (substring arg (match-beginning 2) (match-end 2)))
+      arg)))
+
+
+
+
+
+(defun cscomp-send-string-to-shell (command-string)
+  "sends a string to cscompshell function, returns the result."
+  (let ((result (csharp-shell-exec-and-eval-result command-string)))
+    (cscomp-log 2 "send-string-to-shell (%s) result(%s)" command-string (prin1-to-string  result))
+    ;;(if (and result (listp result)) result nil)
+    result
+    ))
+
+
+
+(defun cscomp-invoke-shell-fn (fn arg)
+  "invokes a 1-arg CscompShell function, returns the result."
+
+  ;; need to use single-quotes here around the arg, because in
+  ;; some cases the arg can have double-quotes in it.
+
+  (let* ((escaped-arg (cscomp-escape-string-for-powershell arg)))
+    (cscomp-send-string-to-shell (concat "[Ionic.Cscomp.Utilities]::" fn "(\'" escaped-arg "\')"))))
+
+
+
+
+(defun cscomp-type-exists (typename)
+  "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'."
+  (interactive "sType name: ")
+  (cscomp-invoke-shell-fn "QualifyType" typename))
+
+
+
+(defun cscomp-get-members-of-class (semantic-tag)
+  "Gets the members of the class denoted by the SEMANTIC-TAG.
+If SEMANTIC-TAG is nil, then this function gets the closest type
+containing point, and gets the members of that.
+
+"
+  (if (null semantic-tag) (setq semantic-tag (cscomp-get-current-class)))
+  (if (eq (cadr semantic-tag) 'type)
+      (semantic-tag-type-members semantic-tag)
+    nil))
+
+
+
+
+(defun cscomp-get-current-class (&optional posn)
+  "Return the semantic tag for the current class or type in scope at POSN.
+"
+  (interactive)
+  (save-excursion
+    (if posn (goto-char posn))
+    (semantic-fetch-tags)
+    (let ((containing-type (semantic-current-tag-of-class 'type)))
+      containing-type)))
+
+
+(defun cscomp-produce-csharp-arglist-block-from-dbrecord (arglist)
+  "Produces an argument list block, suitable for framing within parens
+in a method declaration, from ARGLIST, a list of local arguments obtained from
+`semantic-get-local-arguments'.
+
+When the format of ARGLIST is like this:
+
+   ((\"count\"
+      variable
+      (:type \"int\")
+      (:filename \"c:/dinoch/dev/dotnet/CsharpCompletion.cs\"
+                 reparse-symbol formal_parameters)
+      [621 630])
+    (\"melvin\"
+      variable
+      (:type \"string\")
+      (:filename \"c:/dinoch/dev/dotnet/CsharpCompletion.cs\"
+                 reparse-symbol formal_parameters)
+      [631 645]))
+
+The return value is like this:
+
+    int count, string melvin
+
+When the arglist is empty, the return value is a string of zero length.
+
+
+"
+  (let ((fragment ""))
+    (while arglist
+      (let* ((x (car arglist))
+             (var-name (car x))
+             (var-type (cadr (nth 2 x))))
+
+        (setq fragment (concat fragment var-type " " var-name)
+              arglist (cdr arglist))
+        (if arglist
+            (setq fragment (concat fragment ", ")))))
+    fragment))
+
+
+
+
+(defun cscomp-produce-instance-member-code-fragment (member-list)
+  "Produce a C# fragment that defines placeholder instance members,
+to be inserted into a class template which is then compiled, so that
+Cscomp can inspect the resulting IL to determine the type of a local var
+on which the user is asking for completion.
+
+Cscomp uses the compiler to determine the type of the var. It
+dynamically generates and compiles a class with the same variable
+declaration as the code being edited.
+
+The initialization of the var may depend on instance members.  If
+so, the compiled class must provide instance members of the
+correct type to satisfy those dependencies.  This function
+generates C# code to provide those instance members.
+
+For input that looks like this:
+
+  ((\"staticField1\" variable
+     (:typemodifiers (\"private\" \"static\") :type \"int\")
+     (reparse-symbol class_member_declaration)
+     #<overlay from 605 to 642 in CsharpCompletion.cs>)
+   (\"InstanceMethod1\" function
+     (:arguments (...) :type \"string\")
+     (reparse-symbol class_member_declaration)
+     #<overlay from 652 to 741 in CsharpCompletion.cs>)
+   (\"Run\" function
+     (:typemodifiers (\"public\") :arguments (...) :type \"void\")
+     (reparse-symbol class_member_declaration)
+     #<overlay from 752 to 1487 in CsharpCompletion.cs>)
+   (\"Main\" function
+     (:typemodifiers (\"public\" \"static\") :arguments (...) :type \"void\")
+     (reparse-symbol class_member_declaration)
+     #<overlay from 1497 to 1806 in CsharpCompletion.cs>)
+   )
+
+The output will look like this:
+
+    private static int staticField1 = default(int);
+    string InstanceMethid(...) { return default(string); }
+
+Any void methods will not be emitted because they cannot affect the
+types of local variables declared in methods.
+
+"
+  (let ((synthetic-code ""))
+
+    (while member-list
+      (let* ((x (car member-list))
+             (member-name (car x))
+             (member-flavor (cadr x))
+             (member-type (semantic-tag-get-attribute x :type))
+             (member-modifiers (semantic-tag-get-attribute x :typemodifiers))
+             one-frag
+             )
+        ;;          (message "n(%s) f(%s) t(%s)"
+        ;;                   member-name
+        ;;                   member-flavor
+        ;;                   member-type)
+
+        (setq one-frag
+              (cond
+
+               ((string= member-type "void") ;; the member is a void type
+                "")                          ;; emit nothing, don't need it.
+               ;; it's possible we might need it, in which case,
+               ;; we can just emit an empty fn.
+
+               ((eq member-flavor 'function) ;; it's a method
+                (concat
+                 (mapconcat 'identity member-modifiers " ")
+                 " "
+                 member-type
+                 " "
+                 member-name
+                 "("
+                 (cscomp-produce-csharp-arglist-block-from-dbrecord
+                  (semantic-tag-get-attribute x :arguments))
+                 ") {"
+                 (if member-type
+                     (concat
+                      " return default("
+                      member-type
+                      ");")
+                   "")
+                 "} "))
+
+
+               ((eq member-flavor 'variable) ;; it's an instance variable
+
+                (concat
+                 (mapconcat 'identity member-modifiers " ")
+                 " "
+                 member-type
+                 " "
+                 member-name
+                 " = default("
+                 member-type
+                 "); "))
+
+               (t
+                "")))
+
+        (setq synthetic-code (concat synthetic-code one-frag)))
+      (setq member-list (cdr member-list)))
+    synthetic-code))
+
+
+(defun cscomp-consolidate-whitespace (s)
+  "Collapse consecutive whitespace characters in the given string S
+to a single space.
+"
+  ;; trim leading spaces
+  (if (string-match "^\\([ \t\n\r\f\v]+\\)" s)
+      (setq s (substring s (match-end 1))))
+
+  ;; collapse multiple whitespace into one
+  (while (string-match "\\([ \t\n\r\f\v]\\{2,\\}\\)" s)
+    (setq s
+          (concat
+           (substring s 0 (match-beginning 1))
+           " "
+           (substring s (match-end 1)))))
+  s)
+
+
+(defun cscomp-escape-single-quotes (s)
+  "Escape single-quotes in the given string S.  This is for use within
+powershell.
+"
+  ;; escape single-quotes
+  (while (string-match "\\(.+\\)'\\(.+\\)" s)
+    (setq s
+          (concat
+           (substring s 0 (match-beginning 1))
+           "`'"
+           (substring s (match-end 1)))))
+  s)
+
+
+;;(setq cscomp-log-level 2)
+
+
+(defun cscomp-get-var-type-given-decl (var-declaration
+                                              var-index
+                                              classname
+                                              arglist
+                                              instance-members)
+  "Determines the type of the var declared in the given declaration.
+VAR-DECLARATION is  the C# code that declares all the local vars up to
+and including the local var of interest.
+
+VAR-INDEX is the zero-based index of the local arg in that list,
+that is of interest.  The initialization of that local var may
+depend on the prior local vars, which is why we need the entire
+var declaration list.
+
+CLASSNAME is the name of the class in which the local vars
+appear. This is used in the generated (synthetic) code, in case
+there is a reference to a class-static member.
+
+ARGLIST is a string with the arglist for the method that contains the
+local variable in question.  This will satisfy dependencies on
+local arguments in the initializer for the var, if any.
+
+INSTANCE-MEMBERS is a C# code fragment defining instance members for the
+synthetic class.  This will satisfy dependencies on instance members in
+the initializer for the var, if any.
+
+"
+  (let* ((massaged-decl
+          (cscomp-escape-single-quotes
+           (cscomp-consolidate-whitespace var-declaration)))
+         (namespaces (mapconcat 'identity (cscomp-referenced-assemblies-list) ","))
+         (command-string
+          (concat "[Ionic.Cscomp.Utilities]::GetTypeGivenVarDecl('"
+                  massaged-decl
+                  "','"
+                  namespaces
+                  "','" ;; for now, no additional assembly references
+                  "',"
+                  (number-to-string var-index)
+                  ",'"
+                  classname
+                  "','"
+                  arglist
+                  "','"
+                  (cscomp-consolidate-whitespace instance-members)
+                  "')" )))
+    (cscomp-send-string-to-shell command-string)))
+
+
+
+
+(defun cscomp-get-completions-for-namespace (ns)
+  "Gets a list of known completions (types and child namespaces)
+for the given namespace. You must have loaded an assembly containing
+types from the namespace, into the shell, for it to be known.
+See `cscomp-load-assembly'."
+  (interactive "sNamespace: ")
+  (cscomp-invoke-shell-fn "GetCompletionsForNamespace" ns))
+
+
+
+(defun cscomp-qualify-name (name)
+  "determines if the thing is a type, namespace, or ...?
+
+Result is
+
+    (list \"type\"  name)
+
+      or
+
+    (list \"namespace\"  name)
+
+      or
+
+    (list \"unknown\"  name)
+
+"
+
+  (interactive "sname to qualify: ")
+  (cscomp-invoke-shell-fn "QualifyName" name))
+
+
+(defun cscomp-get-matches (fragment)
+  "returns a list of all possible matches on a given partial name.
+The return value is like this:
+
+   (list (list \"type\"  \"fullNameOfType\")
+         (list \"namespace\"  \"FullNameOfNamespace\"))
+
+"
+  (interactive "sfragment to match on: ")
+
+  (let ((namespaces (mapconcat 'identity (cscomp-referenced-assemblies-list) ",")))
+
+    (cscomp-send-string-to-shell
+     (concat "[Ionic.Cscomp.Utilities]::GetMatches('"
+             fragment
+             "','"
+             namespaces
+             "')"))))
+
+
+
+(defun cscomp-load-additional-assemblies (lib-list)
+"Loads a set of assemblies into the csharp-shell, which then allows Cscomp
+to do completion (etc) on the types in those libraries."
+  (mapcar 'cscomp-load-assembly lib-list))
+
+
+(defun cscomp-load-assembly (lib)
+  "Loads a assembly into the csharp-shell, which then allows Cscomp
+to do completion (etc) on the types in that library."
+  (interactive "sLibrary: ")
+  (cscomp-invoke-shell-fn "LoadOneAssembly" lib))
+
+
+
+(defun cscomp-get-qualified-name (name)
+  "Guess the fully qualified name of the class NAME, using the
+list of referenced assemblies. It returns a string if the fqn
+was found, or null otherwise."
+  (interactive "sType name: ")
+  (cscomp-log 1 "get-qualified-name (%s)" name)
+  (let ((result (cscomp-type-exists name)))
+    (if result result
+      ;; else
+      (let ((usinglist (cscomp-referenced-assemblies-list))
+            fullname namespace )
+
+        ;; usinglist is like this:
+        ;; ("System"  "System.Collections"  "System.Collections.Generic"  "System.Reflection")
+
+        (setq result nil)
+        (while usinglist
+          (setq namespace (car usinglist))
+          (cscomp-load-assembly namespace)
+          (setq fullname (concat namespace "." name))
+          (cscomp-log 2 "checking this type: '%s'" fullname)
+          (if (cscomp-type-exists fullname)
+              (setq result fullname
+                    usinglist nil)
+            (setq usinglist (cdr usinglist))))
+
+        (cscomp-log 1 "get-qualified-name rtns: '%s'" result)
+
+        result))))
+
+
+
+;; (defun cscomp-flush-typeinfo-cache ()
+;;   "Flushes all entries in the completion cache"
+;;   (interactive)
+;;   (setq cscomp-typeinfo-cache nil))
+;;
+;;
+;; (defun cscomp-flush-classes-in-cache (class-list)
+;;   "Flushes all the classes in CLASS-LIST as entries of cache."
+;;   (let ((temp (nth 0 cscomp-typeinfo-cache))
+;;         (index -1)
+;;         (found nil)
+;;         (class (car class-list)))
+;;     (while class
+;;       (while (and temp (not found))
+;;         (setq index (1+ index))
+;;         (setq temp (nth index cscomp-typeinfo-cache))
+;;         (if (string= (car temp) class)
+;;             (setq found t)))
+;;       (if found
+;;           (setq cscomp-typeinfo-cache
+;;                 (nthcdr (1+ index) cscomp-typeinfo-cache)))
+;;       (setq class-list (cdr class-list))
+;;       (setq class (car class-list))
+;;       (setq found nil))))
+
+
+(defun cscomp-add-to-typeinfo-cache (name typeinfo)
+  (let (new-entry new-list)
+    (if (nth cscomp-typeinfo-cache-size cscomp-typeinfo-cache)
+        (progn
+          (setq new-entry (list name typeinfo))
+          (setq new-list (list new-entry nil))
+          (setcdr new-list (cdr cscomp-typeinfo-cache))
+          (setq cscomp-typeinfo-cache new-list)
+          (cscomp-log 1 "cache is full")   )
+      ;;else
+      (setq cscomp-typeinfo-cache
+            (append
+             cscomp-typeinfo-cache
+             (list (list name typeinfo)))))))
+
+
+(defun cscomp-get-typeinfo-from-cache (name)
+  (let ((temp (nth 0 cscomp-typeinfo-cache)) (index -1) (found nil))
+    (while (and temp (not found))
+      (setq index (1+ index))
+      (cscomp-log 2 "looking at cache item %d" index)
+      (setq temp (nth index cscomp-typeinfo-cache))
+      (if (string= (car temp) name)
+          (setq found t)))
+    (if found
+        (progn
+          (cscomp-log 3 "cscomp-get-typeinfo-from-cache: HIT name(%s) r(%s)"
+                    name (prin1-to-string (nth 1 temp)))
+          (nth 1 temp))
+      (cscomp-log 1 "cscomp-get-typeinfo-from-cache: MISS name(%s)" name)
+      nil)))
+
+
+(defun cscomp-get-typeinfo (name)
+  "Return the class info list for the class NAME. This function first
+checks to see if the class info is cached. If so, it returns the
+cached class info. Otherwise, it creates the type info list. Each
+element of the list returned by this function is itself a list whose
+car is a possible completion and whose cdr gives additional
+informations on the completion - the property type, or the param
+list and return type for a method, etc."
+  (interactive "sTypename: ")
+
+  (cscomp-log 2 "cscomp-get-typeinfo name(%s)...trying cache..." name)
+
+  (let ((type-info (cscomp-get-typeinfo-from-cache name))
+        (usinglist (cscomp-referenced-assemblies-list))
+        namespace
+        qualified-type )
+
+    ;; load all the assemblies mentioned in the using clauses
+    (while usinglist
+      (setq namespace (car usinglist))
+      (cscomp-load-assembly namespace)
+      (setq usinglist (cdr usinglist)))
+
+    (if (null type-info)
+        (progn
+          (setq qualified-type
+                (csharp-shell-exec-and-eval-result (concat
+                                    "[Ionic.Cscomp.Utilities]::QualifyType('"
+                                    ;;(cscomp-escape-string-for-powershell name)
+                                    ;; dont need to escape if using single quotes
+                                     name
+                                    "')")))
+
+          (cscomp-log 1 "cscomp-get-typeinfo...(%s)..." (prin1-to-string qualified-type))
+
+          (if qualified-type
+              (setq type-info
+                    (csharp-shell-exec-and-eval-result (concat "[Ionic.Cscomp.Utilities]::GetTypeInfo('"
+                                                (car qualified-type) ; type name
+                                               "', '"
+                                               (cadr qualified-type) ; assembly name
+                                               "')" ))))
+          (if type-info
+              (cscomp-add-to-typeinfo-cache name type-info))))
+
+    type-info))
+
+
+(defun cscomp-get-type-ctors (type-name)
+  "Retrieve constructors from CscompShell for the type named by TYPE-NAME.
+"
+  (interactive "sType name: ")
+  (cscomp-invoke-shell-fn "GetConstructors" type-name))
+
+
+
+
+(defun cscomp-split-by-dots (s)
+  "When the string contains a dot, this fn returns a 2-element
+list (TOKEN1 TOKEN2).  TOKEN1 is the substring of s that precedes
+the last dot.  TOKEN2 is the substring that follows the last dot.
+
+When the string does not contain a dot, this fn returns a
+2-element list in which the first element is nil and the 2nd
+element is the entire string.
+
+"
+  (cscomp-log 2 "cscomp-split-by-dots: s[%s]" s)
+  (if (string-match "\\(.*\\)\\.\\(.*\\)" s)
+      (let ((result (list (match-string 1 s) (match-string 2 s))))
+        (cscomp-log 2 "cscomp-split-by-dots: %s" (prin1-to-string result))
+        result)
+    (list nil s))) ;; it's a single atom
+
+
+
+
+(defun cscomp-parse-csharp-expression-before-point ()
+  "Parses the text at point, and returns the results.
+
+The retval is a list (POSN (TOKEN1 TOKEN2)) , where POSN is the position
+in the buffer of the beginning of TOKEN1 and TOKEN1 and TOKEN2
+are the two tokens surrounding the prior dot.
+
+For example, suppose System.Diagnostics.D were the name at
+point. This function would return the list
+
+    (888 (\"System.Diagnostics\" \"D\"))
+
+...if 888 was the position of the beginning of the word System.
+
+It's just an exercise in syntactically-aware string parsing.
+
+If the text preceding point doesn't look like two tokens, this fn
+returns nil.
+
+"
+  (cscomp-log 2 "parse-csharp-expression-before-point: point(%d)" (point))
+
+  (interactive)
+  (save-excursion
+    (let ((opoint (point))
+          (cycle-count 0)
+          (dot-count 0)
+          m1
+          (regex "[-\\+\\*\\/%,;( {})=\\.]")
+          snip done
+          (paren-depth 0)
+          ;;           (skip-back '(lambda ()
+          ;;                         (skip-chars-backward "\t ")
+          ;;                         (backward-char)))
+          )
+
+
+      (while (not done)
+
+        (skip-chars-backward "\t ")
+
+        (cond
+
+         ((and (eq cycle-count 0) ;; first time through
+               (eq (char-before) 40)) ;; 40 = open paren - means we want fn completion
+          (backward-char))             ;; backup
+
+         ((eq (char-before) 34) ;; 34 = doublequote
+          (backward-char 1)     ;; move back into the quoted string
+          (let ((limits (c-literal-limits)))
+            (if (consp limits)
+                (c-safe (goto-char (car limits)))))) ;; goto beginning of literal string
+
+         ;;          ((eq (char-before) 41)       ;; 41 = close paren - means we want fn completion
+         ;;           (incf paren-depth)
+         ;;           (backward-char))
+         ;;
+         ;;          ((and
+         ;;            (eq (char-before) 40)      ;; 40 = open paren
+         ;;            (> paren-depth 0))         ;; we have a pending close paren (moving backwards)
+         ;;           (decf paren-depth)
+         ;;           ;;(funcall skip-back))
+         ;;           (backward-char))
+
+         ;;          ((or
+         ;;            (eq (char-before) 32)       ;; space
+         ;;            (eq (char-before) ?\t))     ;; tab
+         ;;          (funcall skip-back))
+
+         ((re-search-backward regex nil t)
+          (cond
+
+           ((eq (char-after) 41) ;; 41 = close paren - means we want fn completion
+            (incf paren-depth)
+            t)
+
+           ((and
+             (eq (char-after) 40) ;; 40 = open paren
+             (> paren-depth 0)) ;; we have a pending close paren (moving backwards)
+            (decf paren-depth)
+            ;;(funcall skip-back))
+            t)
+
+
+           ((or
+             (eq (char-after) 32)   ;; space
+             (eq (char-after) ?\t)) ;; tab
+            t)                      ;; do nothing
+
+           ((eq (char-after) ?.)
+            (setq m1 (point)
+                  regex "[-\\+\\*\\/%,;( {})=]"))
+
+           (t
+            (setq done t))))
+
+         (t
+          (backward-char)))
+
+        (incf cycle-count)) ;; count of steps backward
+
+      (setq snip
+            (cscomp-consolidate-whitespace
+             (buffer-substring-no-properties (1+ (point)) opoint)))
+
+      (cscomp-log 2 "parse-expression-before-point: B snip(%s)" snip)
+      (list (1+ (point)) (cscomp-split-by-dots snip)))
+    ))
+
+
+
+
+(defun cscomp-qualify-local-var (symbol opoint)
+  "Use the semantic lex/analysis results to classify the
+name as a local variable. Returns a list, 1st elt is the
+variable type, and the second elt is a vector, containing
+the position of its definition.
+
+See also `cscomp-qualify-instance-var'.
+"
+  (cscomp-start-stripped-semantic)
+  ;;(semantic-lex (point-min) (point-max) 100)
+  (let ((locals (semantic-get-local-variables))
+        (args (semantic-get-local-arguments))
+        (result nil)
+        (decl-count 0)
+        (prior-var-decls ""))
+
+    (while (and locals (not result))
+      (let* ((x (car locals))
+             (var-name (car x))
+             (var-type (cadr (nth 2 x)))
+             (var-pos (nth 4 x)))  ;; pair: start and end of var decl
+
+        ;; The simple string= test will give a false positive if there's
+        ;; a foreach loop variable in a prior
+        ;; foreach loop with the same name as the one the user
+        ;; wants completion on.
+        ;;
+        ;; This is only an issue with two or more foreach loops, each of
+        ;; which create a separate naming scope, and which have the same
+        ;; variable name.  All those foreach variables will be reported
+        ;; as "local variables" by semantic. But, not all of them are in
+        ;; scope for the completion we're performing right now.
+        ;;
+        ;; This needs to do something more intelligent with
+        ;; the declaration. If I had a way to interrogate the scope of
+        ;; the variable decl, that would help. But right now I don't have
+        ;; that.
+
+        ;; I think I need a better understanding of the semantic.el
+        ;; package.
+        ;; =======================================================
+
+
+        ;; if this decl ends *before* the point at which the user is
+        ;; asking for completion.
+        (if (<  (elt var-pos 1) opoint)
+
+            ;; If this var decl is the same name as the one
+            ;; we want.
+            (if (string= var-name symbol)
+                (progn
+
+                  ;; Handle var types - need to determine the actual type.
+                  ;;
+                  ;; To do that, compile the var declaration, then inspect the IL
+                  ;; to determine the var types.
+                  ;;
+                  ;; This engine will determine the var type, in some portion% of
+                  ;; the cases.
+                  ;;
+                  ;; It will handle:
+                  ;;
+                  ;;  - simple var declarations that have no dependencies on other vars
+                  ;;  - cascaded var decls that depend on other local vars.
+                  ;;
+                  ;; For now, it will not handle:
+                  ;;
+                  ;;  - var that depends on a method argument
+                  ;;  - var whose initialization depends on an instance var
+                  ;;  - var decls in foreach loops
+                  ;;
+
+                  ;; if the type of the variable is "var"
+                  (if (string= var-type "var")
+                      (let* ((this-decl
+                              (buffer-substring-no-properties (elt var-pos 0) (elt var-pos 1)))
+
+                             (containing-type (cscomp-get-current-class))
+                             (member-list (cscomp-get-members-of-class containing-type))
+                             (name-of-containing-type  (car containing-type))
+
+                             (inferred-type
+                              (cscomp-get-var-type-given-decl
+                               (concat prior-var-decls " " this-decl)
+                               decl-count
+                               name-of-containing-type
+                               (cscomp-produce-csharp-arglist-block-from-dbrecord args)
+                               (cscomp-produce-instance-member-code-fragment member-list)
+                               )))
+
+                        (if (and inferred-type (string= (car inferred-type) "type"))
+                            (setq var-type (cadr inferred-type))
+                          (message "%s" (prin1-to-string inferred-type))
+                          )))
+
+                  (cscomp-log 2 "cscomp-qualify-local-var: found %s (%s)"
+                            symbol var-type)
+                  (setq result (list var-type var-pos)))
+
+              ;; else - remember it. We may need it later
+              (let* ((this-var-decl
+                      (buffer-substring-no-properties (elt var-pos 0) (elt var-pos 1)))
+                     (tokens (split-string this-var-decl "[ \t]" t)))
+
+                ;; include decl in prior decls if not "foreach(var foo in X)"
+                (if (or (< (length tokens) 4)
+                        (not (string= (nth 3 tokens) "in")))
+                    (setq prior-var-decls (concat prior-var-decls " " this-var-decl)
+                          decl-count (1+ decl-count))
+
+                  ;; else - it's a foreach loop
+
+                  ;; If performing completion on a var within the loop that
+                  ;; depends on the loop variable, then we need to infer
+                  ;; the type of the foreach loop variable here.
+                  ;;
+                  ;; But, I'm punting.
+
+                  )))))
+      (setq locals (cdr locals)))
+
+    result))
+
+
+
+
+
+(defun cscomp-qualify-instance-var (symbol)
+  "Use the semantic lex/analysis results to classify the
+name as an instance variable. Returns a list, 1st elt is the
+variable type, and the second elt is a vector, containing
+the position of its definition.
+
+See also `cscomp-qualify-local-var'.
+
+"
+  (cscomp-start-stripped-semantic)
+  ;;(semantic-lex (point-min) (point-max) 100)
+  (let ((ivars (cscomp-instance-vars))
+        (result nil))
+    (while (and ivars (not result))
+      (let* ((x (car ivars))
+             (var-name (car x))
+             (var-type (cadr (nth 2 x)))
+             (var-pos (nth 4 x)))
+        (if (string= var-name symbol)
+            (progn
+              (cscomp-log 2 "cscomp-qualify-instance-var: found %s (%s)"
+                       symbol var-type)