如何使用Visual Studio扩展创建绿色(或蓝色)波浪装饰。

9

我有一个Visual Studio扩展,可以显示红色错误波浪线。我还想提供其他颜色的波浪线,例如黄色用于警告。

可以通过扩展ITagger类来创建红色波浪线,方法如下:

internal sealed class MySquigglesTagger : ITagger<IErrorTag> {
    public IEnumerable<ITagSpan<IErrorTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
        foreach (IMappingTagSpan<MyTokenTag> myTokenTag in this._aggregator.GetTags(spans))        
            SnapshotSpan tagSpan = myTokenTag.Span.GetSpans(this._sourceBuffer)[0];
            yield return new TagSpan<IErrorTag>(tagSpan, new ErrorTag("Error", "some info about the error"));
        }
    }
}

我尝试过:

  1. 直觉告诉我(错误的)返回一个具有不同errorType的ErrorTag可能会产生不同类型的标记,但无论你传递什么字符串,波浪线仍然是红色的。例如:new ErrorTag("Warning")会产生红色波浪线。MSDN文档几乎没有内容。请参阅ErrorTag
  2. 标记命名空间中没有提到另一个实现ITag接口的不同Tag类。我希望存在WarningTag或InfoTag。
  3. 在MSDN论坛这里提出了一个问题。

问题:如何创建绿色(或蓝色或黄色)波浪线装饰?即使是奇怪或复杂的解决方案也会受到赞赏……

我正在针对VS2015和VS2017。

编辑:在输入这个问题时,MSDN论坛上的某个人回复说,目前的API无法实现。难道在Visual Studio中真的不可能做出黄色波浪线吗?!


Tagging 命名空间还有其他实现了 ITag 接口的标记,其中包括 TextMarkerTag。你读过 https://msdn.microsoft.com/en-us/library/dd885121.aspx 吗? - C.Evenhuis
@C.Evenhuis 是的,我已经阅读并实现了它来匹配大括号和关键字高亮,但我不知道如何使用TextMarkerTag来进行波浪线标记。我想我需要实现IErrorTag。 - HJLebbink
我必须承认,如果没有您的反馈,我无法回答这个问题 :) - C.Evenhuis
你好,能否在这里发布你的代码?我正在尝试做类似的东西,但是运气不太好。 - Ionut Enache
@IonutEnache 我已经添加了一些代码的答案。 - HJLebbink
显示剩余2条评论
3个回答

5

PredefinedErrorTypeNames 包含了 ErrorTagErrorType 属性所支持的值。

"Warning" 已经很接近了,但是 PredefinedErrorTypeNames.Warning 的值似乎是 "编译器警告"。


2
如果微软在你需要的位置添加了一个链接并将其记录下来,我就不会浪费几天时间了。我会向微软的某个人寻求解决方案。 - HJLebbink

1

为了记录我的问题和答案。

创建一个名为SquigglesTaggerProvider.cs的文件,并添加以下内容:

[Export(typeof(IViewTaggerProvider))]
[ContentType("Your Content Type")]
[TagType(typeof(ErrorTag))]
internal sealed class SquigglesTaggerProvider : IViewTaggerProvider {
    [Import]
    private IBufferTagAggregatorFactoryService _aggregatorFactory = null;

    public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag {
        ITagger<T> sc() {
            return new SquigglesTagger(buffer, this._aggregatorFactory) as ITagger<T>;
        }
        return buffer.Properties.GetOrCreateSingletonProperty(sc);
    }
}

创建一个名为SquigglesTagger.cs的文件,并包含以下内容:
internal sealed class SquigglesTagger : ITagger<IErrorTag> {
    private readonly ITextBuffer _sourceBuffer;
    private readonly ITagAggregator<AsmTokenTag> _aggregator;

    internal SquigglesTagger(ITextBuffer buffer, IBufferTagAggregatorFactoryService aggregatorFactory) {
        this._sourceBuffer = buffer;            
        ITagAggregator<AsmTokenTag> sc() {   
            return aggregatorFactory.CreateTagAggregator<AsmTokenTag>(buffer);
        }
        this._aggregator = buffer.Properties.GetOrCreateSingletonProperty(sc);
    }

    public IEnumerable<ITagSpan<IErrorTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
        foreach (IMappingTagSpan<MyTokenTag> myTokenTag in this._aggregator.GetTags(spans))        
            SnapshotSpan tagSpan = myTokenTag.Span.GetSpans(this._sourceBuffer)[0];
            yield return new TagSpan<IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, "some info about the error"));
        }
    }
}
< p > PredefinedErrorTypeNames 包含不同的预定义错误。

public const string SyntaxError = "syntax error";
public const string CompilerError = "compiler error";
public const string OtherError = "other error";
public const string Warning = "compiler warning";
public const string Suggestion = "suggestion";

这段代码取自我的代码库这里

我尝试了上面的版本,但对我没有用。当我在我的代码上进行调试时,变量看起来没问题,选择了正确的文件和行,但最终在Visual Studio编辑器中没有出现任何红色波浪线。我必须手动刷新VS编辑器吗?如果是这样,我该怎么做? - Ionut Enache
@IonutEnache 你是否将内容类型链接到文件扩展名?CreateTagger是否被调用过?可能有很多东西没有正确设置。 - HJLebbink

1
准确来说,这个波浪装饰有一个刷子,它要么是红色的实心刷子,要么是由导出的EditorFormatDefinition决定的刷子,其NameAttribute名称与IErrorTag.ErrorType的名称匹配,并且对应的导出的ErrorTypeDefinition也具有与IErrorTag.ErrorType匹配的NameAttribute。
是EditorFormatDefinition.CreateResourceDictionaryFromDefinition中的ResourceDictionary确定了刷子。如果您没有重写此方法,则导出的EditorFormatDefinition可以设置ForegroundColor为SolidColorBrush,或者将ForegroundBrush设置为任何刷子实现。
这些导出可以在ITagger实现上进行。例如
class ErrorEditorFormatDefinition : EditorFormatDefinition
{

    public ErrorEditorFormatDefinition(Color errorColor, string displayName = null) : this(displayName)
    {
        this.ForegroundColor = errorColor;

    }
    public ErrorEditorFormatDefinition(Brush brush, string displayName = null) : this(displayName)
    {
        this.ForegroundBrush = brush;
    }
    private ErrorEditorFormatDefinition(string displayName)
    {
        if (displayName != null)
        {
            this.DisplayName = displayName;
        }
        this.BackgroundCustomizable = false;
    }
}

internal class ErrorTagger : ITagger<IErrorTag>
{
    public const string MethodNotCoveredErrorType = "MethodNotCovered";
    public const string MethodPartiallyCoveredErrorType = "MethodPartiallyCovered";
    public const string LineNotCoveredErrorType = "LineNotCovered";
    public const string LinePartiallyCoveredErrorType = "LinePartiallyCovered";

    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;

    [Export(typeof(ErrorTypeDefinition))]
    [Name(MethodNotCoveredErrorType)]
    public ErrorTypeDefinition MethodNotCoveredErrorTypeDefinition { get; }

    [Export(typeof(ErrorTypeDefinition))]
    [Name(MethodPartiallyCoveredErrorType)]
    public ErrorTypeDefinition MethodPartiallyErrorTypeDefinition { get; }
    
    [Export(typeof(ErrorTypeDefinition))]
    [Name(LineNotCoveredErrorType)]
    public ErrorTypeDefinition LineNotCoveredErrorTypeDefinition { get; }
    
    [Export(typeof(ErrorTypeDefinition))]
    [Name(LinePartiallyCoveredErrorType)]
    public ErrorTypeDefinition LinePartiallyErrorTypeDefinition { get; }


    [Export(typeof(EditorFormatDefinition))]
    [Name(MethodNotCoveredErrorType)]
    [UserVisible(true)]
    public EditorFormatDefinition MethodNotCoveredErrorFormatDefinition { get; } = new ErrorEditorFormatDefinition(new SolidColorBrush(Colors.Pink));

    [Export(typeof(EditorFormatDefinition))]
    [Name(MethodPartiallyCoveredErrorType)]
    public EditorFormatDefinition MethodPartiallyCoveredErrorFormatDefinition { get; } = new ErrorEditorFormatDefinition(new LinearGradientBrush()
    {
        StartPoint = new System.Windows.Point(0, 0),
        EndPoint = new System.Windows.Point(1, 0),
        GradientStops = new GradientStopCollection
        {
            new GradientStop(Colors.Yellow, 0.0),
            new GradientStop(Colors.Red, 0.25),
            new GradientStop(Colors.Blue, 0.75),
            new GradientStop(Colors.LimeGreen, 1.0)
        }
    },"Call me what you want");
    
    [Name(LineNotCoveredErrorType)]
    [Export(typeof(EditorFormatDefinition))]
    public EditorFormatDefinition LineNotCoveredErrorFormatDefinition { get; } = new ErrorEditorFormatDefinition(Colors.Brown);
    [Name(LinePartiallyCoveredErrorType)]
    public EditorFormatDefinition LinePartiallyCoveredErrorFormatDefinition { get; } = new ErrorEditorFormatDefinition(Colors.Cyan);

    public IEnumerable<ITagSpan<IErrorTag>> GetTags(NormalizedSnapshotSpanCollection spans)
    {
        return new List<ITagSpan<IErrorTag>>
        {
            // determine as appropriate
            new TagSpan<IErrorTag>(new SnapshotSpan(spans[0].Snapshot, new Span(0, spans[0].Snapshot.Length)), new ErrorTag(MethodPartiallyCoveredErrorType, "Method partially covered")),
        };
    }
}

LinearGradientBrush squiggles

预定义的错误类型名称只是那些保证具有相匹配的错误类型定义/编辑器格式定义的名称。
public static class PredefinedErrorTypeNames { 
  /// <summary>Represents syntax errors.</summary> 
  public const string SyntaxError = "syntax error"; 
  /// <summary>Represents compiler errors.</summary> 
  public const string CompilerError = "compiler error"; 
  /// <summary>Represents other errors.</summary> 
  public const string OtherError = "other error"; 
  /// <summary>Represents compiler warnings.</summary> 
  public const string Warning = "compiler warning"; 
  /// <summary>Represents a suggestion with no visual treatment.</summary> 
  public const string Suggestion = "suggestion";
  ///<summary>Represents a suggestion with subtle visual treatment.</summary> 
  public const string HintedSuggestion = "hinted suggestion"; 
}

请注意,在“字体和颜色”中看不到“建议”选项 - 还要检查下面的“显示名称”更改,以了解如何在“字体和颜色”中找到它们。
[Export(typeof(EditorFormatDefinition))]
[Name("suggestion")]
[UserVisible(false)]
internal class SuggestionClassificationFormatDefinition : EditorFormatDefinition
{
    public SuggestionClassificationFormatDefinition()
    {
        this.ForegroundBrush = (Brush)Brushes.Transparent;
        this.BackgroundCustomizable = new bool?(false);
        this.DisplayName = "Suggestion";
    }
}

[Export(typeof(EditorFormatDefinition))]
[Name("compiler warning")]
[UserVisible(true)]
internal class WarningClassificationFormatDefinition : EditorFormatDefinition
{
    public WarningClassificationFormatDefinition()
    {
        this.ForegroundBrush = (Brush)new SolidColorBrush(Color.FromRgb((byte)0, (byte)128, (byte)0));
        this.BackgroundCustomizable = new bool?(false);
        this.DisplayName = "Warning";
    }
}

[Export(typeof(EditorFormatDefinition))]
[Name("compiler error")]
[UserVisible(true)]
internal class CompilerErrorClassificationFormatDefinition : EditorFormatDefinition
{
    public CompilerErrorClassificationFormatDefinition()
    {
        this.ForegroundBrush = (Brush)Brushes.Blue;
        this.BackgroundCustomizable = new bool?(false);
        this.DisplayName = "Compiler Error";
    }
}

[Export(typeof(EditorFormatDefinition))]
[Name("other error")]
[UserVisible(true)]
internal class OtherErrorClassificationFormatDefinition : EditorFormatDefinition
{
    public OtherErrorClassificationFormatDefinition()
    {
        this.ForegroundBrush = (Brush)new SolidColorBrush(Color.FromRgb((byte)149, (byte)23, (byte)149));
        this.BackgroundCustomizable = new bool?(false);
        this.DisplayName = "Other Error";
    }
}

[Export(typeof(EditorFormatDefinition))]
[Name("syntax error")]
[UserVisible(true)]
internal class SyntaxErrorFormatDefinition : EditorFormatDefinition
{
    public SyntaxErrorFormatDefinition()
    {
        this.ForegroundBrush = (Brush)Brushes.Red;
        this.BackgroundCustomizable = new bool?(false);
        this.DisplayName = "Syntax Error";
    }
}

[Export(typeof(EditorFormatDefinition))]
[Name("hinted suggestion")]
[UserVisible(true)]
internal class HintedSuggestionClassificationFormatDefinition : EditorFormatDefinition
{
    public HintedSuggestionClassificationFormatDefinition()
    {
        this.ForegroundBrush = (Brush)new SolidColorBrush(Color.FromRgb((byte)165, (byte)165, (byte)165));
        this.BackgroundCustomizable = new bool?(false);
        this.DisplayName = "Suggestion ellipses (...)";
    }
}

在Vs 2022中有一个未包含在此列表中的错误类型“Edit and Continue”,默认情况下提供了一个紫色的刷子,在“Fonts And Colors”中是“Rude Edit”。
如果您想要在Visual Studio中编辑波浪线的颜色,那么请在EditorFormatDefinition上设置[UserVisible(true)],如果您这样做,请将this.BackgroundCustomizable = false;设置为false,就像我在ErrorEditorFormatDefinition类中所做的那样,因为背景不会被使用。如果您提供的不是SolidColorBrush,请不要将其设置为用户可见。
最后,对于ErrorType = PredefinedErrorTypeNames.HintedSuggestion,有一个不同的装饰,其他都是波浪线。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接