Better intellisense information

A couple of days ago I brought up the code definition window.  I mentioned what purpose it was trying to serve, how some of the developers were thinking about changing it and how I thought it could be improved. In response to that, a poster mentioned that Eclipse had a behavior that they really liked, specifically that when you held down ctrl and hovered over an identifier it would show a fragment of code showing the definition.

I can see an immediate benefit of that system over our current one in that it allows you to get similar information to the Code Definition View (CDV) without having to move your cursor from where you were working.  Thus you can easily hover over a ton of variables in the block of code where you're working and refresh your understanding of them.  I decided to spike that kind of feature to see if it could be done.  In order to do this I just tried to leverage our existing architecture as much as possible in order to make the amount of coding effort extremely small and so that I could get some quick results to run by you and the rest of the team as to how good a feature this was.

In order to do that I started with the fact that we already support the concept of giving you information about an identifier when you hover over it through the form of a tooltip.  Normally this is pretty basic information.  For a field/method we'll show the name of the type it's defined in and it's signature.  For a local variable we'll show it's type and name.  For a type we'll show if it's a class/interface/enum/delegate.  And for all of the above we'll also show the doc comment along with it.

I couldn't think of really relevant information to show when hovering over the name of a class (although maybe seeing the base and interface list would be useful).  I also couldn't' think of anything useful for a property/method declaration since we already show their entire signature (although it might be useful to know if a property has a getter/setter or not).  So that left me with fields, enums, and local variables.  For all of those it seemed useful to show not only the type and name of the field when you hovered over it, but also and code that might have initialized it.

I.e. normally when you hover over an enum value you see something pretty basic.  Given the following enum:

        enum Colors





            Yellow = Red | Green



When you select (or hover over) the use of Yellow you would see


but now you see


This initializer expression can be arbitrarily complex, and it works just fine even with multiple variable declarations.  All in all, i think it could be pretty useful like in the following case:

Before: hovering!

After: hovering!

There are of course many ways we could improve on this.  For one, i think it would be far more useful to show you the definition in context.  So rather than just see the declaration and initialization, you see a few statements above and below that one.  There's a good chance that that auxiliary information will help you understand that member better.  That could be a bit confusing, so it would probably be necessary to bold out the actual definition line in the tooltip so you could identify it in the ~5+'ish lines we'd be showing you (this is also something I'd like to spike).  IMO, the ideal thing to do would be to pop up a tooltip which contained a perfectly rendered snippet of your code with the appropriate definition highlighted somehow (maybe by slightly adjusting the background color behind it).

The current implementation has some issues with it that would need to be addressed.  Firstly, it rather blasé about how much memory it uses.  For every item that you have it stores this additional initialization information so that it can be displayed as necessary.  As you can imagine, the amount of these items one might have in their solution could be enormous and we need to be conscious of how much memory we use and not go overboard. If the amount of memory this consumed was a problem (on say 250 project solutions) then I'd probably move to a delayed computation mode where the initialization expression was determined when it was needed for the tooltip. But, this implementation was by far the simplest that could work and so I did it that way 🙂   If we were to move to a model where we displayed the context around the definition I'm fairly certain this would have to change as every definition we learned about would suddenly be storing a large amount of duplicated data along with it.

Also, the new display has the potential to be quite confusing in debugger related scenarios.  Imagine the following code:

Now, when you're debugging you hover and you see that text and you go "what?!  How is the value 0??  Waitaminute, the watch window shows it as 5. wtfomgnojuo!!!"  Other systems, like the class designer and the object browser might then call into this code to get things to display to heir user and this information might not be relevant, and might be completely nonsensical to them.  Each of these issues is pretty easily solvable, but the worry is that there might be more out there that we could be unaware of.

The issue of consistency also comes into play.   If we added this, it's not clear that VB/C++/J# would as well.  They might not consider it a useful feature "too much clutter", or they might not be able to do it efficiently and don't want it affecting their user experience.

Anyways, I'd love to hear your thoughts on this.  If you like just the spiked version and would consider that a significant benefit; if you like it but really think it needs more; if you like it but think we're going down a completely wrong path and we should be doing something else; or if you just plain don't like it.

Comments (9)
  1. Brian says:

    I might be off my rocker but….

    I thought that VB.NET had a lot of cool Intellisense features at the cost of a background compiler. And the background compiler is what hindered the language from being used in HUGE projects.

    Is there background compiling going on here?

  2. Brian: Great question. I wanted to address a few of your points:

    A) VB does have a background compiler which does allow them to determine a lot of things as you type that we are (currently) unable to.

    B) VB has worked a lot on scalability so that they can deal with large projects

    C) This work I did does depend on any compiler features. It literally goes and grabs the initialization text where the item is defined and just jams it in 🙂

    In C# we have a separate compiler that we invoke when you hit "build" an we have something called "The C# Language Service" (LS) which you can think of as a trimmed down compiler. Where the compiler is built to be absolutely correct to the C# spec at any cost, the LS is defined to be as good as possible given the constraint of needing to be fast enough that we never interfere with typing. It’s my complete belief that the two goals are not orthogonal. However, currently that’s how it’s architected and in the future we’ll have to see about doing things different so that you can get the benefit’s that are possible with a full background compiler.

    It’s important to realize that the LS is a mini-compiler in a sense. So any of the features that VB has could be done in C# if we’re willing to extend this compiler to understand those ideas. Implementing them is usually no problem, the question is can we do it in a performant manner, can we test it adequately, and is the benefit high enough for the user versus the other features we can work on. I posted earlier about adding support for method and operator overload resolution. This is an area where VB already has functionality. Adding it would be possible, however it could drastically affect performance (now intellisense would be evaluating types of arguments to functions when binding them, which means abitrary expression evaluation). So if w want to do it we’d need to know that it was really worth the high cost it would have for us in terms of implementation time, time to get performance up, and time to test.

    Does that help clear things up?

  3. Addy Santo says:

    This genre of questions have one universal answer: MAKE IT CONFIGURABLE. Now the question becomes what should the default behavior be, and I would say: disabled while the application is running (ie debug mode), otherwise enabled.

  4. arhra says:

    I’ve no idea how hard it would be, but for local variables, how about making it show the last assignment to it, rather than the initilialization? (of course, ideally, the last assignment would _always_ be the initialisation… </functional zealot>

  5. Addy: I’m not sure if I agree. Making it configurable is not necessarily the right choice in all circumstances. If there is a "right" think to do, then pick that over a choice. It’s also not right if you’re forcing hte user to change the choice over and over depending on what they’re doing.

  6. Ahrha: Why would that be idea? 🙂

  7. What about making this behaviour configurable via macros or something like the keyboard mapping dialog? It’s better not to have too many options in the options dialog, but it would be nice to expose these commands to the user somewhere. For instance, I might want to call the "Show defintion" function with ctrl-d so I don’t have to take my hands from the keyboard. Similarly, in debug mode, I could display variable values when hovering but variable definitions when ctrl-hovering.

  8. David: These behaviors are always available through the keyboard. Specifically this would fall under the command:


    which you can bind to any keystroke.

Comments are closed.

Skip to main content