Udostępnij za pośrednictwem


Instrukcja: wyświetlanie podpowiedzi dotyczących żarówki

Żarówki to ikony w edytorze programu Visual Studio, które rozszerzają się, aby wyświetlić zestaw akcji, na przykład poprawki problemów zidentyfikowanych przez wbudowane analizatory kodu lub refaktoryzację kodu.

W edytorach Visual C# i Visual Basic można również użyć platformy kompilatora .NET ("Roslyn"), aby napisać i spakować własne analizatory kodu za pomocą akcji, które automatycznie wyświetlają żarówki. Aby uzyskać więcej informacji, zobacz:

  • Instrukcje: pisanie diagnostyki i poprawki kodu w języku C#

  • Jak napisać diagnostykę języka Visual Basic i poprawkę kodu

    Inne języki, takie jak C++, również oferują podpowiedzi do szybkiego działania, takie jak sugestia utworzenia szkieletowej implementacji tej funkcji.

    Oto, jak wygląda żarówka. W projekcie Visual Basic lub Visual C# czerwona falista linia pojawia się pod nazwą zmiennej, gdy jest ona nieprawidłowa. W przypadku myszy nad nieprawidłowym identyfikatorem żarówka pojawi się w pobliżu kursora.

    żarówka

    Po kliknięciu strzałki w dół przez żarówkę zostanie wyświetlony zestaw sugerowanych akcji wraz z podglądem wybranej akcji. W takim przypadku pokazuje zmiany wprowadzone w kodzie, jeśli wykonasz akcję.

    żarówka (wersja zapoznawcza)

    Możesz użyć żarówek, aby przedstawić własne sugerowane akcje. Można na przykład podać akcje, aby przenieść nawiasy klamrowe otwierające do nowego wiersza lub przenieść je na koniec poprzedniego wiersza. W poniższej instrukcji pokazano, jak utworzyć żarówkę pojawiającą się nad bieżącym słowem, która ma dwie sugerowane akcje: Konwertuj na wielkie litery i Konwertuj na małe litery.

Tworzenie projektu zarządzanej struktury rozszerzalności (MEF)

  1. Utwórz projekt VSIX w języku C#. (W oknie dialogowym Nowy projekt wybierz pozycję Visual C# / Rozszerzalność, a następnie projekt VSIX.) Nadaj rozwiązaniu nazwę LightBulbTest.

  2. Dodaj do projektu szablon elementu klasyfikatora edytora . Aby uzyskać więcej informacji, zobacz Tworzenie rozszerzenia za pomocą szablonu elementu edytora.

  3. Usuń istniejące pliki klas.

  4. Dodaj następujące odwołanie do projektu i ustaw Kopiuj lokalne na False:

    Microsoft.VisualStudio.Language.Intellisense

  5. Dodaj nowy plik klasy i nadaj mu nazwę LightBulbTest.

  6. Dodaj następujące dyrektywy using:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Text.Operations;
    using Microsoft.VisualStudio.Utilities;
    using System.ComponentModel.Composition;
    using System.Threading;
    
    

Implementowanie dostawcy źródła żarówki

  1. W pliku klasy LightBulbTest.cs usuń klasę LightBulbTest. Dodaj klasę o nazwie TestSuggestedActionsSourceProvider, która implementuje ISuggestedActionsSourceProvider. Wyeksportuj go z nazwą "Test sugerowanych akcji" oraz ContentTypeAttribute "tekst".

    [Export(typeof(ISuggestedActionsSourceProvider))]
    [Name("Test Suggested Actions")]
    [ContentType("text")]
    internal class TestSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider
    
  2. Wewnątrz klasy dostawcy źródłowego zaimportuj ITextStructureNavigatorSelectorService i dodaj ją jako właściwość.

    [Import(typeof(ITextStructureNavigatorSelectorService))]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  3. Zaimplementuj metodę CreateSuggestedActionsSource, aby zwrócić obiekt ISuggestedActionsSource. Źródło zostało omówione w następnej sekcji.

    public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer)
    {
        if (textBuffer == null || textView == null)
        {
            return null;
        }
        return new TestSuggestedActionsSource(this, textView, textBuffer);
    }
    

Implementacja ISuggestedActionSource

Sugerowane źródło akcji jest odpowiedzialne za zbieranie zestawu sugerowanych akcji i dodawanie ich w odpowiednim kontekście. W tym przypadku kontekst stanowi aktualne słowo, a sugerowane akcje to UpperCaseSuggestedAction i LowerCaseSuggestedAction, które zostały omówione w poniższej sekcji.

  1. Dodaj klasę TestSuggestedActionsSource, która implementuje ISuggestedActionsSource.

    internal class TestSuggestedActionsSource : ISuggestedActionsSource
    
  2. Dodaj prywatne pola tylko do odczytu dla sugerowanego dostawcy źródła akcji, bufor tekstu i widok tekstu.

    private readonly TestSuggestedActionsSourceProvider m_factory;
    private readonly ITextBuffer m_textBuffer;
    private readonly ITextView m_textView;
    
  3. Dodaj konstruktor, który ustawia pola prywatne.

    public TestSuggestedActionsSource(TestSuggestedActionsSourceProvider testSuggestedActionsSourceProvider, ITextView textView, ITextBuffer textBuffer)
    {
        m_factory = testSuggestedActionsSourceProvider;
        m_textBuffer = textBuffer;
        m_textView = textView;
    }
    
  4. Dodaj prywatną metodę zwracającą słowo, które znajduje się obecnie pod kursorem. Poniższa metoda analizuje bieżącą lokalizację kursora i pyta nawigator struktury tekstu o zakres słowa. Jeśli kursor znajduje się na słowie, TextExtent jest zwracany w parametrze wyjściowym; w przeciwnym razie parametr out jest null, a metoda zwraca false.

    private bool TryGetWordUnderCaret(out TextExtent wordExtent)
    {
        ITextCaret caret = m_textView.Caret;
        SnapshotPoint point;
    
        if (caret.Position.BufferPosition > 0)
        {
            point = caret.Position.BufferPosition - 1;
        }
        else
        {
            wordExtent = default(TextExtent);
            return false;
        }
    
        ITextStructureNavigator navigator = m_factory.NavigatorService.GetTextStructureNavigator(m_textBuffer);
    
        wordExtent = navigator.GetExtentOfWord(point);
        return true;
    }
    
  5. Zaimplementuj metodę HasSuggestedActionsAsync. Edytor wywołuje tę metodę, aby dowiedzieć się, czy ma być wyświetlana żarówka. To wywołanie jest wykonywane często na przykład za każdym razem, gdy kursor przesuwa się z jednego wiersza do innego lub gdy wskaźnik myszy najeżdża na podkreślenie błędu. Jest asynchroniczna, aby umożliwić wykonywanie innych operacji interfejsu użytkownika podczas pracy tej metody. W większości przypadków ta metoda musi wykonać parsowanie i analizę aktualnej linii, więc przetwarzanie może zająć trochę czasu.

    W tej implementacji asynchronicznie pobiera TextExtent i określa, czy zakres jest znaczący, czyli czy zawiera jakiś tekst inny niż puste znaki.

    public Task<bool> HasSuggestedActionsAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken)
    {
        return Task.Factory.StartNew(() =>
        {
            TextExtent extent;
            if (TryGetWordUnderCaret(out extent))
            {
                // don't display the action if the extent has whitespace
                return extent.IsSignificant;
              }
            return false;
        });
    }
    
  6. Zaimplementuj metodę GetSuggestedActions, która zwraca tablicę obiektów SuggestedActionSet zawierających różne obiekty ISuggestedAction. Ta metoda jest wywoływana po rozszerzeniu żarówki.

    Ostrzeżenie

    Upewnij się, że implementacje HasSuggestedActionsAsync() i GetSuggestedActions() są spójne; oznacza to, że jeśli HasSuggestedActionsAsync() zwraca true, GetSuggestedActions() powinny mieć kilka akcji do wyświetlenia. W wielu przypadkach HasSuggestedActionsAsync() jest wywoływana tuż przed GetSuggestedActions(), ale nie zawsze tak jest. Jeśli na przykład użytkownik wywołuje akcje żarówki, naciskając (ctrl+ ). Wywoływana jest tylko GetSuggestedActions().

    public IEnumerable<SuggestedActionSet> GetSuggestedActions(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken)
    {
        TextExtent extent;
        if (TryGetWordUnderCaret(out extent) && extent.IsSignificant)
        {
            ITrackingSpan trackingSpan = range.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive);
            var upperAction = new UpperCaseSuggestedAction(trackingSpan);
            var lowerAction = new LowerCaseSuggestedAction(trackingSpan);
            return new SuggestedActionSet[] { new SuggestedActionSet(new ISuggestedAction[] { upperAction, lowerAction }) };
        }
        return Enumerable.Empty<SuggestedActionSet>();
    }
    
  7. Zdefiniuj zdarzenie SuggestedActionsChanged.

    public event EventHandler<EventArgs> SuggestedActionsChanged;
    
  8. Aby ukończyć implementację, dodaj implementacje dla metod Dispose() i TryGetTelemetryId(). Nie chcesz wykonywać telemetrii, więc wystarczy zwrócić false i ustawić identyfikator GUID na wartość Empty.

    public void Dispose()
    {
    }
    
    public bool TryGetTelemetryId(out Guid telemetryId)
    {
        // This is a sample provider and doesn't participate in LightBulb telemetry
        telemetryId = Guid.Empty;
        return false;
    }
    

Implementacja działań dotyczących żarówki

  1. W projekcie dodaj odwołanie do Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll i ustaw Kopiuj lokalnie na False.

  2. Utwórz dwie klasy, pierwszą o nazwie UpperCaseSuggestedAction i drugą o nazwie LowerCaseSuggestedAction. Obie klasy implementują ISuggestedAction.

    internal class UpperCaseSuggestedAction : ISuggestedAction
    internal class LowerCaseSuggestedAction : ISuggestedAction
    

    Obie klasy są podobne, z tą różnicą, że jedna wywołuje ToUpper, a drugie wywołuje ToLower. Poniższe kroki dotyczą tylko klasy akcji z wielkimi literami, ale należy zaimplementować obie klasy. Użyj kroków implementacji akcji zamiany na wielkie litery jako wzorca do implementacji akcji zamiany na małe litery.

  3. Dodaj następujące dyrektywy using dla tych klas:

    using Microsoft.VisualStudio.Imaging.Interop;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
    
    
  4. Zadeklaruj zestaw pól prywatnych.

    private ITrackingSpan m_span;
    private string m_upper;
    private string m_display;
    private ITextSnapshot m_snapshot;
    
  5. Dodaj konstruktor, który ustawia pola.

    public UpperCaseSuggestedAction(ITrackingSpan span)
    {
        m_span = span;
        m_snapshot = span.TextBuffer.CurrentSnapshot;
        m_upper = span.GetText(m_snapshot).ToUpper();
        m_display = string.Format("Convert '{0}' to upper case", span.GetText(m_snapshot));
    }
    
  6. Zaimplementuj metodę GetPreviewAsync, aby wyświetlić podgląd akcji.

    public Task<object> GetPreviewAsync(CancellationToken cancellationToken)
    {
        var textBlock = new TextBlock();
        textBlock.Padding = new Thickness(5);
        textBlock.Inlines.Add(new Run() { Text = m_upper });
        return Task.FromResult<object>(textBlock);
    }
    
  7. Zaimplementuj metodę GetActionSetsAsync, aby zwracała pustą SuggestedActionSet enumerację.

    public Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult<IEnumerable<SuggestedActionSet>>(null);
    }
    
  8. Zaimplementuj właściwości w następujący sposób.

    public bool HasActionSets
    {
        get { return false; }
    }
    public string DisplayText
    {
        get { return m_display; }
    }
    public ImageMoniker IconMoniker
    {
       get { return default(ImageMoniker); }
    }
    public string IconAutomationText
    {
        get
        {
            return null;
        }
    }
    public string InputGestureText
    {
        get
        {
            return null;
        }
    }
    public bool HasPreview
    {
        get { return true; }
    }
    
  9. Zaimplementuj metodę Invoke, zastępując tekst w określonym fragmencie jego wielkimi literami.

    public void Invoke(CancellationToken cancellationToken)
    {
        m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper);
    }
    

    Ostrzeżenie

    Akcja żarówki Wywołaj metodę nie powinna pokazywać interfejsu użytkownika. Jeśli akcja powoduje wyświetlenie nowego interfejsu użytkownika (na przykład okna dialogowego podglądu lub wyboru), nie wyświetlaj interfejsu użytkownika bezpośrednio z poziomu metody Invoke, ale zamiast tego zaplanuj wyświetlanie interfejsu użytkownika po powrocie z Invoke.

  10. Aby ukończyć implementację, dodaj metody Dispose() i TryGetTelemetryId().

    public void Dispose()
    {
    }
    
    public bool TryGetTelemetryId(out Guid telemetryId)
    {
        // This is a sample action and doesn't participate in LightBulb telemetry
        telemetryId = Guid.Empty;
        return false;
    }
    
  11. Nie zapomnij wykonać tej samej czynności dla LowerCaseSuggestedAction, zmieniając tekst wyświetlany na "Konwertuj '{0}' na małe litery", oraz zmień wywołanie ToUpper na ToLower.

Kompilowanie i testowanie kodu

Aby przetestować ten kod, skompiluj rozwiązanie LightBulbTest i uruchom je w wystąpieniu eksperymentalnym.

  1. Skompiluj rozwiązanie.

  2. Po uruchomieniu tego projektu w debugerze zostanie uruchomione drugie wystąpienie programu Visual Studio.

  3. Utwórz plik tekstowy i wpisz tekst. Powinna zostać wyświetlona żarówka po lewej stronie tekstu.

    przetestować żarówkę

  4. Wskaż żarówkę. Powinna zostać wyświetlona strzałka w dół.

  5. Po kliknięciu żarówki powinny zostać wyświetlone dwie sugerowane akcje wraz z podglądem wybranej akcji.

    żarówka testowa rozszerzona

  6. Jeśli klikniesz pierwszą akcję, cały tekst w bieżącym słowie powinien zostać przekonwertowany na wielkie litery. Jeśli klikniesz drugą akcję, cały tekst powinien zostać przekonwertowany na małe litery.