Just like Visual Studio, ReSharper implements its own form of code completion (a.k.a. IntelliSense) that is used to provide various helpers when typing code. Unlike Visual Studio, however, ReSharper implements three different varieties of code completion that plugin developers need to be aware of. These are:
- Symbol completion, which is the closest analogy to IntelliSense in terms of operation. This is essentially the mechanism that completes the names of symbol identifiers as they are being typed into the editor. Symbol completion is typically invoked with the Ctrl+Space shortcut.
- Smart completion is a code completion mechanism which attempts to narrow down the list of suggested items given the particular context. For example, when calling a method that takes a
string, pressing Ctrl+Alt+Space while entering the parameter to the method will present the list of all
string-typed identifiers available at the current scope.
- Import symbol completion is a means of completion that is used to complete identifier names even if such identifiers have not been imported with a
usingstatement. Import symbol completion is invoked with Shift+Alt+Space and lets the user quickly add both the identifier name and a
Let’s begin our overview of these mechanisms by looking at the root interface of code completion,
ICodeCompletionItemsProvider is an interface for any type that wants to provide code completion information to ReSharper. We won’t discuss its methods, since you’ll most likely be inheriting from a derived abstract class, but what’s important to note here is that all of its methods take as a parameter an
ISpecificCodeCompletionContext that is used to make decisions on what completion items are available.
Rather than implementing
ICodeCompletionItemsProvide directly, it makes more sense to inherit from the
ItemsProviderOfSpecificContext<TContext> class. This class is the one that gets inherited by various ReSharper mechanisms. The two most common interface methods that providers override are:
IsAvailable()--- this method determines whether the lookup items (i.e., items inserted into the completion list) are in fact added.
AddLookupItems()is the method that actually adds the items.
Let’s look at these in more detail. First, it’s important to note that the
TContext generic parameter that you specify will be the first parameter in both of the above methods. This generic parameter typically relates to the language you’re supporting, so that for example, if you want to support code completion in C#, you would inherit from
Once you know what context you have, you can begin to use it in the aforementioned methods. For example, when checking if the completion items are available, you can perform a check similar to the following:
The above check ensures that the items are only available if the type of completion is Smart.
The second method,
AddLookupItems(), takes two parameters: the smart completion context and a
GroupedItemsCollector. The second parameter is of particular importance since it is through this parameter that completion items are provided.
To allow adding of items,
GroupedItemsCollector provides a set of methods such as
AddAtDefaultPlace(). All of these methods take an
ILookupItem as a parameter. This interface is by itself fairly complicated, but luckily a number of lookup item factories are available in order to facilitate the process in common scenarios. For example, the
CSharpCodeCompletionContext class has a property called
LookupItemsFactory which yields an instance of a
CSharpLookupItemFactory. You can use this factory to create different lookup items. Putting it all together, here is an example of how you can add a lookup item to a collector:
CreateTextLookupItem() method used above simply creates and initializes a
TextLookupItem containing specific text.
If we go off looking down the hierarchy of the
ItemsProviderOfSpecificContext, we’ll eventually find language-specific classes such as
CSharpItemsProviderBase. This class, which also takes a context generic parameter, is the kind of class that one would actually use to build extensions to code completion.
Here’s a very simple example: let’s suppose that we want to add the string hello as a code completion item to any C# file regardless of the position of the caret. In other words, the option hello will be available practically everywhere. To implement this, we first make a class that inherits from
Then, we override the
IsAvailable() method to only allow our code completion item to appear in automatic completion (and not in smart or type symbol completion):
Finally, we override the
AddLookupItems() method and add the simplest possible statement to include the string hello in the code completion popup list:
And that’s it --- you have a code completion provider that adds an extra element when working in C# context.