How to create green (or blue) squiggle adornments

2020-06-16 04:21发布

问题:

I have a Visual Studio extension that show red error squiggles. I also like to provide squiggles with other colors, for example yellow for warnings.

Creating red squiggles can be done by extending the ITagger class, along the lines:

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"));
        }
    }
}

What I have tried:

  1. My intuition (incorrectly) says that returning an ErrorTag with an different errorType may yield a different type of tag, but whatever string you pass it, the squiggles remain red. Eg. new ErrorTag("Warning") gives red squiggles. The MSDN documentation is almost nonexistent. See ErrorTag.
  2. In the Tagging namespace there is no mention of a different Tag class implementing ITag. I hoped a WarningTag or InfoTag existed.
  3. Asked a question on MSDN forum here.

Question: how to create green (or blue or yellow) squiggle adornments? Sadly, even arcane or convoluted solutions are appreciated...

I'm targeting VS2015 and VS2017.

Edit: While typing this question someone at the MSDN forum replied that it cannot be done with the current API. Is it really impossible to make yellow squiggles in Visual Studio?!

回答1:

The PredefinedErrorTypeNames contains the supported values for the ErrorType property of the ErrorTag.

You got close with "Warning", but the value of PredefinedErrorTypeNames.Warning appears to be "compiler warning".



回答2:

Just to document my own question and answer.

Create a file SquigglesTaggerProvider.cs with the following content:

[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);
    }
}

Create a file named SquigglesTagger.cs with the following content:

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"));
        }
    }
}

The PredefinedErrorTypeNames has different errors predefined.

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";

The code is taken from my repository here.