创建Visual Studio主题特定语法高亮显示

我想在Visual Studio 2012 (及以上版本) 中创建支持不同主题 (黑暗,浅色,蓝色) 的语法突出显示器

Visual Studio的编辑器分类器项目模板解释了如何使用Microsoft.VisualStudio.Text.Classification.ClassificationFormatDefinition在环境中创建自己的颜色。 它工作正常...

...直到你意识到在Visual Studio 2012(及以上版本)中有不同的主题,而你并不真正支持它们。 在黑暗的主题环境中,你在灯光主题上的漂亮深蓝色标识变得无法读取。

对于我的理解,如果您在给定主题(例如:Light)的Tools / Options / Fonts&Colors中更改ClassificationFormatDefinition,它将不会影响同一Classification.FormatDefinition在不同主题(例如:Dark)中。 颜色似乎是不同主题的独立。

那很好。 但是,我如何实现定义在所有主题中具有相同名称的ClassificationFormatDefinition(例如:MyKeywords),但为它们提供了不同的颜色? 就像Visual Studio自己的“标识符”一样,这个标识符在Light主题上是默认的黑色,在黑色主题上是默认的。

我知道Microsoft.VisualStudio.PlatformUI.VSColorTheme.ThemeChanged事件,它允许我在更改颜色主题时得到通知。 我是否必须使用它并以某种方式获取我现有的ClassificationFormatDefinition并根据新主题为其分配新颜色? 但是,这也带来了一个问题:这些修改后的颜色是否会被保留到环境中,即,如果我重新启动Visual Studio,那么下次在所有不同的主题中,我的更改都会在那里。

我还没有找到任何属性可以说明ClassificationFormatDefinition支持哪个主题,也没有发现关于该主题的很多有用的文章。

任何帮助赞赏。


这可能会帮助您,来自F#Power Tools的代码似乎正在监听ThemeChanged事件并更新分类器 - https://github.com/fsprojects/VisualFSharpPowerTools/blob/a7d7aa9dd3d2a90f21c6947867ac7d7163b9f99a/src/FSharpVSPowerTools/SyntaxConstructClassifierProvider.cs


好的,这是我找到的解决方法。 它远非完美,但它是如此之好。

诀窍是在定义自己的分类类型时使用另一个基本定义。 这将使用他们的默认颜色为不同的主题。 重要的是,您不能在MyKeywordsFormatDefinition定义自己的颜色,因为这会在主题之间切换时禁用默认行为。 因此,请尝试找到与您的颜色相匹配的基本定义。 在此处查找预定义的Classificatoin类型:Microsoft.VisualStudio.Language.StandardClassification.PredefinedClassificationTypeNames

internal static class Classifications
{
    // ...
    public const string MyKeyword = "MyKeyword";
    // ...
}

[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = Classifications.MyKeyword)]
[Name("MyKeywords")]
[DisplayName("My Keywords")]
[UserVisible(true)]
internal sealed class MyKeywordsFormatDefinition: ClassificationFormatDefinition
{
    // Don't set the color here, as it will disable the default color supporting themes
}

[Export(typeof(ClassificationTypeDefinition))]
[Name(Classifications.MyKeyword)]
[BaseDefinition(PredefinedClassificationTypeNames.Keyword)]
internal static ClassificationTypeDefinition MyKeywordsTypeDefinition;

我希望它对你们中的一些人有用。 甚至可能有助于在不重用现有颜色定义的情况下实际设置自己的颜色时改进适当的解决方案。


我有类似的问题。 我在工作中为DSL开发了语法高亮显示器。 它有两套颜色 - 浅色和黑色主题。 当VS主题发生变化时,我需要在运行时在这两组颜色之间切换。

经过一番搜索之后,我在负责与VS集成的代码中找到了F#github中的解决方案:https://github.com/majocha/visualfsharp/blob/bcd1929828a3c424b464fe2275590f11446b288e/vsintegration/src/FSharp.Editor/Classification/ClassificationDefinitions.fs

F#repo中的代码与Omer Raviv的答案中的代码非常相似。 我将它翻译成C#并获得如下所示的内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Media;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

using DefGuidList = Microsoft.VisualStudio.Editor.DefGuidList;
using VSConstants =  Microsoft.VisualStudio.VSConstants;

//...

internal abstract class EditorFormatBase : ClassificationFormatDefinition, IDisposable
{
    private const string textCategory = "text";
    private readonly string classificationTypeName; 

    protected EditorFormatBase()
    {          
        VSColorTheme.ThemeChanged += VSColorTheme_ThemeChanged;

        //Get string ID which has to be attached with NameAttribute for ClassificationFormatDefinition-derived classes
        Type type = this.GetType();
        classificationTypeName = type.GetCustomAttribute<NameAttribute>()?.Name;      

        if (classificationTypeName != null)
        {
                ForegroundColor = VSColors.GetThemedColor(classificationTypeName);   //Call to my class VSColors which returns correct color for the theme
        }              
    }

    private void VSColorTheme_ThemeChanged(ThemeChangedEventArgs e)
    {


     //Here MyPackage.Instance is a singleton of my extension's Package derived class, it contains references to
     // IClassificationFormatMapService and  
     // IClassificationTypeRegistryService objects
        if (MyPackage.Instance?.ClassificationFormatMapService == null || MyPackage.Instance.ClassificationRegistry == null || classificationTypeName == null)
        {
            return;
        }

        var fontAndColorStorage = 
            ServiceProvider.GlobalProvider.GetService(typeof(SVsFontAndColorStorage)) as IVsFontAndColorStorage;
        var fontAndColorCacheManager = 
            ServiceProvider.GlobalProvider.GetService(typeof(SVsFontAndColorCacheManager)) as IVsFontAndColorCacheManager;

        if (fontAndColorStorage == null || fontAndColorCacheManager == null)
            return;

        Guid guidTextEditorFontCategory = DefGuidList.guidTextEditorFontCategory;
        fontAndColorCacheManager.CheckCache(ref guidTextEditorFontCategory, out int _ );

        if (fontAndColorStorage.OpenCategory(ref guidTextEditorFontCategory, (uint) __FCSTORAGEFLAGS.FCSF_READONLY) != VSConstants.S_OK)
        {
            //Possibly log warning/error, in F# source it’s ignored           
        }

        Color? foregroundColorForTheme =  VSColors.GetThemedColor(classificationTypeName);  //VSColors is my class which stores colors, GetThemedColor returns color for the theme

        if (foregroundColorForTheme == null)
            return;

        IClassificationFormatMap formatMap = MyPackage.Instance.ClassificationFormatMapService
                              .GetClassificationFormatMap(category: textCategory);

        if (formatMap == null)
            return;

        try
        {
            formatMap.BeginBatchUpdate();
            ForegroundColor = foregroundColorForTheme;
            var myClasType = MyPackage.Instance.ClassificationRegistry
                                                                  .GetClassificationType(classificationTypeName);

            if (myClasType == null)
                return;

            ColorableItemInfo[] colorInfo = new ColorableItemInfo[1];

            if (fontAndColorStorage.GetItem(classificationTypeName, colorInfo) != VSConstants.S_OK)    //comment from F# repo: "we don't touch the changes made by the user"
            {
                var properties = formatMap.GetTextProperties(myClasType);
                var newProperties = properties.SetForeground(ForegroundColor.Value);

                formatMap.SetTextProperties(myClasType, newProperties);
            }                                                                           
        }
        catch (Exception)
        {
            //Log error here, in F# repo there are no catch blocks, only finally block       
        }
        finally
        {
            formatMap.EndBatchUpdate();
        }          
    }

    void IDisposable.Dispose()
    {
        VSColorTheme.ThemeChanged -= VSColorTheme_ThemeChanged;
    }
}

我已经使用上面的类作为我的所有ClassificationFormatDefinition类的基类。

链接地址: http://www.djcxy.com/p/21283.html

上一篇: Create Visual Studio Theme Specific Syntax Highlighting

下一篇: What happened to the "real" Cassandra C++ library libcql?