Ich bin ein bisschen an die Partei zu spät, aber hey, warum nicht meinen 2 Cent in werfen
Wie Sie in Ihrer Frage erklärt haben, Ihr Projekt hat zwei Hauptteile:.
- die Klassen zu finden, die
IDisposable
- Hervorhebungen sie
die erste ist bei weitem die schwerste, wenn auch nicht unmöglich umzusetzen. Ein wortlistenbasierter Ansatz ist wahrscheinlich der einfachste, obwohl es mit Roslyn möglich sein sollte, spontan herauszufinden, welche Klassen IDisposible
erben.
Sie können auch immer nach einem Build die kompilierte .exe/.dll des Projekts in den Hintergrund laden und herausfinden, was die Typen dort sind, aber Sie müssten immer noch einen magischen Klebstoffcode schreiben, um herauszufinden, was Kurze Klassennamen im Code verweisen auf tatsächliche Klassen mit vollem Namen in der Assembly.
Der zweite Teil, Hervorhebung, ist ziemlich einfach, sobald Sie wissen, wie man es macht (es hilft, dass ich die letzten Monate Vollzeit gearbeitet habe, um VS zu erweitern). Natürlich ist mit Visual Studio nichts so einfach wie es aussieht (trotz der Bemühungen von Microsoft, es benutzerfreundlich zu machen). Also habe ich eine Beispielerweiterung erstellt, die nur Klassen mit dem Namen "Stream" in C# -Dateien hervorhebt, um Ihnen den Einstieg zu erleichtern.
Der entsprechende Code unten ist, und die volle project source is on GitHub). Es beginnt mit einem Klassifikations-Tagger Anbieter:
[Export(typeof(ITaggerProvider))]
[ContentType("CSharp")]
[TagType(typeof(ClassificationTag))]
[Name("HighlightDisposableTagger")]
public class HighlightDisposableTaggerProvider : ITaggerProvider
{
[Import]
private IClassificationTypeRegistryService _classificationRegistry = null;
[Import]
private IClassifierAggregatorService _classifierAggregator = null;
private bool _reentrant;
public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
if (_reentrant)
return null;
try {
_reentrant = true;
var classifier = _classifierAggregator.GetClassifier(buffer);
return new HighlightDisposableTagger(buffer, _classificationRegistry, classifier) as ITagger<T>;
}
finally {
_reentrant = false;
}
}
}
Dann wird der Tagger selbst:
public class HighlightDisposableTagger : ITagger<ClassificationTag>
{
private const string DisposableFormatName = "HighlightDisposableFormat";
[Export]
[Name(DisposableFormatName)]
public static ClassificationTypeDefinition DisposableFormatType = null;
[Export(typeof(EditorFormatDefinition))]
[Name(DisposableFormatName)]
[ClassificationType(ClassificationTypeNames = DisposableFormatName)]
[UserVisible(true)]
public class DisposableFormatDefinition : ClassificationFormatDefinition
{
public DisposableFormatDefinition()
{
DisplayName = "Disposable Format";
ForegroundColor = Color.FromRgb(0xFF, 0x00, 0x00);
}
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };
private ITextBuffer _subjectBuffer;
private ClassificationTag _tag;
private IClassifier _classifier;
private bool _reentrant;
public HighlightDisposableTagger(ITextBuffer subjectBuffer, IClassificationTypeRegistryService typeService, IClassifier classifier)
{
_subjectBuffer = subjectBuffer;
var classificationType = typeService.GetClassificationType(DisposableFormatName);
_tag = new ClassificationTag(classificationType);
_classifier = classifier;
}
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (_reentrant) {
return Enumerable.Empty<ITagSpan<ClassificationTag>>();
}
var tags = new List<ITagSpan<ClassificationTag>>();
try {
_reentrant = true;
foreach (var span in spans) {
if (span.IsEmpty)
continue;
foreach (var token in _classifier.GetClassificationSpans(span)) {
if (token.ClassificationType.IsOfType(/*PredefinedClassificationTypeNames.Identifier*/ "User Types")) {
// TODO: Somehow figure out if this refers to a class which implements IDisposable
if (token.Span.GetText() == "Stream") {
tags.Add(new TagSpan<ClassificationTag>(token.Span, _tag));
}
}
}
}
return tags;
}
finally {
_reentrant = false;
}
}
}
ich nur diese auf VS2010 getestet haben, aber es sollte für VS2013 zu (das einzige, was Arbeit, die Macht anders sein ist der Klasseneinstufungsname, aber das ist mit einem gut platzierten Haltepunkt leicht zu entdecken). Ich habe noch nie eine Erweiterung für VS2012 geschrieben, also kann ich dazu nichts sagen, aber ich weiß, dass VS2013 in vieler Hinsicht ziemlich nah dran ist.
Das wäre wunderbar. – TyCobb
Ich habe Ihren Erweiterungscode heruntergeladen und lokal ausgeführt. Es sieht so aus, als würde es für mich richtig funktionieren. Einziger Unterschied Ich kann mir vorstellen, dass ich in VS2012 vs. 2010 laufe, also musste ich ein Projekt neu erstellen und den Code kopieren. Ihr vsixmanifest hat nicht gut auf meinem Computer gespielt, vielleicht hat das Upgrade von 2010-> 2012 es irgendwie kaputt gemacht –
Siehe meine Updates über den Tooltip-Text. Verkenne ich, was ein Editor-Klassifikator ist? –