Exemplarische Vorgehensweise: Implementieren von Codeausschnitten
Sie können Codeausschnitte erstellen und diese in einer Editorerweiterung einschließen, damit Benutzer die Erweiterung diese ihren eigenen Code hinzufügen können.
Ein Codeausschnitt ist ein Fragment des Codes oder anderer Textpuffer, die in einer einzigen Datei integriert werden kann. Um alle Ausschnitte anzuzeigen, die für bestimmte Programmiersprachen im Menü Extras registriert wurden, klicken Sie auf Codeausschnitt-Manager. Um einen Ausschnitt einfügen in einer Datei mit der rechten Maustaste auf Suchen, in dem Sie den Ausschnitt soll, oder Ausschnitt einfügen auf Umschließen mit klicken, um den Ausschnitt, und doppelklicken Sie auf den gewünschten ihn dann. Drücken Sie TAB oder UMSCHALT+TAB, um die relevanten Teile des Ausschnitts zu ändern, und drücken Sie dann die EINGABETASTE oder ESC, um es zu akzeptieren. Weitere Informationen finden Sie unter Codeausschnitte.
Ein Codeausschnitt wird in einer XML-Datei enthalten, die die .snippet verfügt. Ein Ausschnitt kann Felder enthalten, die markiert werden, nachdem der Ausschnitt eingefügt wurde, sodass der Benutzer suchen und sie ändern kann. Eine Ausschnittdatei stellt außerdem die Informationen für Codeausschnitt-Manager bereit, damit dieser den Namen des Ausschnitts in der richtigen Kategorie anzeigen kann. Weitere Informationen zum Ausschnittschema finden Sie unter Schemareferenz für Codeausschnitte.
In dieser exemplarischen Vorgehensweise wird erläutert, wie die folgenden Aufgaben ausgeführt werden:
Erstellen und Registrieren von Codeausschnitten für eine bestimmte Sprache.
Fügen Sie den Befehl Ausschnitt einfügen einem Kontextmenü hinzu.
Implementieren Sie Ausschnittserweiterung.
Diese exemplarische Vorgehensweise basiert auf Exemplarische Vorgehensweise: Anweisungsvervollständigung anzeigen.
Vorbereitungsmaßnahmen
Zum Abschließen dieser exemplarischen Vorgehensweise müssen Sie das Visual Studio 2010 SDK installieren. Informationen über das Herunterladen und das Visual Studio-SDK finden Sie Visual Studio Extensibility Developer Center auf der MSDN-Website.
Codeausschnitte Erstellen und Registrieren
In der Regel werden Codeausschnitte mit einem registrierten Sprachdienst zugeordnet. Sie müssen jedoch LanguageService nicht implementieren, um Codeausschnitte zu registrieren. Stattdessen, geben Sie einfach eine GUID in der Ausschnitts indexdatei an, und verwenden Sie dann das gleiche GUID in ProvideLanguageCodeExpansionAttribute, die Sie dem Projekt hinzufügen.
Die folgenden Schritte zeigen, wie Sie Codeausschnitte erstellen und sie mit einem bestimmten Satz GUID zugeordnet wird.
So erstellen Sie Codeausschnitte
Erstellen Sie die folgende Verzeichnisstruktur:
TestSnippets %InstallDir% \ \ Snippets \ 1033 \
Dabei %InstallDir% der Ordner Visual Studio-Installations ist. (Obwohl dieser Pfad in der Regel verwendet wird, um Codeausschnitte zu installieren, können Sie einen beliebigen Pfad angeben.)
In \ 1033 \ Ordner erstellen Sie eine XML-Datei erstellt und nennen Sie sie SnippetIndex .xml. (Obwohl dieser Name in der Regel für eine indexdatei Ausschnitts verwendet wird, können Sie jeden beliebigen Namen angeben, sofern er eine .xml-Dateinamenerweiterung ist). Fügen Sie den folgenden Text, und löschen Sie dann den Platzhalter GUID und fügen Sie eine eigene hinzu.
<?xml version="1.0" encoding="utf-8" ?> <SnippetCollection> <Language Lang="TestSnippets" Guid="{00000000-0000-0000-0000-000000000000}"> <SnippetDir> <OnOff>On</OnOff> <Installed>true</Installed> <Locale>1033</Locale> <DirPath>%InstallRoot%\TestSnippets\Snippets\%LCID%\</DirPath> <LocalizedName>Snippets</LocalizedName> </SnippetDir> </Language> </SnippetCollection>
Erstellen Sie eine Datei im Ordner Ausschnitts mit dem Namen Test .snippet, und fügen Sie dann den folgenden Text hinzu:
<?xml version="1.0" encoding="utf-8" ?> <CodeSnippets xmlns="https://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>Test replacement fields</Title> <Shortcut>test</Shortcut> <Description>Code snippet for testing replacement fields</Description> <Author>MSIT</Author> <SnippetTypes> <SnippetType>Expansion</SnippetType> </SnippetTypes> </Header> <Snippet> <Declarations> <Literal> <ID>param1</ID> <ToolTip>First field</ToolTip> <Default>first</Default> </Literal> <Literal> <ID>param2</ID> <ToolTip>Second field</ToolTip> <Default>second</Default> </Literal> </Declarations> <References> <Reference> <Assembly>System.Windows.Forms.dll</Assembly> </Reference> </References> <Code Language="TestSnippets"> <![CDATA[MessageBox.Show("$param1$"); MessageBox.Show("$param2$");]]> </Code> </Snippet> </CodeSnippet> </CodeSnippets>
Die folgenden Schritte zeigen, wie die Codeausschnitte registriert.
So registrieren GUID für eine bestimmte Codeausschnitte
Öffnen Sie das CompletionTest-Projekt. Informationen zum Ändern dieses Projekt finden Sie unter Exemplarische Vorgehensweise: Anweisungsvervollständigung anzeigen erstellt.
Fügen Sie im Projekt Verweise auf die folgenden Assemblys hinzu:
Microsoft.VisualStudio.TextManager.Interop
Microsoft.VisualStudio.TextManager.Interop.8.0
microsoft.msxml
Um die Codeausschnitte zu registrieren, muss das Projekt eine PKGDEF-Datei ausgeben. Weitere Informationen finden Sie unter Registering VSPackages.
Im Projekt öffnen Sie die Datei source.extension.vsixmanifest.
Im Inhalt-Abschnitt klicken Sie auf Inhalt hinzufügen, wählen Sie den GEGEN Paket Inhaltstyp aus, wählen Sie die Option ProjektTestCompletion aus, und wählen Sie in der Dropdownliste aus.
Die folgende Zeile sollte in der Datei angezeigt:
TestCompletion;PkgdefProjectOutputGroup|
Speichern Sie die Datei " source.extension.vsixmanifest ", und schließen Sie sie.
Fügen Sie dem Projekt eine statische SnippetUtilities-Klasse hinzu.
Module SnippetUtilities
static class SnippetUtilities
In der SnippetUtilities-Klasse definieren Sie ein GUID und geben Sie es mit der dieser Wert in der SnippetsIndex.xml-Datei übergeben wird.
Friend Const LanguageServiceGuidStr As String = "00000000-0000-0000-0000-00000000"
internal const string LanguageServiceGuidStr = "00000000-0000-0000-0000-00000000";
Fügen Sie ProvideLanguageCodeExpansionAttribute der TestCompletionHandler-Klasse hinzu. Dieses Attribut kann auf jede öffentliche oder internen (nicht statisch) Klasse im Projekt hinzugefügt werden. (Sie müssen eine using-Anweisung für den Microsoft.VisualStudio.Shell-Namespace hinzufügen.)
<ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", 0, "TestSnippets", "%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", SearchPaths:="%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs:="%InstallRoot%\TestSnippets\Snippets\%LCID%\")> Friend Class TestCompletionCommandHandler Implements IOleCommandTarget
[ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", //the language name 0, //the resource id of the language "TestSnippets", //the language ID used in the .snippet files @"%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", //the path of the index file SearchPaths = @"%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs = @"%InstallRoot%\TestSnippets\Snippets\%LCID%\")] internal class TestCompletionCommandHandler : IOleCommandTarget
Erstellen Sie das Projekt, und führen Sie es aus. Klicken Sie in der experimentellen Instanz von Visual Studio, das gestartet wird, wenn das Projekt ausgeführt wird, sollte der Block, den Sie gerade registriert haben, in Codeausschnitt-Manager unter der TestSnippets Sprache angezeigt werden.
Der EINFG-Ausschnitts-Befehl dem Kontextmenü hinzu
Der Befehl wird nicht Ausschnitt einfügen im Kontextmenü für eine Textdatei enthalten. Daher müssen Sie den Befehl erneut aktivieren.
Um den Befehl EINFG-Ausschnitts dem Kontextmenü hinzu
Öffnen Sie die Klassendatei TestCompletionCommandHandler.
Da diese Klasse IOleCommandTarget implementiert, können Sie den Befehl Ausschnitt einfügen in der QueryStatus-Methode ermöglichen. Bevor Sie den Befehl erneut aktivieren, überprüfen Sie, ob diese Methode nicht innerhalb einer Automatisierungsfunktion aufgerufen wird, wenn auf den Befehl Ausschnitt einfügen geklickt wird, Ausschnitts-Auswahl der Benutzeroberfläche angezeigt wird.
Public Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal cCmds As UInteger, ByVal prgCmds As OLECMD(), ByVal pCmdText As IntPtr) As Integer Implements IOleCommandTarget.QueryStatus If Not VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider) Then If pguidCmdGroup = VSConstants.VSStd2K AndAlso cCmds > 0 Then ' make the Insert Snippet command appear on the context menu If CUInt(prgCmds(0).cmdID) = CUInt(VSConstants.VSStd2KCmdID.INSERTSNIPPET) Then prgCmds(0).cmdf = CInt(Constants.MSOCMDF_ENABLED) Or CInt(Constants.MSOCMDF_SUPPORTED) Return VSConstants.S_OK End If End If End If Return m_nextCommandHandler.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText) End Function
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) { if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { if (pguidCmdGroup == VSConstants.VSStd2K && cCmds > 0) { // make the Insert Snippet command appear on the context menu if ((uint)prgCmds[0].cmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET) { prgCmds[0].cmdf = (int)Constants.MSOCMDF_ENABLED | (int)Constants.MSOCMDF_SUPPORTED; return VSConstants.S_OK; } } } return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); }
Erstellen Sie das Projekt, und führen Sie es aus. Klicken Sie in der experimentellen Instanz öffnen Sie eine Datei mit der .zzz-Dateinamenerweiterung und dann mit der rechten Maustaste auf eine beliebige Stelle in ihr verfügt. Der Befehl sollte Ausschnitt einfügen im Kontextmenü angezeigt werden.
Ausschnitts-Erweiterung in der Ausschnitts-Auswahl Benutzeroberfläche implementieren
In diesem Abschnitt wird erläutert, wie Codeausschnittserweiterung implementiert, damit die Ausschnitts-Auswahl Benutzeroberfläche angezeigt wird, wenn Sie im Kontextmenü auf Ausschnitt einfügen geklickt wird. Ein Codeausschnitt wird auch wenn Benutzer die Verknüpfung Codeausschnitt erweitert und dann die TAB- drückt.
Um die Ausschnitts-Auswahl Benutzeroberfläche anzuzeigen und Navigation und Ausschnitts akzeptanz nach der Einfügung zu aktivieren, verwenden Sie die Exec-Methode. Die Einfügung selbst wird durch die OnItemChosen-Methode behandelt.
Die Implementierung der Codeausschnitt verwendeten Erweiterung Legacy Microsoft.VisualStudio.TextManager.Interop-Schnittstellen. Wenn Sie den aktuellen Editor Klassen zum Übersetzen von Code Legacy, beachten Sie, dass die Schnittstellen Legacy eine Kombination von Zeilennummern und Spaltennummern verwendet werden, um Positionen in einem Textpuffer anzugeben, aber die aktuellen Klassen verwenden einen Index. Wenn also ein Puffer drei Zeilen verfügt, von denen jede zehn Zeichen Plus aufweist (einen Zeilenumbruch, der als 1 Zeichen ist), wird das vierte Zeichen in der dritten Zeile an Position 27 in der aktuellen Implementierung ist jedoch in Zeile 2, Position 3 in der alten Implementierung.
So implementieren Sie die Erweiterung Ausschnitts
Die Datei, die die TestCompletionCommandHandler-Klasse enthält, fügen Sie die folgenden Anweisungen hinzu. using
Imports Microsoft.VisualStudio.Text.Operations Imports MSXML
using Microsoft.VisualStudio.Text.Operations; using MSXML; using System.ComponentModel.Composition;
Lassen Sie die TestCompletionCommandHandler-Klasse die IVsExpansionClient-Schnittstelle implementieren.
<ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", 0, "TestSnippets", "%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", SearchPaths:="%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs:="%InstallRoot%\TestSnippets\Snippets\%LCID%\")> Friend Class TestCompletionCommandHandler Implements IOleCommandTarget Implements IVsExpansionClient
internal class TestCompletionCommandHandler : IOleCommandTarget, IVsExpansionClient
In der TestCompletionCommandHandlerProvider-Klasse importieren Sie ITextStructureNavigatorSelectorService.
<Import()> Friend Property NavigatorService As ITextStructureNavigatorSelectorService
[Import] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
Fügen Sie einige private Felder für die IVsTextView und Schnittstellen für Code hinzu.
Dim m_vsTextView As IVsTextView Dim m_exManager As IVsExpansionManager Dim m_exSession As IVsExpansionSession
IVsTextView m_vsTextView; IVsExpansionManager m_exManager; IVsExpansionSession m_exSession;
Im Konstruktor der TestCompletionCommandHandler-Klasse, legen Sie die folgenden Felder fest.
Friend Sub New(ByVal textViewAdapter As IVsTextView, ByVal textView As ITextView, ByVal provider As TestCompletionHandlerProvider) Me.m_textView = textView Me.m_provider = provider Me.m_vsTextView = textViewAdapter Dim textManager As IVsTextManager2 = DirectCast(m_provider.ServiceProvider.GetService(GetType(SVsTextManager)), IVsTextManager2) textManager.GetExpansionManager(m_exManager) m_exSession = Nothing 'add the command to the command chain textViewAdapter.AddCommandFilter(Me, m_nextCommandHandler) End Sub
internal TestCompletionCommandHandler(IVsTextView textViewAdapter, ITextView textView, TestCompletionHandlerProvider provider) { this.m_textView = textView; m_vsTextView = textViewAdapter; m_provider = provider; //get the text manager from the service provider IVsTextManager2 textManager = (IVsTextManager2)m_provider.ServiceProvider.GetService(typeof(SVsTextManager)); textManager.GetExpansionManager(out m_exManager); m_exSession = null; //add the command to the command chain textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler); }
Um die Anzeige Ausschnitts-Auswahl Ausschnitt einfügen wenn der Benutzer auf den Befehl klickt, fügen Sie folgenden Code in die Exec-Methode hinzu. (Diese Erläuterung verständlicher zu gestalten, wird der Code des Leitprogramms (), der für die Anweisungsvervollständigung verwendet wird, nicht angezeigt. Stattdessen werden Codeblöcke in die vorhandene Methode) hinzugefügt. Fügen Sie den folgenden Codeblock nach dem Code hinzu, der für ein Zeichen überprüft.
'code previously written for Exec If pguidCmdGroup = VSConstants.VSStd2K AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TYPECHAR) Then typedChar = ChrW(CUShort(Marshal.GetObjectForNativeVariant(pvaIn))) End If 'the snippet picker code starts here If nCmdID = CUInt(VSConstants.VSStd2KCmdID.INSERTSNIPPET) Then Dim textManager As IVsTextManager2 = DirectCast(m_provider.ServiceProvider.GetService(GetType(SVsTextManager)), IVsTextManager2) textManager.GetExpansionManager(m_exManager) m_exManager.InvokeInsertionUI( m_vsTextView, Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), Nothing, 0, 0, Nothing, 0, 0, "TestSnippets", String.Empty) Return VSConstants.S_OK End If
//code previously written for Exec if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } //the snippet picker code starts here if (nCmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET) { IVsTextManager2 textManager = (IVsTextManager2)m_provider.ServiceProvider.GetService(typeof(SVsTextManager)); textManager.GetExpansionManager(out m_exManager); m_exManager.InvokeInsertionUI( m_vsTextView, this, //the expansion client new Guid(SnippetUtilities.LanguageServiceGuidStr), null, //use all snippet types 0, //number of types (0 for all) 0, //ignored if iCountTypes == 0 null, //use all snippet kinds 0, //use all snippet kinds 0, //ignored if iCountTypes == 0 "TestSnippets", //the text to show in the prompt string.Empty); //only the ENTER key causes insert return VSConstants.S_OK; }
Wenn ein Ausschnitt Felder verfügt, zu der navigiert werden können, wird das Add-In eine geöffnet gehalten, bis die Erweiterung explizit angenommen wurde. Wenn der Ausschnitt keine Felder verfügt, wird die Sitzung geschlossen und wird als null von der InvokeInsertionUI-Methode zurückgegeben. In der Exec-Methode nachdem der Code der Ausschnitts-Auswahl Benutzeroberfläche, den Sie im vorherigen Schritt hinzugefügt haben, fügen Sie den folgenden Code hinzu (Navigation ausschnitts Handle beim Einfügen von TAB oder UMSCHALT+TAB nach Ausschnitts klickt).
'the expansion insertion is handled in OnItemChosen 'if the expansion session is still active, handle tab/backtab/return/cancel If m_exSession IsNot Nothing Then If nCmdID = CUInt(VSConstants.VSStd2KCmdID.BACKTAB) Then m_exSession.GoToPreviousExpansionField() Return VSConstants.S_OK ElseIf nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) Then m_exSession.GoToNextExpansionField(0) 'false to support cycling through all the fields Return VSConstants.S_OK ElseIf nCmdID = CUInt(VSConstants.VSStd2KCmdID.[RETURN]) OrElse nCmdID = CUInt(VSConstants.VSStd2KCmdID.CANCEL) Then If m_exSession.EndCurrentExpansion(0) = VSConstants.S_OK Then m_exSession = Nothing Return VSConstants.S_OK End If End If End If
//the expansion insertion is handled in OnItemChosen //if the expansion session is still active, handle tab/backtab/return/cancel if (m_exSession != null) { if (nCmdID == (uint)VSConstants.VSStd2KCmdID.BACKTAB) { m_exSession.GoToPreviousExpansionField(); return VSConstants.S_OK; } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { m_exSession.GoToNextExpansionField(0); //false to support cycling through all the fields return VSConstants.S_OK; } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.CANCEL) { if (m_exSession.EndCurrentExpansion(0) == VSConstants.S_OK) { m_exSession = null; return VSConstants.S_OK; } } }
Um den Codeausschnitt eingefügt werden soll, wenn der Benutzer drückt die entsprechende Verknüpfung und dann die TAB- Code hinzufügen, der Exec-Methode. Der private Methode, die den Ausschnitt einfügt, wird in einem späteren Schritt gezeigt. Fügen Sie den folgenden Code nach dem Code für die Navigation hinzu, den Sie im vorherigen Schritt hinzugefügt haben.
'neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut If m_session Is Nothing AndAlso m_exSession Is Nothing AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) Then 'get the word that was just added Dim pos As CaretPosition = m_textView.Caret.Position Dim word As TextExtent = m_provider.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1) Dim textString As String = word.Span.GetText() 'if it is a code snippet, insert it, otherwise carry on If InsertAnyExpansion(textString, Nothing, Nothing) Then Return VSConstants.S_OK End If End If
//neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut if (m_session == null && m_exSession == null && nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { //get the word that was just added CaretPosition pos = m_textView.Caret.Position; TextExtent word = m_provider.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1); //use the position 1 space back string textString = word.Span.GetText(); //the word that was just added //if it is a code snippet, insert it, otherwise carry on if (InsertAnyExpansion(textString, null, null)) return VSConstants.S_OK; }
Implementieren Sie die Methoden der IVsExpansionClient-Schnittstelle. In dieser Implementierung sind die einzigen relevanten Methoden und EndExpansionOnItemChosen. Die anderen Methoden sollten S_OK nur zurückgeben.
Public Function EndExpansion() As Integer Implements IVsExpansionClient.EndExpansion m_exSession = Nothing Return VSConstants.S_OK End Function Public Function FormatSpan(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan()) As Integer Implements IVsExpansionClient.FormatSpan Return VSConstants.S_OK End Function Public Function GetExpansionFunction(ByVal xmlFunctionNode As IXMLDOMNode, ByVal bstrFieldName As String, ByRef pFunc As IVsExpansionFunction) As Integer Implements IVsExpansionClient.GetExpansionFunction pFunc = Nothing Return VSConstants.S_OK End Function Public Function IsValidKind(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan(), ByVal bstrKind As String, ByRef pfIsValidKind As Integer) As Integer Implements IVsExpansionClient.IsValidKind pfIsValidKind = 1 Return VSConstants.S_OK End Function Public Function IsValidType(ByVal pBuffer As IVsTextLines, ByVal ts() As TextSpan, ByVal rgTypes() As String, ByVal iCountTypes As Integer, ByRef pfIsValidType As Integer) As Integer Implements IVsExpansionClient.IsValidType pfIsValidType = 1 Return VSConstants.S_OK End Function Public Function OnAfterInsertion(ByVal pSession As IVsExpansionSession) As Integer Implements IVsExpansionClient.OnAfterInsertion Return VSConstants.S_OK End Function Public Function OnBeforeInsertion(ByVal pSession As IVsExpansionSession) As Integer Implements IVsExpansionClient.OnBeforeInsertion Return VSConstants.S_OK End Function Public Function PositionCaretForEditing(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan()) As Integer Implements IVsExpansionClient.PositionCaretForEditing Return VSConstants.S_OK End Function
public int EndExpansion() { m_exSession = null; return VSConstants.S_OK; } public int FormatSpan(IVsTextLines pBuffer, TextSpan[] ts) { return VSConstants.S_OK; } public int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldName, out IVsExpansionFunction pFunc) { pFunc = null; return VSConstants.S_OK; } public int IsValidKind(IVsTextLines pBuffer, TextSpan[] ts, string bstrKind, out int pfIsValidKind) { pfIsValidKind = 1; return VSConstants.S_OK; } public int IsValidType(IVsTextLines pBuffer, TextSpan[] ts, string[] rgTypes, int iCountTypes, out int pfIsValidType) { pfIsValidType = 1; return VSConstants.S_OK; } public int OnAfterInsertion(IVsExpansionSession pSession) { return VSConstants.S_OK; } public int OnBeforeInsertion(IVsExpansionSession pSession) { return VSConstants.S_OK; } public int PositionCaretForEditing(IVsTextLines pBuffer, TextSpan[] ts) { return VSConstants.S_OK; }
Implementieren Sie die OnItemChosen-Methode. Die Hilfsmethode, die tatsächlich die Erweiterungen einfügt, wird in einem späteren Schritt erläutert. TextSpan stellt Zeilen- und Spalteninformationen, die Sie aus IVsTextView abrufen können.
Public Function OnItemChosen(ByVal pszTitle As String, ByVal pszPath As String) As Integer Implements IVsExpansionClient.OnItemChosen InsertAnyExpansion(Nothing, pszTitle, pszPath) Return VSConstants.S_OK End Function
public int OnItemChosen(string pszTitle, string pszPath) { InsertAnyExpansion(null, pszTitle, pszPath); return VSConstants.S_OK; }
Die folgenden privaten Methode fügt einen Codeausschnitt, basiert entweder auf die Verknüpfung oder auf den Namen und Pfad. Anschließend wird die InsertNamedExpansion-Methode mit dem Ausschnitt an.
Private Function InsertAnyExpansion(ByVal shortcut As String, ByVal title As String, ByVal path As String) As Boolean Dim endColumn As Integer, startLine As Integer 'get the column number from the IVsTextView, not the ITextView m_vsTextView.GetCaretPos(startLine, endColumn) Dim addSpan As New TextSpan() addSpan.iStartIndex = endColumn addSpan.iEndIndex = endColumn addSpan.iStartLine = startLine addSpan.iEndLine = startLine 'get the expansion from the shortcut If shortcut IsNot Nothing Then 'reset the TextSpan to the width of the shortcut, because we're going to replace the shortcut with the expansion addSpan.iStartIndex = addSpan.iEndIndex - shortcut.Length m_exManager.GetExpansionByShortcut( Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), shortcut, m_vsTextView, New TextSpan() {addSpan}, 0, path, title) End If If title IsNot Nothing AndAlso path IsNot Nothing Then Dim textLines As IVsTextLines = Nothing m_vsTextView.GetBuffer(textLines) Dim bufferExpansion As IVsExpansion = DirectCast(textLines, IVsExpansion) If bufferExpansion IsNot Nothing Then Dim hr As Integer = bufferExpansion.InsertNamedExpansion( title, path, addSpan, Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), 0, m_exSession) If VSConstants.S_OK = hr Then Return True End If End If End If Return False End Function
private bool InsertAnyExpansion(string shortcut, string title, string path) { //first get the location of the caret, and set up a TextSpan int endColumn, startLine; //get the column number from the IVsTextView, not the ITextView m_vsTextView.GetCaretPos(out startLine, out endColumn); TextSpan addSpan = new TextSpan(); addSpan.iStartIndex = endColumn; addSpan.iEndIndex = endColumn; addSpan.iStartLine = startLine; addSpan.iEndLine = startLine; if (shortcut != null) //get the expansion from the shortcut { //reset the TextSpan to the width of the shortcut, //because we're going to replace the shortcut with the expansion addSpan.iStartIndex = addSpan.iEndIndex - shortcut.Length; m_exManager.GetExpansionByShortcut( this, new Guid(SnippetUtilities.LanguageServiceGuidStr), shortcut, m_vsTextView, new TextSpan[] { addSpan }, 0, out path, out title); } if (title != null && path != null) { IVsTextLines textLines; m_vsTextView.GetBuffer(out textLines); IVsExpansion bufferExpansion = (IVsExpansion)textLines; if (bufferExpansion != null) { int hr = bufferExpansion.InsertNamedExpansion( title, path, addSpan, this, new Guid(SnippetUtilities.LanguageServiceGuidStr), 0, out m_exSession); if (VSConstants.S_OK == hr) { return true; } } } return false; }
Erstellen und Teseen von Codeausschnitt-Erweiterung
Sie können testen, ob Ausschnittserweiterung im Projekt funktioniert.
So erstellen und testen Sie Codeausschnittserweiterung
Erstellen Sie die Projektmappe. Wenn Sie dieses Projekt im Debugger ausführen, wird eine zweite Instanz von Visual Studio instanziiert.
Öffnen Sie eine Textdatei, und geben Sie Text ein.
Klicken Sie mit der rechten Maustaste irgendwo im Text, und klicken Sie dann auf Ausschnitt einfügen.
Die Ausschnitts-Auswahl Benutzeroberfläche angezeigt werden soll und die Zeichenfolge "Test" Ersetzung Feldern anzeigen. Doppelklicken Sie auf diese Zeichenfolge.
Der folgende Ausschnitt eingefügt werden soll.
MessageBox.Show("first"); MessageBox.Show("second");
Führen Sie nicht die EINGABETASTE oder drücken die ESC-TASTE.
Drücken Sie TAB, UMSCHALT+TAB zum Wechseln zwischen "zuerst" und "second".
Übernehmen Sie die Einfügung, indem Sie entweder die EINGABETASTE oder ESC drücken.
In einem anderen Teil des Texts, geben Sie "Test" ein, und drücken Sie dann die TAB-TASTE. Da der Codeausschnitt "Test" Verknüpfung ist, sollte der Ausschnitt erneut eingefügt werden.