C# Code Completion in emacs - a look at Cedet, semantic, and CSDE
In my prior post I wrote that I have a dream of getting c# code completion in emacs. Jason Rumney wrote to me:
I think everything you want is here: http://cedet.sourceforge.net/semantic.shtml Semantic is what JDEE uses to provide code completion, and the page above claims grammars are already available for C# .
Well, I checked it out. Did a little reconnoitering. Here's what I found.
Cedet is an interesting batch of tools, some of which are interesting to me, and some of which are not. Like, I don't want a Connected Graph Editor. "Cogre". I don't even want to know what such a thing is. But it's in Cedet. Also, Cedet has something called eieio. It's a very cute name, and I'm sure a very clever reference to something. But I don't get the joke, and don't care to. Senator (After some stumbling around I discovered that "Senator" is a part of cedet that does the navigation, informed by the code analysis. (like, jump forward one class, one method, whatever)) Bovine, another oblique reference to yacc and bison I guess. Whatthehell is "bovinate"? Do I want to do that or not? Will I be arrested if I try it?
Look, all I want is code completion. I am vaguely aware that various impressive magic has to happen in order to get code completion. There is some parsing magic, some context-analysis magic, and so on. I don't want to write a compiler and a parser though, although I am happy to use someone else's. I also don't want to admire the beauty of someone else's compiler, parser, or analyzer. Nor do I want to learn 8 new brand names for different magic technology (eieio, semantic, bovine, cogre, cedet, ede, speedbar, senator, etc etc etc) and how they all integrate and work together. I just want code completion. I'm sure your compiler is beautiful. I'm sure your parser is pure elegance. Your branding is very clever. It's all very nice. I just want code completion.
Ok, let me stop whining and start over. CEDET seems to have a whole bunch of infrastructure for doing analysis of source code in emacs, and then doing things with the analysis. Like, navigation. Code highlighting. And, in theory, code completion. There is a csharp parser contribution to semantic, and this means that csharp source code is correctly parsed when you load it into an emacs buffer. Installing it is pretty simple, you have to download cedet, then fiddle your emacs to add the cedet directories to your load-path, then load up semantic, and so on. Ok, it's not just a matter of running an msi file. It's a little more complicated than that. But you can handle it, you run emacs.
Once you get it installed, semantic gives you highlights on namespaces, classes, methods, and so on. It looks like this:
So this is hard evidence that semantic has successfully parsed the Csharp code. Keep in mind that there is another engine parsing the csharp code – it is called csharp-mode, and it has provided the pretty colors on the text (what emacs calls "font-lock"). But cedet seems to be a much deeper analysis of the code based on a formal parser. So, it's "better". Ok, we have blue lines calling my attention to the classes and methods. What else? In particular, DO WE GET CODE COMPLETION?
Hmm, well, see… (Reminds me of an episode of "The Office" where Michael asks about a potential dating partner. He asks, "Would this woman fit in a standard-sized rowboat, without causing the boat to capsize?" And there's no answer. And Michael says, "your delay in answering causes some concern…" Same thing here). Ah, so where were we? Code completion. Well, see, the code completion done by semantic depends on a tags database, I think, which does not exist for the .NET Framework class library. Semantic automagically generates suggested completions for classes in your source code. It looks like this:
As you can see, Semantic has put some stuff in the minibuffer to tell us how much it knows about the current context. It knows my incomplete line of code is referencing the Secant type, and it is looking for static members on that type. That alone is pretty impressive. But not so impressive is the crappy popup. Half of the text is cut off and unreadable. If I then type an 'S' and then just a few seconds, Semantic suggests the SolveViaSecant() method, and if I TAB through, Semantic will autocomplete that method. Yeehaw! The delay is not up to Visual Studio snappiness standards, but it did work.
(NB: the rose-colored highlighted lines come from flymake.el, which I wrote about previously).
As I said Semantic can do this with the classes defined in code in the buffer. And maybe even with classes defined in other source code in the same directory, although I could not get that to work. Also, sometimes the suggested completions were wrong. AND More importantly!! Semantic does not know about any of the 5000+ classes that are defined in the .NET Framework base class library. (that reminds me, I should count the classes in .NET 3.5 sometime soon).
In other words, if I declare a variable of type, let's say, System.Data.SqlClient and then try to get code completion, semantic knows I want to get a member on an instance of type SqlClient, but semantic doesn't know what SqlClient looks like. It lacks the knowledge of SqlClient and it lacks the ability to go find out.
In theory I could build a "system database" of tags that could be used by semantic to inform the code completion. BUT, I could not find any tools that would enable me to build such a database, nor could I find examples of such a database. I couldn't figure out how to teach Semantic about libraries other than those defined in active source code.
I imagine that Cedet and its semantic sub-technology works really well with C and C++. Not so much with C#, not yet anyway. And, I found it impenetrable.
CSDE is an abandonware clone of the JDEE. The JDEE is a bunch of add-ons to emacs that make developing in Java much easier. One of the things you get is… code completion! Zowie! Since C# is so similar to Java, the guy who started with CSDE figured the JDEE would be a great leg up. Basically he copied all the elisp and just did a global search-and-replace, swapping out "java" and inserting "csharp".
The statement by Jason was that JDEE uses Semantic to power its code completion, but this is not exactly what I found. I didn't do a teardown of JDEE, but the snapshot of JDEE that CSDE is based upon, uses the beanshell in order to get class information. Here's the thing, code completion magic all works mostly the same. Some analysis has to happen to figure out what you're doing in the code. Then there's got to be an information database about the type or identifier you are fiddling with – this is the source of context-sensitive suggestions. JDEE gets the class information by doing reflection on a named class, in the beanshell. The beanshell is a name foe a JVM that runs as an inferior process inside emacs, and just waits for commands to run. Emacs sends it a "tell me about class java.lang.Integer" command, and the beanshell returns what it knows about that class- all its members and so on.
The CSDE still has all the beanshell crapola in it, all the –classpath nonsense and jar files and so on. The same idea for getting class information could work in .NET, but certainly not with a JVM. We're gonna need more than that.
So CSDE looks like a non-starter.
Finally there is CSense. As I commented elsewhere, it looks like the Csense project was thrown together in a couple afternoons by a passionate developer, then abandoned just as quickly. Csense actually has tools that go and build a database of information about classes from the various assemblies. This is really cool. But I could not get csense to apply that information to a code-completion request.
The Bottom Line
So the end result is that I cannot find code completion in emacs for C#. We have some tantalizing building blocks, but no real joy. The best results I have got so far is using dabbrev, which works on a text analysis of the buffer. Cedet looks good, but I cannot figure out how to build the database for system or third party assemblies. Csense builds a database for system assemblies, but I cannot figure out how to get it to use that data. CSDE seems to be a nice idea that was never really developed.
The right answer I think would require combining some magic from these various projects and developing them further. Combining the csense database-generation magic with the code-completion stuff in either CSDE or Semantic would do the trick. Or possibly just developing the CSDE a little further to have its own inferior process. Figuring out which of those paths to take? I will leave that for another day.
[ Update: I have continued to explore this, and actually produced a CsdeShell. For more on this, see my other posts on C# and emacs with this link. ]