Freigeben über


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:

  1. Erstellen und Registrieren von Codeausschnitten für eine bestimmte Sprache.

  2. Fügen Sie den Befehl Ausschnitt einfügen einem Kontextmenü hinzu.

  3. 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

  1. 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.)

  2. 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>
    
  3. 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

  1. Öffnen Sie das CompletionTest-Projekt. Informationen zum Ändern dieses Projekt finden Sie unter Exemplarische Vorgehensweise: Anweisungsvervollständigung anzeigen erstellt.

  2. Fügen Sie im Projekt Verweise auf die folgenden Assemblys hinzu:

    • Microsoft.VisualStudio.TextManager.Interop

    • Microsoft.VisualStudio.TextManager.Interop.8.0

    • microsoft.msxml

  3. 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.

  4. 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|
    
  5. Speichern Sie die Datei " source.extension.vsixmanifest ", und schließen Sie sie.

  6. Fügen Sie dem Projekt eine statische SnippetUtilities-Klasse hinzu.

    Module SnippetUtilities
    
    static class SnippetUtilities
    
  7. 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";
    
  8. 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
    
  9. 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

  1. Ö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);
    }
    
  2. 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

  1. 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;
    
  2. 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
    
  3. In der TestCompletionCommandHandlerProvider-Klasse importieren Sie ITextStructureNavigatorSelectorService.

    <Import()>
    Friend Property NavigatorService As ITextStructureNavigatorSelectorService
    
    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  4. 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;
    
  5. 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);
    }
    
  6. 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;
    }
    
  7. 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;
            }
        }
    }
    
  8. 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;
    }
    
  9. 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;
    }
    
  10. 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;
    }
    
  11. 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

  1. Erstellen Sie die Projektmappe. Wenn Sie dieses Projekt im Debugger ausführen, wird eine zweite Instanz von Visual Studio instanziiert.

  2. Öffnen Sie eine Textdatei, und geben Sie Text ein.

  3. Klicken Sie mit der rechten Maustaste irgendwo im Text, und klicken Sie dann auf Ausschnitt einfügen.

  4. 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.

  5. Drücken Sie TAB, UMSCHALT+TAB zum Wechseln zwischen "zuerst" und "second".

  6. Übernehmen Sie die Einfügung, indem Sie entweder die EINGABETASTE oder ESC drücken.

  7. 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.