Návod: Nápověda k zobrazení podpisu

Nápověda k podpisu (označovaná také jako Informace o parametrech) zobrazuje podpis metody v popisu, když uživatel zadá počáteční znak seznamu parametrů (obvykle levou závorku). Jako typ parametru a oddělovače parametrů (obvykle čárka) se popis aktualizuje tak, aby zobrazoval další parametr tučně. Nápovědu k podpisu můžete definovat následujícími způsoby: v kontextu služby jazyka, definujte vlastní příponu názvu souboru a typ obsahu a zobrazte nápovědu k podpisu pro tento typ nebo zobrazte nápovědu k podpisu pro existující typ obsahu (například "text"). Tento názorný postup ukazuje, jak zobrazit nápovědu k podpisu pro typ obsahu "text".

Nápovědu k podpisu obvykle aktivujete zadáním konkrétního znaku, například "(" (levá závorka) a zavřete zadáním jiného znaku, například ")" (pravá závorka). Funkce IntelliSense aktivované zadáním znaku lze implementovat pomocí obslužné rutiny příkazu pro stisknutí kláves ( IOleCommandTarget rozhraní) a zprostředkovatele obslužné rutiny, který implementuje IVsTextViewCreationListener rozhraní. Chcete-li vytvořit zdroj nápovědy podpisu, což je seznam podpisů, které se účastní nápovědy k podpisu, implementujte ISignatureHelpSource rozhraní a zdrojového zprostředkovatele, který spouští ISignatureHelpSourceProvider rozhraní. Zprostředkovatelé jsou součásti meF (Managed Extensibility Framework) a jsou zodpovědní za export tříd zdrojového a kontroleru a import služeb a zprostředkovatelů, ITextStructureNavigatorSelectorServicenapříklad , který umožňuje navigaci v textové vyrovnávací paměti a ISignatureHelpBroker, který aktivuje relaci Nápovědy podpisu.

Tento návod ukazuje, jak nastavit nápovědu k podpisu pro pevně zakódovanou sadu identifikátorů. V úplných implementacích je jazyk zodpovědný za poskytování daného obsahu.

Vytvoření projektu MEF

Vytvoření projektu MEF

  1. Vytvořte projekt VSIX jazyka C#. (V Dialogové okno Nový projekt , vyberte Visual C# / Rozšiřitelnost a pak projekt VSIX.) Pojmenujte řešení SignatureHelpTest.

  2. Přidejte do projektu šablonu položky klasifikátoru editoru. Další informace najdete v tématu Vytvoření rozšíření pomocí šablony položky editoru.

  3. Odstraňte existující soubory třídy.

  4. Přidejte do projektu následující odkazy a ujistěte se, že je vlastnost CopyLocal nastavená na false:

    Microsoft.VisualStudio.Editor

    Microsoft.VisualStudio.Language.Intellisense

    Microsoft.VisualStudio.OLE.Interop

    Microsoft.VisualStudio.Shell.14.0

    Microsoft.VisualStudio.TextManager.Interop

Implementace podpisových podpisů a parametrů nápovědy

Zdroj nápovědy podpisu je založen na podpisech, které implementují ISignature, každý z nich obsahuje parametry, které implementují IParameter. V úplné implementaci by se tyto informace získaly z dokumentace jazyka, ale v tomto příkladu jsou podpisy pevně zakódované.

Implementace podpisových podpisů a parametrů nápovědy

  1. Přidejte soubor třídy a pojmenujte ho SignatureHelpSource.

  2. Přidejte následující importy.

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Utilities;
    using Microsoft.VisualStudio.Editor;
    using Microsoft.VisualStudio.Text.Operations;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.OLE.Interop;
    
  3. Přidejte třídu s názvem TestParameter , která implementuje IParameter.

    internal class TestParameter : IParameter
    
  4. Přidejte konstruktor, který nastaví všechny vlastnosti.

    public TestParameter(string documentation, Span locus, string name, ISignature signature)
    {
        Documentation = documentation;
        Locus = locus;
        Name = name;
        Signature = signature;
    }
    
  5. Přidejte vlastnosti .IParameter

    public string Documentation { get; private set; }
    public Span Locus { get; private set; }
    public string Name { get; private set; }
    public ISignature Signature { get; private set; }
    public Span PrettyPrintedLocus { get; private set; }
    
  6. Přidejte třídu s názvem TestSignature , která implementuje ISignature.

    internal class TestSignature : ISignature
    
  7. Přidejte některá soukromá pole.

    private ITextBuffer m_subjectBuffer;
    private IParameter m_currentParameter;
    private string m_content;
    private string m_documentation;
    private ITrackingSpan m_applicableToSpan;
    private ReadOnlyCollection<IParameter> m_parameters;
    private string m_printContent;
    
  8. Přidejte konstruktor, který nastaví pole a přihlásí se k odběru Changed události.

    internal TestSignature(ITextBuffer subjectBuffer, string content, string doc, ReadOnlyCollection<IParameter> parameters)
    {
        m_subjectBuffer = subjectBuffer;
        m_content = content;
        m_documentation = doc;
        m_parameters = parameters;
        m_subjectBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(OnSubjectBufferChanged);
    }
    
  9. Deklarujte CurrentParameterChanged událost. Tato událost se vyvolá, když uživatel vyplní jeden z parametrů v podpisu.

    public event EventHandler<CurrentParameterChangedEventArgs> CurrentParameterChanged;
    
  10. CurrentParameter Implementujte vlastnost tak, aby vyvolala CurrentParameterChanged událost při změně hodnoty vlastnosti.

    public IParameter CurrentParameter
    {
        get { return m_currentParameter; }
        internal set
        {
            if (m_currentParameter != value)
            {
                IParameter prevCurrentParameter = m_currentParameter;
                m_currentParameter = value;
                this.RaiseCurrentParameterChanged(prevCurrentParameter, m_currentParameter);
            }
        }
    }
    
  11. Přidejte metodu, která vyvolá CurrentParameterChanged událost.

    private void RaiseCurrentParameterChanged(IParameter prevCurrentParameter, IParameter newCurrentParameter)
    {
        EventHandler<CurrentParameterChangedEventArgs> tempHandler = this.CurrentParameterChanged;
        if (tempHandler != null)
        {
            tempHandler(this, new CurrentParameterChangedEventArgs(prevCurrentParameter, newCurrentParameter));
        }
    }
    
  12. Přidejte metodu, která vypočítá aktuální parametr porovnáním počtu čárek v ApplicableToSpan podpisu s počtem čárek v podpisu.

    internal void ComputeCurrentParameter()
    {
        if (Parameters.Count == 0)
        {
            this.CurrentParameter = null;
            return;
        }
    
        //the number of commas in the string is the index of the current parameter
        string sigText = ApplicableToSpan.GetText(m_subjectBuffer.CurrentSnapshot);
    
        int currentIndex = 0;
        int commaCount = 0;
        while (currentIndex < sigText.Length)
        {
            int commaIndex = sigText.IndexOf(',', currentIndex);
            if (commaIndex == -1)
            {
                break;
            }
            commaCount++;
            currentIndex = commaIndex + 1;
        }
    
        if (commaCount < Parameters.Count)
        {
            this.CurrentParameter = Parameters[commaCount];
        }
        else
        {
            //too many commas, so use the last parameter as the current one.
            this.CurrentParameter = Parameters[Parameters.Count - 1];
        }
    }
    
  13. Přidejte obslužnou rutinu Changed události pro událost, která volá metodu ComputeCurrentParameter() .

    internal void OnSubjectBufferChanged(object sender, TextContentChangedEventArgs e)
    {
        this.ComputeCurrentParameter();
    }
    
  14. Implementujte ApplicableToSpan vlastnost. Tato vlastnost obsahuje ITrackingSpan rozsah textu ve vyrovnávací paměti, na který se podpis vztahuje.

    public ITrackingSpan ApplicableToSpan
    {
        get { return (m_applicableToSpan); }
        internal set { m_applicableToSpan = value; }
    }
    
  15. Implementujte další parametry.

    public string Content
    {
        get { return (m_content); }
        internal set { m_content = value; }
    }
    
    public string Documentation
    {
        get { return (m_documentation); }
        internal set { m_documentation = value; }
    }
    
    public ReadOnlyCollection<IParameter> Parameters
    {
        get { return (m_parameters); }
        internal set { m_parameters = value; }
    }
    
    public string PrettyPrintedContent
    {
        get { return (m_printContent); }
        internal set { m_printContent = value; }
    }
    

Implementace zdroje nápovědy podpisu

Zdroj nápovědy k podpisu je sada podpisů, pro které zadáte informace.

Implementace zdroje nápovědy podpisu

  1. Přidejte třídu s názvem TestSignatureHelpSource , která implementuje ISignatureHelpSource.

    internal class TestSignatureHelpSource : ISignatureHelpSource
    
  2. Přidejte odkaz na textovou vyrovnávací paměť.

    private ITextBuffer m_textBuffer;
    
  3. Přidejte konstruktor, který nastaví vyrovnávací paměť textu a zprostředkovatele zdroje nápovědy podpisu.

    public TestSignatureHelpSource(ITextBuffer textBuffer)
    {
        m_textBuffer = textBuffer;
    }
    
  4. Implementujte metodu AugmentSignatureHelpSession . V tomto příkladu jsou podpisy pevně zakódované, ale v úplné implementaci získáte tyto informace z dokumentace jazyka.

    public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList<ISignature> signatures)
    {
        ITextSnapshot snapshot = m_textBuffer.CurrentSnapshot;
        int position = session.GetTriggerPoint(m_textBuffer).GetPosition(snapshot);
    
        ITrackingSpan applicableToSpan = m_textBuffer.CurrentSnapshot.CreateTrackingSpan(
         new Span(position, 0), SpanTrackingMode.EdgeInclusive, 0);
    
        signatures.Add(CreateSignature(m_textBuffer, "add(int firstInt, int secondInt)", "Documentation for adding integers.", applicableToSpan));
        signatures.Add(CreateSignature(m_textBuffer, "add(double firstDouble, double secondDouble)", "Documentation for adding doubles.", applicableToSpan));
    
    }
    
  5. Pomocná metoda CreateSignature() je k dispozici pouze pro ilustraci.

    private TestSignature CreateSignature(ITextBuffer textBuffer, string methodSig, string methodDoc, ITrackingSpan span)
    {
        TestSignature sig = new TestSignature(textBuffer, methodSig, methodDoc, null);
        textBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(sig.OnSubjectBufferChanged);
    
        //find the parameters in the method signature (expect methodname(one, two)
        string[] pars = methodSig.Split(new char[] { '(', ',', ')' });
        List<IParameter> paramList = new List<IParameter>();
    
        int locusSearchStart = 0;
        for (int i = 1; i < pars.Length; i++)
        {
            string param = pars[i].Trim();
    
            if (string.IsNullOrEmpty(param))
                continue;
    
            //find where this parameter is located in the method signature
            int locusStart = methodSig.IndexOf(param, locusSearchStart);
            if (locusStart >= 0)
            {
                Span locus = new Span(locusStart, param.Length);
                locusSearchStart = locusStart + param.Length;
                paramList.Add(new TestParameter("Documentation for the parameter.", locus, param, sig));
            }
        }
    
        sig.Parameters = new ReadOnlyCollection<IParameter>(paramList);
        sig.ApplicableToSpan = span;
        sig.ComputeCurrentParameter();
        return sig;
    }
    
  6. Implementujte metodu GetBestMatch . V tomto příkladu jsou jenom dva podpisy, z nichž každý má dva parametry. Proto tato metoda není nutná. V plnohodnotné implementaci, ve které je k dispozici více než jeden zdroj nápovědy podpisu, se tato metoda používá k rozhodnutí, zda zdroj nápovědy podpisu s nejvyšší prioritou může poskytnout odpovídající podpis. Pokud to nejde, metoda vrátí hodnotu null a zdroj další nejvyšší priority se zobrazí výzva k zadání shody.

    public ISignature GetBestMatch(ISignatureHelpSession session)
    {
        if (session.Signatures.Count > 0)
        {
            ITrackingSpan applicableToSpan = session.Signatures[0].ApplicableToSpan;
            string text = applicableToSpan.GetText(applicableToSpan.TextBuffer.CurrentSnapshot);
    
            if (text.Trim().Equals("add"))  //get only "add" 
                return session.Signatures[0];
        }
        return null;
    }
    
  7. Implementujte metodu Dispose() :

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

Implementace zprostředkovatele zdroje nápovědy podpisu

Poskytovatel zdroje nápovědy podpisu zodpovídá za export součásti MEF (Managed Extensibility Framework) a vytvoření instance zdroje nápovědy podpisu.

Implementace zprostředkovatele zdroje nápovědy podpisu

  1. Přidejte třídu s názvemTestSignatureHelpSourceProvider, která implementuje ISignatureHelpSourceProvider, a exportujte ji s textem NameAttributeContentTypeAttribute "text" a hodnotou OrderAttribute Before="default".

    [Export(typeof(ISignatureHelpSourceProvider))]
    [Name("Signature Help source")]
    [Order(Before = "default")]
    [ContentType("text")]
    internal class TestSignatureHelpSourceProvider : ISignatureHelpSourceProvider
    
  2. Implementujte TryCreateSignatureHelpSource vytvořením instance objektu TestSignatureHelpSource.

    public ISignatureHelpSource TryCreateSignatureHelpSource(ITextBuffer textBuffer)
    {
        return new TestSignatureHelpSource(textBuffer);
    }
    

Implementace obslužné rutiny příkazu

Nápovědu k podpisu obvykle aktivuje levá závorka (znak () a zavřený pravou závorkou )." znak. Tyto stisknutí kláves můžete zpracovat tak, že spustí IOleCommandTarget relaci nápovědy podpisu, když obdrží počáteční znak závorky před známým názvem metody a zavře relaci, když obdrží pravou závorku.

Implementace obslužné rutiny příkazu

  1. Přidejte třídu s názvem TestSignatureHelpCommand , která implementuje IOleCommandTarget.

    internal sealed class TestSignatureHelpCommandHandler : IOleCommandTarget
    
  2. Přidejte soukromá pole pro IVsTextView adaptér (která umožňuje přidat obslužnou rutinu příkazu do řetězu obslužných rutin příkazů), textové zobrazení, zprostředkovatele nápovědy podpisu a relaci, ITextStructureNavigatora a další IOleCommandTarget.

    IOleCommandTarget m_nextCommandHandler;
    ITextView m_textView;
    ISignatureHelpBroker m_broker;
    ISignatureHelpSession m_session;
    ITextStructureNavigator m_navigator;
    
  3. Přidejte konstruktor pro inicializaci těchto polí a přidejte filtr příkazů do řetězu filtrů příkazů.

    internal TestSignatureHelpCommandHandler(IVsTextView textViewAdapter, ITextView textView, ITextStructureNavigator nav, ISignatureHelpBroker broker)
    {
        this.m_textView = textView;
        this.m_broker = broker;
        this.m_navigator = nav;
    
        //add this to the filter chain
        textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler);
    }
    
  4. Implementujte metodu Exec , která aktivuje relaci nápovědy podpisu, když filtr příkazu obdrží levou závorku "(" znak za jedním ze známých názvů metod a zavře relaci, když obdrží pravou závorku ")" znak, zatímco relace je stále aktivní. V každém případě se příkaz předá.

    public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
    {
        char typedChar = char.MinValue;
    
        if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR)
        {
            typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn);
            if (typedChar.Equals('('))
            {
                //move the point back so it's in the preceding word
                SnapshotPoint point = m_textView.Caret.Position.BufferPosition - 1;
                TextExtent extent = m_navigator.GetExtentOfWord(point);
                string word = extent.Span.GetText();
                if (word.Equals("add"))
                    m_session = m_broker.TriggerSignatureHelp(m_textView);
    
            }
            else if (typedChar.Equals(')') && m_session != null)
            {
                m_session.Dismiss();
                m_session = null;
            }
        }
        return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
    }
    
  5. Implementujte metodu QueryStatus tak, aby vždy předal příkaz.

    public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
    {
        return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
    }
    

Implementace zprostředkovatele příkazů nápovědy podpisu

Příkaz Nápovědy k podpisu můžete zadat implementací IVsTextViewCreationListener instance obslužné rutiny příkazu při vytvoření textového zobrazení.

Implementace zprostředkovatele příkazů Nápovědy podpisu

  1. Přidejte třídu s názvem TestSignatureHelpController , která implementuje IVsTextViewCreationListener a exportuje ji pomocí NameAttributetřídy , ContentTypeAttributea TextViewRoleAttribute.

    [Export(typeof(IVsTextViewCreationListener))]
    [Name("Signature Help controller")]
    [TextViewRole(PredefinedTextViewRoles.Editable)]
    [ContentType("text")]
    internal class TestSignatureHelpCommandProvider : IVsTextViewCreationListener
    
  2. Naimportujte IVsEditorAdaptersFactoryService (používá se k získání objektu IVsTextViewITextView), ITextStructureNavigatorSelectorService objektu (použitému k vyhledání aktuálního slova) a ISignatureHelpBroker (k aktivaci relace nápovědy podpisu).

    [Import]
    internal IVsEditorAdaptersFactoryService AdapterService;
    
    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
    [Import]
    internal ISignatureHelpBroker SignatureHelpBroker;
    
  3. Implementujte metodu VsTextViewCreated vytvořením instance TestSignatureCommandHandler.

    public void VsTextViewCreated(IVsTextView textViewAdapter)
    {
        ITextView textView = AdapterService.GetWpfTextView(textViewAdapter);
        if (textView == null)
            return;
    
        textView.Properties.GetOrCreateSingletonProperty(
             () => new TestSignatureHelpCommandHandler(textViewAdapter,
                textView,
                NavigatorService.GetTextStructureNavigator(textView.TextBuffer),
                SignatureHelpBroker));
    }
    

Sestavení a otestování kódu

Tento kód otestujete tak, že sestavíte řešení SignatureHelpTest a spustíte ho v experimentální instanci.

Sestavení a testování řešení SignatureHelpTest

  1. Sestavte řešení.

  2. Když tento projekt spustíte v ladicím programu, spustí se druhá instance sady Visual Studio.

  3. Vytvořte textový soubor a zadejte nějaký text, který obsahuje slovo "přidat" a levou závorku.

  4. Po zadání levých závorek by se měl zobrazit popis, který zobrazí seznam dvou podpisů metody add() .