7

在寻找了很长时间#region在 Visual Studio 中更改指令文本颜色的简单方法后,我得出结论,没有简单的方法可以做到这一点。

我知道如何更改#region语句颜色,以及如何更改折叠区域的颜色,但我想更改带有区域描述的文本颜色。所以:

#region Some text   <--- all this text should be in a different color

public void Test()
{
}

#endregion          <--- this too

似乎很多人都在寻找这样的东西 - 请参阅如何在 VS2008 中更改扩展区域标题的颜色?.

所以我一直在考虑编写一个简单的 Visual Studio 插件来更改颜色。但是,它比我想象的要复杂,有Snapshot, Tagger, Classifier,WpfTextViewCreationListener等类AdornmentLayer

简而言之,我不知道从哪里开始!我在 MSDN 网站上遵循了几个教程,但对于我正在尝试做的事情来说,它们似乎太复杂了。

有人可以指出最简单的方法吗?IE。我应该使用 VS SDK 中的哪些类/方法/事件。我也不介意颜色是否不能通过 UI 等自定义。我正在使用VS2010。

编辑:刚刚向我推荐了mztools网站;我也去那里看看。还注意到 StackOverflow 的regions 语法高亮几乎正是我想要的!

4

2 回答 2

13

我最终想出了一个解决方案,至少对于 VS2010 是这样。虽然我已经用它来为 ' #region' 和 ' #endregion' 标签着色,但类似的解决方案应该适用于 Visual Studio 窗口中的任何文本内容。

似乎可以通过创建一个IViewTaggerProvider将源代码的“分类”部分“标记”来解决此类问题。Visual Studio 将为标记有该分类的文本提供样式,然后用户可以通过Tools > Options... > Environment > Fonts and Colors将其更改为所需的样式。


标记器提供程序如下所示:

[Export(typeof(IViewTaggerProvider))]
[ContentType("any")]
[TagType(typeof(ClassificationTag))]
public sealed class RegionTaggerProvider : IViewTaggerProvider
{
    [Import]
    public IClassificationTypeRegistryService Registry;

    [Import]
    internal ITextSearchService TextSearchService { get; set; }

    public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
    {
        if (buffer != textView.TextBuffer)
            return null;

        var classType = Registry.GetClassificationType("region-foreground");
        return new RegionTagger(textView, TextSearchService, classType) as ITagger<T>;
    }
}

这将创建一个ITagger对象,在给定 Visual Studio 文本视图的情况下,该对象将使用给定的分类类型标记部分文本。请注意,这适用于所有文本视图(即源代码编辑器、“查找结果”窗口等)。可以通过编辑ContentType属性来改变它(只是C#?)。


分类类型(在本例中为“区域前景”)定义为:

public static class TypeExports
{
    [Export(typeof(ClassificationTypeDefinition))]
    [Name("region-foreground")]
    public static ClassificationTypeDefinition OrdinaryClassificationType;
}

[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "region-foreground")]
[Name("region-foreground")]
[UserVisible(true)]
[Order(After = Priority.High)]
public sealed class RegionForeground : ClassificationFormatDefinition
{
    public RegionForeground()
    {
        DisplayName = "Region Foreground";
        ForegroundColor = Colors.Gray;
    }
}

与也可能适用于文本范围的其他分类相比,该Order属性确定何时应用分类。将DisplayName在“工具”>“选项...”对话框中使用。


一旦定义了分类,一个ITagger类就可以搜索视图的文本并为其找到的文本的适用部分提供分类。

简而言之,它的工作是监听文本视图的ViewLayoutChanged事件,当提供的文本视图的内容发生变化时(例如,因为用户输入了某些内容)会触发该事件。

然后它必须在文本中搜索它感兴趣的文本区域(称为“跨度”)。#region在这里,它返回包含或的行的跨度#endregion。我一直保持这个简单,但是TextSearchService用于查找匹配项的也可以使用正则表达式进行搜索。

最后,为 Visual Studio 提供了一种方法来检索它找到的文本的标签,称为GetTags(). 对于给定的跨度集合,这将返回带有分类标签的文本跨度,即应该以某种方式分类的跨度区域。

它的代码是:

public sealed class RegionTagger : ITagger<ClassificationTag>
{
    private readonly ITextView m_View;
    private readonly ITextSearchService m_SearchService;
    private readonly IClassificationType m_Type;
    private NormalizedSnapshotSpanCollection m_CurrentSpans;

    public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };

    public RegionTagger(ITextView view, ITextSearchService searchService, IClassificationType type)
    {
        m_View = view;
        m_SearchService = searchService;
        m_Type = type;

        m_CurrentSpans = GetWordSpans(m_View.TextSnapshot);

        m_View.GotAggregateFocus += SetupSelectionChangedListener;
    }

    private void SetupSelectionChangedListener(object sender, EventArgs e)
    {
        if (m_View != null)
        {
            m_View.LayoutChanged += ViewLayoutChanged;
            m_View.GotAggregateFocus -= SetupSelectionChangedListener;
        }
    }

    private void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
    {
        if (e.OldSnapshot != e.NewSnapshot)
        {
            m_CurrentSpans = GetWordSpans(e.NewSnapshot);
            TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(e.NewSnapshot, 0, e.NewSnapshot.Length)));
        }
    }

    private NormalizedSnapshotSpanCollection GetWordSpans(ITextSnapshot snapshot)
    {
        var wordSpans = new List<SnapshotSpan>();
        wordSpans.AddRange(FindAll(@"#region", snapshot).Select(regionLine => regionLine.Start.GetContainingLine().Extent));
        wordSpans.AddRange(FindAll(@"#endregion", snapshot).Select(regionLine => regionLine.Start.GetContainingLine().Extent));
        return new NormalizedSnapshotSpanCollection(wordSpans);
    }

    private IEnumerable<SnapshotSpan> FindAll(String searchPattern, ITextSnapshot textSnapshot)
    {
        if (textSnapshot == null)
            return null;

        return m_SearchService.FindAll(
            new FindData(searchPattern, textSnapshot) {
                    FindOptions = FindOptions.WholeWord | FindOptions.MatchCase
                });
    }

    public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
    {
        if (spans == null || spans.Count == 0 || m_CurrentSpans.Count == 0)
            yield break;

        ITextSnapshot snapshot = m_CurrentSpans[0].Snapshot;
        spans = new NormalizedSnapshotSpanCollection(spans.Select(s => s.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive)));

        foreach (var span in NormalizedSnapshotSpanCollection.Intersection(m_CurrentSpans, spans))
        {
            yield return new TagSpan<ClassificationTag>(span, new ClassificationTag(m_Type));
        }
    }
}

为简洁起见,我省略了命名空间和 using 语句,它们通常采用Microsoft.VisualStudio.Text.*. 要使这些可用,必须首先下载Visual Studio 2010 SDK 。


在过去的几个月里,我一直在使用这个解决方案,没有任何问题。

我注意到的一个限制是颜色不是“混合”的,因此不透明度小于 100% 的颜色不会“淡出”跨度中的现有颜色——这可能有助于保留语法突出显示。

我也不太了解它的效率,因为它看起来会在每次按键时重复搜索文档。我还没有进行研究以查看 Visual Studio 是否以某种方式对其进行了优化。我确实注意到大文件(> ~1000 行)上的 Visual Studio 速度变慢,但我也使用 Resharper,所以我不能单独将此归因于这个插件。

由于这主要是使用猜测进行编码,因此我欢迎任何可以澄清或简化事情或改进代码性能的评论或代码更改。

于 2012-05-29T12:47:41.887 回答
0

I guess you could start with Visual Studio Add-in project, it will used EnvDTE, which was considered as Visual Studio Object Model, and please find MSDN document here: http://msdn.microsoft.com/en-us/vstudio/bb968855 You could control your visual studio behavior, like debugger, code editor and so on by EnvDTE.

于 2012-03-14T08:17:28.360 回答