I would like to create a Syntax Highlighter in Visual Studio 2012 (and above) that supports different themes (Dark, Light, Blue).
Visual Studio's Editor Classifier project template explains how to create your own colors in the environment using Microsoft.VisualStudio.Text.Classification.ClassificationFormatDefinition
. It works fine...
... until you realize that there are different themes in Visual Studio 2012 (and above) and you don't really support them. Your pretty dark blue colored identifiers on the light theme becomes unreadable in a dark themed environment.
To my understanding if you change your ClassificationFormatDefinition in the Tools/Options/Fonts & Colors in a given theme (e.g.: Light) it won't affect the same ClassificationFormatDefinition in a different theme (e.g.: Dark). The colors seem to be independent across different themes.
That is good. But how do I achieve defining the same ClassificationFormatDefinition (e.g.: MyKeywords) that has the same name in all the themes, but provides different colors for them? Just like Visual Studio's own "Identifier", which is default black on the Light theme and default while on the Black theme.
I know about the Microsoft.VisualStudio.PlatformUI.VSColorTheme.ThemeChanged
event that allows me to get notified when the color themes are changed. Do I have to use this and somehow get hold of my existing ClassificationFormatDefinition and assign new colors to them based on the new theme? But that also pops a question: will these modified colors be persisted to the environment, i.e. if I restart Visual Studio, will my changes be there the next time in all the different themes.
I haven't found any attribute that would state which theme the ClassificationFormatDefinition supports nor found much helpful article on the subject.
Any help appreciated.
This might help you, code from F# Power Tools, seems to be listening to the ThemeChanged event and updating the classifiers - https://github.com/fsprojects/VisualFSharpPowerTools/blob/a7d7aa9dd3d2a90f21c6947867ac7d7163b9f99a/src/FSharpVSPowerTools/SyntaxConstructClassifierProvider.cs
Ok, here's a workaround I've found. It is far from perfect, but it is as good as it gets.
The trick is to use another base definition when you define your own classification type. This will use their default color for the different themes. The important thing is that you must not define your own color in
MyKeywordsFormatDefinition
because that disables the default behavior when switching between themes. So try to find a base definition that matches your color. Look for predefined Classificatoin Types here: Microsoft.VisualStudio.Language.StandardClassification.PredefinedClassificationTypeNamesI hope it will be useful for some of you. Even maybe help to refine a proper solution when you can actually set your own color without reusing existing color definitions.
I had a similar problem. I've developed a syntax highlighter for the DSL at work. It has two sets of colors - for light and dark themes. I needed a way to switch between these two sets of colors at runtime when VS theme changes.
After some search I found a solution in the F# github in the code responsible for the integration with VS: https://github.com/majocha/visualfsharp/blob/bcd1929828a3c424b464fe2275590f11446b288e/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs
The code in F# repo is quite similar to the code from Omer Raviv’s answer. I translated it into C# and get something like this:
I’ve used the class above as the base class for all my ClassificationFormatDefinition classes.
There's another, cleaner way using the
VsixColorCompiler
that ships with the VS SDK.First, create a
ClassificationTypeDefinition
andClassificationFormatDefinition
as usual. This will define the default colour in all themes:Next, create a colours.xml file. This will allow us to override the colour for specific themes:
Now edit your .csproj to include a post-build command to compile the XML to a .pkgdef next to your normal package's .pkgdef (VS2015 SDK shown here):
Whenever you make a change, be sure to clear the MEF cache between builds to force it to update. Additionally, the following registry keys may need to be deleted as well: