Návod: Dokončení příkazu Display
Dokončování příkazů na základě jazyka můžete implementovat definováním identifikátorů, pro které chcete dokončit, a následným spuštěním relace dokončení. Dokončování příkazů můžete definovat v kontextu služby jazyka, definovat vlastní příponu názvu souboru a typ obsahu a pak zobrazit dokončení pouze pro tento typ. Nebo můžete aktivovat dokončování pro existující typ obsahu – například "prostý text". Tento názorný postup ukazuje, jak aktivovat dokončování příkazů pro typ obsahu prostého textu, což je typ obsahu textových souborů. Typ obsahu "text" je nadřazený všem ostatním typům obsahu, včetně kódu a souborů XML.
Dokončování příkazů se obvykle aktivuje zadáním určitých znaků– například zadáním začátku identifikátoru, jako je například using. Obvykle se zavře stisknutím mezerníku, tabulátoru nebo klávesy Enter pro potvrzení výběru. Funkce IntelliSense, které se aktivují při zadávání znaku, můžete 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 dokončení, což je seznam identifikátorů, které se účastní dokončení, implementujte ICompletionSource rozhraní a zprostředkovatele zdroje dokončení ( ICompletionSourceProvider rozhraní). Zprostředkovatelé jsou součásti mef (Managed Extensibility Framework). Zodpovídají za export tříd zdrojového a kontroleru a import služeb a zprostředkovatelů, ITextStructureNavigatorSelectorServicenapříklad za navigaci v textové vyrovnávací paměti a za ICompletionBrokeraktivaci relace dokončení.
Tento návod ukazuje, jak implementovat dokončování příkazů pro pevně zakódovanou sadu identifikátorů. V úplných implementacích zodpovídá za poskytování daného obsahu služba jazyka a dokumentace k jazyku.
Vytvoření projektu MEF
Vytvoření projektu MEF
Vytvořte projekt VSIX jazyka C#. (V Dialogové okno Nový projekt , vyberte Visual C# / Rozšiřitelnost a pak projekt VSIX.) Pojmenujte řešení
CompletionTest
.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.
Odstraňte existující soubory třídy.
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.15.0
Microsoft.VisualStudio.Shell.Immutable.10.0
Microsoft.VisualStudio.TextManager.Interop
Implementace zdroje dokončení
Zdroj dokončení zodpovídá za shromažďování sady identifikátorů a přidání obsahu do okna dokončení, když uživatel zadá trigger dokončení, například první písmena identifikátoru. V tomto příkladu jsou identifikátory a jejich popisy pevně zakódovány v AugmentCompletionSession metodě. Ve většině reálných použití byste pomocí analyzátoru jazyka získali tokeny k naplnění seznamu dokončení.
Implementace zdroje dokončení
Přidejte soubor třídy a pojmenujte ho
TestCompletionSource
.Přidejte tyto importy:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.Composition; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities;
Upravte deklaraci třídy tak
TestCompletionSource
, aby implementovali ICompletionSource:Přidejte soukromá pole pro zprostředkovatele zdroje, vyrovnávací paměť textu a seznam Completion objektů (které odpovídají identifikátorům, které se budou účastnit relace dokončení):
Přidejte konstruktor, který nastaví zprostředkovatele zdroje a vyrovnávací paměť. Třída
TestCompletionSourceProvider
je definována v pozdějších krocích:Implementujte metodu AugmentCompletionSession přidáním sady dokončení, která obsahuje dokončení, které chcete poskytnout v kontextu. Každá sada dokončení obsahuje sadu Completion dokončení a odpovídá tabulátoru okna dokončení. (V projektech jazyka Visual Basic jsou karty okna dokončení pojmenované. Společné a všechny.) Metoda
FindTokenSpanAtPosition
je definována v dalším kroku.void ICompletionSource.AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets) { List<string> strList = new List<string>(); strList.Add("addition"); strList.Add("adaptation"); strList.Add("subtraction"); strList.Add("summation"); m_compList = new List<Completion>(); foreach (string str in strList) m_compList.Add(new Completion(str, str, str, null, null)); completionSets.Add(new CompletionSet( "Tokens", //the non-localized title of the tab "Tokens", //the display title of the tab FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer), session), m_compList, null)); }
Následující metoda slouží k vyhledání aktuálního slova z pozice kurzoru:
private ITrackingSpan FindTokenSpanAtPosition(ITrackingPoint point, ICompletionSession session) { SnapshotPoint currentPoint = (session.TextView.Caret.Position.BufferPosition) - 1; ITextStructureNavigator navigator = m_sourceProvider.NavigatorService.GetTextStructureNavigator(m_textBuffer); TextExtent extent = navigator.GetExtentOfWord(currentPoint); return currentPoint.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive); }
Implementujte metodu
Dispose()
:
Implementace zprostředkovatele zdroje dokončení
Zprostředkovatel zdroje dokončení je komponenta MEF, která vytvoří instanci zdroje dokončení.
Implementace zprostředkovatele zdroje dokončení
Přidejte třídu s názvem
TestCompletionSourceProvider
, která implementuje ICompletionSourceProvider. Exportovat tuto třídu s " ContentTypeAttribute prostým textem" a NameAttribute "dokončení testu".Naimportujte výraz ITextStructureNavigatorSelectorService, který najde aktuální slovo ve zdroji dokončení.
Implementujte metodu TryCreateCompletionSource pro vytvoření instance zdroje dokončení.
Implementace zprostředkovatele obslužné rutiny příkazu dokončení
Zprostředkovatel obslužné rutiny příkazu dokončení je odvozen z objektu IVsTextViewCreationListener, který naslouchá události vytvoření textového zobrazení a převede zobrazení z objektu IVsTextView–, který umožňuje přidání příkazu do řetězce příkazů prostředí sady Visual Studio – do objektu ITextView. Vzhledem k tomu, že tato třída je export MEF, můžete ji použít také k importu služeb, které vyžaduje samotná obslužná rutina příkazu.
Implementace zprostředkovatele obslužné rutiny příkazu dokončení
Přidejte soubor s názvem
TestCompletionCommandHandler
.Přidejte tyto direktivy using:
using System; using System.ComponentModel.Composition; using System.Runtime.InteropServices; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Utilities;
Přidejte třídu s názvem
TestCompletionHandlerProvider
, která implementuje IVsTextViewCreationListener. Export této třídy s "obslužnou rutinou NameAttribute dokončení tokenu", ContentTypeAttribute "plaintext" a a TextViewRoleAttribute z Editable.Naimportujte IVsEditorAdaptersFactoryService, který umožňuje převod z a IVsTextView ITextView, a ICompletionBroker, a, SVsServiceProvider který umožňuje přístup ke standardním službám sady Visual Studio.
Implementujte metodu VsTextViewCreated pro vytvoření instance obslužné rutiny příkazu.
public void VsTextViewCreated(IVsTextView textViewAdapter) { ITextView textView = AdapterService.GetWpfTextView(textViewAdapter); if (textView == null) return; Func<TestCompletionCommandHandler> createCommandHandler = delegate() { return new TestCompletionCommandHandler(textViewAdapter, textView, this); }; textView.Properties.GetOrCreateSingletonProperty(createCommandHandler); }
Implementace obslužné rutiny příkazu dokončení
Vzhledem k tomu, že dokončování příkazů je aktivováno pomocí klávesových úhozí, musíte implementovat IOleCommandTarget rozhraní pro příjem a zpracování klávesových úhozí, které trigger, potvrzení a zavře relace dokončení.
Implementace obslužné rutiny příkazu dokončení
Přidejte třídu s názvem
TestCompletionCommandHandler
, která implementuje IOleCommandTarget:Přidejte soukromá pole pro další obslužnou rutinu příkazu (do které předáte příkaz), textové zobrazení, zprostředkovatele obslužné rutiny příkazu (který umožňuje přístup k různým službám) a relaci dokončení:
Přidejte konstruktor, který nastaví textové zobrazení a pole zprostředkovatele a přidá příkaz do řetězce příkazů:
Implementujte metodu QueryStatus předáním příkazu společně:
Implementujte metodu Exec . Když tato metoda obdrží stisknutí klávesy, musí provést jednu z těchto věcí:
Povolte zápis znaku do vyrovnávací paměti a pak aktivujte nebo filtrujte dokončení. (Tisk znaků provede.)
Potvrďte dokončení, ale nepovolujte zápis znaku do vyrovnávací paměti. (Prázdné znaky, Tab a Enter to udělat při zobrazení relace dokončení.)
Povolte předání příkazu další obslužné rutině. (Všechny ostatní příkazy.)
Vzhledem k tomu, že tato metoda může zobrazit uživatelské rozhraní, voláním IsInAutomationFunction se ujistěte, že není volána v kontextu automatizace:
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); } //make a copy of this so we can look at it after forwarding some commands uint commandID = nCmdID; char typedChar = char.MinValue; //make sure the input is a char before getting it if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } //check for a commit character if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB || (char.IsWhiteSpace(typedChar) || char.IsPunctuation(typedChar))) { //check for a selection if (m_session != null && !m_session.IsDismissed) { //if the selection is fully selected, commit the current session if (m_session.SelectedCompletionSet.SelectionStatus.IsSelected) { m_session.Commit(); //also, don't add the character to the buffer return VSConstants.S_OK; } else { //if there is no selection, dismiss the session m_session.Dismiss(); } } } //pass along the command so the char is added to the buffer int retVal = m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); bool handled = false; if (!typedChar.Equals(char.MinValue) && char.IsLetterOrDigit(typedChar)) { if (m_session == null || m_session.IsDismissed) // If there is no active session, bring up completion { this.TriggerCompletion(); m_session.Filter(); } else //the completion session is already active, so just filter { m_session.Filter(); } handled = true; } else if (commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE //redo the filter if there is a deletion || commandID == (uint)VSConstants.VSStd2KCmdID.DELETE) { if (m_session != null && !m_session.IsDismissed) m_session.Filter(); handled = true; } if (handled) return VSConstants.S_OK; return retVal; }
Tento kód je privátní metoda, která aktivuje relaci dokončení:
private bool TriggerCompletion() { //the caret must be in a non-projection location SnapshotPoint? caretPoint = m_textView.Caret.Position.Point.GetPoint( textBuffer => (!textBuffer.ContentType.IsOfType("projection")), PositionAffinity.Predecessor); if (!caretPoint.HasValue) { return false; } m_session = m_provider.CompletionBroker.CreateCompletionSession (m_textView, caretPoint.Value.Snapshot.CreateTrackingPoint(caretPoint.Value.Position, PointTrackingMode.Positive), true); //subscribe to the Dismissed event on the session m_session.Dismissed += this.OnSessionDismissed; m_session.Start(); return true; }
Dalším příkladem je soukromá metoda, která se odhlásí od odběru Dismissed události:
Sestavení a otestování kódu
Tento kód otestujete tak, že sestavíte řešení CompletionTest a spustíte ho v experimentální instanci.
Sestavení a otestování řešení CompletionTest
Sestavte řešení.
Když tento projekt spustíte v ladicím programu, spustí se druhá instance sady Visual Studio.
Vytvořte textový soubor a zadejte nějaký text, který obsahuje slovo "přidat".
Při psaní prvního "a" a "d" by se měl zobrazit seznam, který obsahuje "sčítání" a "adaptaci". Všimněte si, že je vybráno přidání. Když zadáte další "d", seznam by měl obsahovat pouze "sčítání", které je nyní vybráno. Přidání můžete potvrdit stisknutím mezerníku, tabulátoru nebo klávesy Enter nebo zavřením seznamu zadáním klávesy Esc nebo jiné klávesy.