2014-07-10 23 views
11

Ich versuche, benutzerdefinierte Färbung für nur bestimmte Schlüsselwörter in meinem Visual Studio-Editor für C# -Code hinzuzufügen. Ich möchte in der Lage sein, jeden Typ zu färben, der IDisposable als eine andere Farbe implementiert. Im Idealfall möchte ich eine einfache Liste von Klassen/Interfaces erstellen, die von IDisposable in einer Art von Konfiguration stammen, die ich bearbeiten kann. (Obwohl, wenn Sie sagten, es gäbe eine Methode/ein Plugin, die automatisch alle verfügbaren Arten finden und sie unabhängig voneinander färben würde, wäre das der Heilige Gral).Benutzerdefinierte Stichwort Färbung in Visual Studio 2010 +

Ich habe eine Menge Forschung getan und es sieht so aus, als ob eine Erweiterung "Editor Classifier" den Trick machen könnte. Allerdings habe ich einen erstellt, der lediglich versucht, das Wort "Stream" einzufärben, und obwohl es meinen Code trifft, der versucht, dieses Wort hervorzuheben, endet es nicht im Editor.

Ich habe meine VS Erweiterung Github hinzugefügt here

Dies scheint wirklich so ziemlich einfach sein sollte, aber ich habe nach unten nur viele Gassen auf diesem wegen Sackgassen zu finden. Gibt es einen einfacheren Weg, oder ist meine Erweiterung kaputt?

aktualisieren

Sehr seltsam. Ich habe gerade meine Erweiterung erneut ausgeführt und obwohl sie den Text im Editor nicht hervorhebt, markiert sie alle Instanzen von "Stream" im Popup-Text, wenn Sie den Mauszeiger über einen Typ/eine Variable bewegen! Gibt es eine Möglichkeit, um es für den Editor gelten zu lassen?

enter image description here

+3

Das wäre wunderbar. – TyCobb

+0

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 –

+0

Siehe meine Updates über den Tooltip-Text. Verkenne ich, was ein Editor-Klassifikator ist? –

Antwort

3

Je nachdem, ob Sie Jetbrains ReSharper oder nicht verwenden können Sie ein Plugin für das schreiben. Auf diese Weise können Sie IDisposable nicht nur visuell auf eine Variable hinweisen, sondern auch Quickfixes bereitstellen, und zwar nur dann, wenn es nicht aufgerufen wird, was ich annehmen möchte. Wohlgemerkt, ich kann mir vorstellen, dass es dafür bereits ein R # -Plugin gibt. Ich weiß, dass ich darüber nachgedacht habe, aber ich war zu faul, um dafür ein Plugin zu schreiben.

Versteh mich nicht falsch BTW - Wenn Sie r # noch nicht verwenden, sollten Sie darüber nachdenken, es auszuprobieren.

Sie unter anderem mit diesem arbeiten würden: API-QuickFix

Es gibt auch Möglichkeiten, individuelle Schlüsselwörter zu definieren, wie ReSharper von einem benutzerdefinierten Markup gegeben hat, und gelten quickfixes darauf.

PS: Nein, ich arbeite nicht bei Jetbrains. es ist nur so gut :)

UPDATE:

Potential VS Erweiterung beheben?

Karo dieses heraus: MSDN Link Highlighting Text

Ich habe versucht, Ihr Github-Projekt zu öffnen, konnte aber nicht so dachte ich, ich werde einfach Msdn statt überprüfen. Es scheint, dass Sie von der falschen Klasse abgeleitet sind, um Ihre Bedürfnisse zu erfüllen?

MSDN Stichwort „Editors - Erweiterung den Editor - Exemplarische Vorgehensweise: Hervorhebungen Text“

Ich weiß, SO will Code auf der Website, aber Msdn Links going down ist eher unwahrscheinlich, und mit den gegebenen Informationen kann der Inhalt leicht zu finden So genug :)

+0

Liebe Resharper, aber es hat nicht das Budget die letzten paar Jahre gemacht. Hoffe auf eine kostenlose oder DIY-Lösung –

+0

@mjmarsh hey. Was ist dann dein Status? hat es funktioniert? github update wurde noch nicht angezeigt – Dbl

1

, eine mögliche Lösung (ich glaube, dies funktioniert):

1) erstellen Sie Ihren eigenen Inhaltstyp, der von csharp erbt.

2) Erstellen Sie einen neuen TextViewCreationListener, der alle "csharp" Inhaltstypen mit Ihren eigenen austauscht und somit möglicherweise alle anderen Klassifikatoren "entwaffnet".

3) Registrieren Sie Ihren Klassifikator, um Ihren eigenen Inhaltstyp zu verarbeiten.

Hier einige der Code ist:

[Export(typeof(IVsTextViewCreationListener))] 
[ContentType("csharp")] 
[TextViewRole(PredefinedTextViewRoles.Editable)] 
class TextViewCreationListener : IVsTextViewCreationListener { 
    internal readonly IVsEditorAdaptersFactoryService _adaptersFactory; 

    [Import] internal IContentTypeRegistryService ContentTypeRegistryService = null; 

    [ImportingConstructor] 
    public TextViewCreationListener(IVsEditorAdaptersFactoryService adaptersFactory) { 
     _adaptersFactory = adaptersFactory; 
    } 

    #region IVsTextViewCreationListener Members 

    public void VsTextViewCreated(VisualStudio.TextManager.Interop.IVsTextView textViewAdapter) { 
     var textView = _adaptersFactory.GetWpfTextView(textViewAdapter); 

     var myContent = ContentTypeRegistryService.GetContentType(MyContentType); 
     if(myContent == null) 
     { 
      ContentTypeRegistryService.AddContentType(MyContentType, new[] {"csharp"}); 
      myContent = ContentTypeRegistryService.GetContentType(MyContentType); 
     } 

     // some kind of check if the content type is not already MyContentType. 
     textView.TextBuffer.ChangeContentType(myContent, null); 
    } 

    #endregion 
} 

Und jetzt, ändern Sie einfach Ihre IClassifierProvider mit Ihrem eigenen Inhaltstyp, die als solche registrieren: [ContentType(MyContentType)]

Iin Ihre eigene IClassifier, Sie im Grunde tun können Ihre eigene Berechnung und sobald Sie denken, dass Sie nicht mit dem Zeug umgehen können, könnten Sie die Kontrolle an andere Klassifikatoren übergeben.

Wenn Sie MEF verwenden und IClassifierAggregatorService importieren, können Sie einen "MASTER-Klassifikator" erhalten, der die gesamte Logik für Sie ausführt. Ich habe es noch nicht implementiert, aber ich habe etwas ähnliches in der Vergangenheit vorgeschlagen, und es schien zu funktionieren. Alternativ könntest du vielleicht [ImportMany] mit List<IClassifier> verwenden und die csharp-Einsen herausfiltern ?!

+0

Das 'Order'-Attribut bei Editor-Formatdefinitionen wirkt sich nur auf die Reihenfolge aus, in der sie in den Fonts & Colors-Optionen angezeigt werden. Wie beim Anwenden von 'Order' auf den Provider selbst, können Sie' Order (After = Priority.Default) 'verwenden, aber ich bin mir nicht ganz sicher, ob jemand dieses Attribut beim Ausführen der Klassifikatoren betrachtet. – Cameron

+0

Ich habe meine Antwort mit neuer möglicher Antwort bearbeitet. Was deinen Kommentar angeht, ist es wahr. Bevor ich die vorherige Antwort posten konnte, habe ich etwas von der Dekompilierung gemacht und absolut keine Beweise gefunden, dass Order [()] für Klassifikatoren funktionieren würde, obwohl ich sah, dass es in einigen Microsoft-Codes verwendet wurde und dachte, dass es sich lohnt . –

2

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:.

  1. die Klassen zu finden, die IDisposable
  2. 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.

highlighting at work

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.