Couple of years ago, I’ve created a Visual Studio extension to colorize things in C#. More specifically I was trying to colorize different programming constructs such as extension methods. So it had to be done in a syntax aware manner as oppose to coloring text. For that I used Roslyn .NET compiler to do this. Roslyn API made it very easy to recognize these programming constructs and apply text formatting to them.
In this post I’m going to explain what I did along with explanation for the things that was more difficult. Also I’m going to include a working repository of the code with a link to visual studio gallery of this extension.
The Inner Working of Color Coder : ITaggerProvider
One of the most important part of this Color Coder extension is
ColorCoderTaggerProvider which inherits from
ITaggerProvider. This class is responsible for providing taggers. Taggers are going to be used to color different aspect of our code based on the values present inside our
ColorCoderTagger here act as our concrete instance that actually returns the
ClassificationFormatDefinition is where we tell Roslyn Compiler that a
ClassificationType should have certain textual characteristic.
For example in the code excerpt below I defined a new classification type called Attribute. I assigned the name of this classification type and one of its textual feature. Which in this case is whether or not it is bold. Now we can use this classification type to color attributes. Also the name we assigned here to DisplayName is going to show up in visual studio font and colors section.
Also you can see an attribute above the class called Order. Order is set to Priority.High. That’s because if we don’t do that, the color we select is going to be overwritten by a color we’ve selected for class. Here we’re trying to color an attribute, but attributes are also classes. So we tell the compiler to apply the color for attribute after the color selected for class.
Also worth noting that visual studio by default has its own set of
ClassificationFormatDefinition. We have a lot of classification types which we’re going to color in this extension, but since the classification already exist by default in Visual Studio, it’s not added here.
Recognizing and Highlighting Specific Symbol Using Roslyn
Now that we defined our classifications, we need a way to decipher which symbol belong to what category. For example we defined an Attribute classification type, now we need to write code to return a specific
TagSpan<IClassificationTag> if the current symbol was an Attribute.
In the code about we checkout to see if the current
SyntaxNode is an Attribute. If so we return a new
ClassificationTag value set to the name we chose for that symbol. After returning the
TagSpan, since we specify a
ClassificationFormatDefinition with the same name with specific characteristic, it’s going to be pick up. That is to say the Roslyn Compiler is going to apply our classification definition to the symbol. What I just described was the most important aspect of what I did with this extension. Everything else is helping this process.
Save Settings Into Windows Registry
Another important part of this extension is being able to save and load our settings into windows registry.
In the code above, we use
Microsoft.VisualStudio.Shell.Interop to set the item in the category which we created. Before doing that we need to have a unique identifier for the category that we want to set things in. We use this set method in our
ChangeColorOptionGrid class in the setters on our properties. That will set the individual colors when there a change in our dialog page.
There are two other methods, the save method saves all our colors in Register. The load method is used when we try to open our Dialog page to load the colors that we’ve selected previously. The underlying mechanism of behind all these methods are almost the same. Perhaps the load method is different because we use
GetItem to get the colors from registry.
Challenges of Creating a Visual Studio Extensions
One of the most challenging aspect of creating a Visual Studio extension is lack of documentation. This is mainly because Visual Studio extensions are not something that one build in day to day development. Perhaps if a company specializes in providing tools for Visual Studio, but that’s not what most companies are all about. Also the community that knows the subject are very small and most questions on Stack overflow goes unanswered. So in this situation best things to do is reading other peoples code in my opinion.
There is a GitHub repo where a lot of sample repositories that does different things. If we reading those repositories that do something that is close to what we want, we might have a starting point. For example we have Visual Studio Extensibility Samples and also here is visual studio extensibility documentation and also Roslyn SDK docs.
We can also follow people like Mads Kristensen, he has a lot of GitHub repositories which are interesting to look into. Also he sometime create educational content on YouTube for Microsoft. For example in this video he shows how he develops Add Any File extension. If you know of a better place to look for information which I missed please let me know in the comment section.
When A Feature From a Third Party Extension Get Integrated Into Visual Studio
Sometimes a feature from a Visual Studio extension get integrated directly into Visual Studio. Depending on you one look at it, it can both be a good and or a bad thing. But I think it’s a good thing not only because it’s satisfying to see a feature in your extension got integrated into Visual Studio, but also because one does not have to install an extra extension to use that feature. This happened in Color Coder case, with Visual Studio 16.5 onward, there are member types that allows us to control their formatting right in visual studio without using an extension.
In this post I explained a few things about how I created the Color Coder visual studio extension. We also saw what are some of the challenges I faced while I created this extension. Color Coder is open source and the code is available here.