Przewodnik: wyświetlanie etykietek narzędzi QuickInfo

QuickInfo to funkcja IntelliSense, która wyświetla podpisy i opisy metod, gdy użytkownik przenosi wskaźnik na nazwę metody. Funkcje oparte na języku, takie jak QuickInfo, można zaimplementować, definiując identyfikatory, dla których chcesz podać opisy QuickInfo, a następnie tworząc etykietkę narzędzia, w której ma być wyświetlana zawartość. Możesz zdefiniować quickinfo w kontekście usługi językowej lub zdefiniować własne rozszerzenie nazwy pliku i typ zawartości oraz wyświetlić quickinfo tylko dla tego typu lub wyświetlić QuickInfo dla istniejącego typu zawartości (np. "text"). W tym przewodniku pokazano, jak wyświetlić quickinfo dla typu zawartości "text".

Przykład QuickInfo w tym przewodniku wyświetla etykietki narzędzi, gdy użytkownik przenosi wskaźnik nad nazwą metody. Ten projekt wymaga zaimplementowania tych czterech interfejsów:

  • interfejs źródłowy

  • interfejs dostawcy źródłowego

  • interfejs kontrolera

  • interfejs dostawcy kontrolera

    Dostawcy źródłowych i kontrolerów są składnikami Managed Extensibility Framework (MEF) i są odpowiedzialni za eksportowanie klas źródłowych i kontrolerów oraz importowanie usług i brokerów, takich jak ITextBufferFactoryService, który tworzy bufor tekstu etykietki narzędzia i IQuickInfoBroker, który wyzwala sesję QuickInfo.

    W tym przykładzie źródło QuickInfo używa trwale zakodowanej listy nazw metod i opisów, ale w pełnych implementacjach usługa językowa i dokumentacja języka są odpowiedzialne za dostarczanie tej zawartości.

Tworzenie projektu MEF

Aby utworzyć projekt MEF

  1. Utwórz projekt VSIX w języku C#. (W Okno dialogowe Nowy projekt , wybierz pozycję Visual C# / Rozszerzalność, a następnie projekt VSIX. Nadaj rozwiązaniu QuickInfoTestnazwę .

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

  3. Usuń istniejące pliki klas.

Implementowanie źródła QuickInfo

Źródło QuickInfo jest odpowiedzialne za zbieranie zestawu identyfikatorów i ich opisów oraz dodawanie zawartości do buforu tekstowego etykietki narzędzia po napotkaniu jednego z identyfikatorów. W tym przykładzie identyfikatory i ich opisy są właśnie dodawane w konstruktorze źródłowym.

Aby zaimplementować źródło QuickInfo

  1. Dodaj plik klasy i nadaj mu TestQuickInfoSourcenazwę .

  2. Dodaj odwołanie do microsoft.VisualStudio.Language.IntelliSense.

  3. Dodaj następujące importy.

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Text.Operations;
    using Microsoft.VisualStudio.Text.Tagging;
    using Microsoft.VisualStudio.Utilities;
    
  4. Zadeklaruj klasę, która implementuje element , i nadaj IQuickInfoSourcemu TestQuickInfoSourcenazwę .

    internal class TestQuickInfoSource : IQuickInfoSource
    
  5. Dodaj pola dla dostawcy źródła QuickInfo, buforu tekstu i zestawu nazw metod i podpisów metod. W tym przykładzie nazwy metod i podpisy są inicjowane w konstruktorze TestQuickInfoSource .

    private TestQuickInfoSourceProvider m_provider;
    private ITextBuffer m_subjectBuffer;
    private Dictionary<string, string> m_dictionary;
    
  6. Dodaj konstruktor, który ustawia dostawcę źródła QuickInfo i bufor tekstu oraz wypełnia zestaw nazw metod oraz podpisy i opisy metod.

    public TestQuickInfoSource(TestQuickInfoSourceProvider provider, ITextBuffer subjectBuffer)
    {
        m_provider = provider;
        m_subjectBuffer = subjectBuffer;
    
        //these are the method names and their descriptions
        m_dictionary = new Dictionary<string, string>();
        m_dictionary.Add("add", "int add(int firstInt, int secondInt)\nAdds one integer to another.");
        m_dictionary.Add("subtract", "int subtract(int firstInt, int secondInt)\nSubtracts one integer from another.");
        m_dictionary.Add("multiply", "int multiply(int firstInt, int secondInt)\nMultiplies one integer by another.");
        m_dictionary.Add("divide", "int divide(int firstInt, int secondInt)\nDivides one integer by another.");
    }
    
  7. Zaimplementuj metodę AugmentQuickInfoSession . W tym przykładzie metoda znajduje bieżące słowo lub poprzednie słowo, jeśli kursor znajduje się na końcu wiersza lub buforu tekstu. Jeśli słowo jest jedną z nazw metod, opis tej nazwy metody jest dodawany do zawartości QuickInfo.

    public void AugmentQuickInfoSession(IQuickInfoSession session, IList<object> qiContent, out ITrackingSpan applicableToSpan)
    {
        // Map the trigger point down to our buffer.
        SnapshotPoint? subjectTriggerPoint = session.GetTriggerPoint(m_subjectBuffer.CurrentSnapshot);
        if (!subjectTriggerPoint.HasValue)
        {
            applicableToSpan = null;
            return;
        }
    
        ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot;
        SnapshotSpan querySpan = new SnapshotSpan(subjectTriggerPoint.Value, 0);
    
        //look for occurrences of our QuickInfo words in the span
        ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_subjectBuffer);
        TextExtent extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value);
        string searchText = extent.Span.GetText();
    
        foreach (string key in m_dictionary.Keys)
        {
            int foundIndex = searchText.IndexOf(key, StringComparison.CurrentCultureIgnoreCase);
            if (foundIndex > -1)
            {
                applicableToSpan = currentSnapshot.CreateTrackingSpan
                    (
                    //querySpan.Start.Add(foundIndex).Position, 9, SpanTrackingMode.EdgeInclusive
                                            extent.Span.Start + foundIndex, key.Length, SpanTrackingMode.EdgeInclusive
                    );
    
                string value;
                m_dictionary.TryGetValue(key, out value);
                if (value != null)
                    qiContent.Add(value);
                else
                    qiContent.Add("");
    
                return;
            }
        }
    
        applicableToSpan = null;
    }
    
  8. Należy również zaimplementować metodę Dispose(), ponieważ IQuickInfoSource implementuje IDisposablemetodę :

    private bool m_isDisposed;
    public void Dispose()
    {
        if (!m_isDisposed)
        {
            GC.SuppressFinalize(this);
            m_isDisposed = true;
        }
    }
    

Implementowanie dostawcy źródła QuickInfo

Dostawca źródła QuickInfo służy przede wszystkim do eksportowania się jako części składnika MEF i tworzenia wystąpienia źródła QuickInfo. Ponieważ jest to część składnika MEF, może importować inne części składników MEF.

Aby zaimplementować dostawcę źródła QuickInfo

  1. Zadeklaruj dostawcę źródła QuickInfo o nazwie TestQuickInfoSourceProvider , który implementuje IQuickInfoSourceProviderelement , i wyeksportuj go za pomocą NameAttribute wartości "Źródło QuickInfo etykietki narzędzia", wartości OrderAttribute Before="default" i " ContentTypeAttribute text".

    [Export(typeof(IQuickInfoSourceProvider))]
    [Name("ToolTip QuickInfo Source")]
    [Order(Before = "Default Quick Info Presenter")]
    [ContentType("text")]
    internal class TestQuickInfoSourceProvider : IQuickInfoSourceProvider
    
  2. Zaimportuj dwie usługi ITextStructureNavigatorSelectorService edytora i ITextBufferFactoryService, jako właściwości TestQuickInfoSourceProvider.

    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
    [Import]
    internal ITextBufferFactoryService TextBufferFactoryService { get; set; }
    
  3. Zaimplementuj TryCreateQuickInfoSource , aby zwrócić nowy TestQuickInfoSourceelement .

    public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer)
    {
        return new TestQuickInfoSource(this, textBuffer);
    }
    

Implementowanie kontrolera QuickInfo

Kontrolery QuickInfo określają, kiedy jest wyświetlana funkcja QuickInfo. W tym przykładzie funkcja QuickInfo pojawia się, gdy wskaźnik znajduje się nad wyrazem odpowiadającym jednej z nazw metod. Kontroler QuickInfo implementuje program obsługi zdarzeń aktywowania myszy, który wyzwala sesję QuickInfo.

Aby zaimplementować kontroler QuickInfo

  1. Zadeklaruj klasę, która implementuje element , i nadaj IIntellisenseControllermu TestQuickInfoControllernazwę .

    internal class TestQuickInfoController : IIntellisenseController
    
  2. Dodaj pola prywatne dla widoku tekstowego, bufory tekstowe reprezentowane w widoku tekstowym, sesji QuickInfo i dostawcy kontrolera QuickInfo.

    private ITextView m_textView;
    private IList<ITextBuffer> m_subjectBuffers;
    private TestQuickInfoControllerProvider m_provider;
    private IQuickInfoSession m_session;
    
  3. Dodaj konstruktor, który ustawia pola i dodaje procedurę obsługi zdarzeń aktywowania myszy.

    internal TestQuickInfoController(ITextView textView, IList<ITextBuffer> subjectBuffers, TestQuickInfoControllerProvider provider)
    {
        m_textView = textView;
        m_subjectBuffers = subjectBuffers;
        m_provider = provider;
    
        m_textView.MouseHover += this.OnTextViewMouseHover;
    }
    
  4. Dodaj procedurę obsługi zdarzeń aktywowania myszy, która wyzwala sesję QuickInfo.

    private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e)
    {
        //find the mouse position by mapping down to the subject buffer
        SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch
             (new SnapshotPoint(m_textView.TextSnapshot, e.Position),
            PointTrackingMode.Positive,
            snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer),
            PositionAffinity.Predecessor);
    
        if (point != null)
        {
            ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position,
            PointTrackingMode.Positive);
    
            if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView))
            {
                m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true);
            }
        }
    }
    
  5. Zaimplementuj metodę Detach tak, aby usuwała program obsługi zdarzeń aktywowania myszy, gdy kontroler jest odłączony od widoku tekstu.

    public void Detach(ITextView textView)
    {
        if (m_textView == textView)
        {
            m_textView.MouseHover -= this.OnTextViewMouseHover;
            m_textView = null;
        }
    }
    
  6. W tym przykładzie zaimplementuj metodę ConnectSubjectBuffer i metodę DisconnectSubjectBuffer jako pustą.

    public void ConnectSubjectBuffer(ITextBuffer subjectBuffer)
    {
    }
    
    public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer)
    {
    }
    

Implementowanie dostawcy kontrolera QuickInfo

Dostawca kontrolera QuickInfo służy przede wszystkim do eksportowania się jako części składnika MEF i tworzenia wystąpienia kontrolera QuickInfo. Ponieważ jest to część składnika MEF, może importować inne części składników MEF.

Aby zaimplementować dostawcę kontrolera QuickInfo

  1. Zadeklaruj klasę o nazwie TestQuickInfoControllerProvider , która implementuje IIntellisenseControllerProviderelement , i wyeksportuj go za pomocą NameAttribute elementu "ToolTip QuickInfo Controller" i elementu ContentTypeAttribute "text":

    [Export(typeof(IIntellisenseControllerProvider))]
    [Name("ToolTip QuickInfo Controller")]
    [ContentType("text")]
    internal class TestQuickInfoControllerProvider : IIntellisenseControllerProvider
    
  2. Zaimportuj właściwość IQuickInfoBroker jako.

    [Import]
    internal IQuickInfoBroker QuickInfoBroker { get; set; }
    
  3. Zaimplementuj metodę TryCreateIntellisenseController , tworząc wystąpienie kontrolera QuickInfo.

    public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers)
    {
        return new TestQuickInfoController(textView, subjectBuffers, this);
    }
    

Kompilowanie i testowanie kodu

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

Aby skompilować i przetestować rozwiązanie QuickInfoTest

  1. Stwórz 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 zawierający wyrazy "add" i "odejmowanie".

  4. Przenieś wskaźnik na jedno z wystąpień polecenia "add". Powinien zostać wyświetlony podpis i opis add metody.