Compartilhar via


Passo a passo: Implementando trechos de código

Você pode criar trechos de código e incluí-los em uma extensão de editor para que os usuários da extensão podem adicionar seu próprio código.

Um trecho de código é um fragmento de código ou outro texto que pode ser incorporado em um arquivo. Para exibir todos os trechos que foram registrados para linguagens de programação específicas, no Ferramentas menu, clique em Code Snippet Manager. Para inserir um trecho de código em um arquivo, o botão direito do mouse onde você deseja que o trecho, clique em Insert Snippet ou Surround com, localize o trecho desejado e clique duas vezes nele. Pressione TAB ou SHIFT + TAB para modificar as partes relevantes do trecho e pressione ENTER ou ESC para aceitá-lo. Para mais informações, consulte Trechos de código.

Um trecho de código está contido em um arquivo XML que tem a extensão de nome de arquivo .snippet. Um trecho pode conter campos são realçados depois de inserido o trecho para que o usuário possa localizar e alterá-los. Um arquivo de trecho de código também fornece informações para o Code Snippet Manager para que ele possa exibir o nome do trecho de código na categoria correta. Para obter informações sobre o esquema de trecho de código, consulte Referência de esquema dos trechos de código.

Esta explicação passo a passo ensina a realizar estas tarefas:

  1. Criar e registrar trechos de código para um idioma específico.

  2. Adicionar o Insert Snippet comando a um menu de atalho.

  3. Implementar a expansão do trecho.

Esta explicação passo a passo é baseada em Passo a passo: Exibindo a conclusão da instrução.

Pré-requisitos

Para concluir esta explicação passo a passo, você deve instalar o Visual Studio 2010 SDK. Para obter informações sobre o SDK do Visual Studio e fazer o download, consulte Visual Studio extensibilidade Developer Center no site do MSDN.

Criar e registrar trechos de código

Normalmente, trechos de código são associados um serviço de linguagem registrados. No entanto, você não precisará implementar um LanguageService para registrar os trechos de código. Em vez disso, basta Especifica um GUID no arquivo de índice do trecho e use o mesmo GUID de ProvideLanguageCodeExpansionAttribute que você adicionar ao seu projeto.

As etapas a seguir demonstram como criar trechos de código e associar um GUID específico.

Criar trechos de código

  1. Crie a seguinte estrutura de diretório:

    %InstallDir%\TestSnippets\Snippets\1033\

    onde % InstallDir % é a pasta de instalação Visual Studio. (Embora esse caminho é geralmente usado para instalar trechos de código, você pode especificar qualquer caminho.)

  2. Na pasta \1033\, crie um arquivo. XML e o nome SnippetIndex. XML. (Embora esse nome é usado geralmente para um arquivo de índice do trecho, você pode especificar qualquer nome desde que ele tenha uma extensão de nome de arquivo. XML.) Adicione o seguinte texto e excluir o espaço reservado GUID e adicionar seu próprio.

    <?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. Criar um arquivo na pasta do trecho, o nome test.snippete, em seguida, adicione o seguinte texto:

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

As etapas a seguir mostram como registrar os trechos de código.

Para registrar os trechos de código para um GUID específico

  1. Abra o projeto CompletionTest. Para obter informações sobre como criar este projeto, consulte Passo a passo: Exibindo a conclusão da instrução.

  2. No projeto, adicione referências aos assemblies seguintes:

    • Microsoft.VisualStudio.TextManager.Interop

    • Microsoft.VisualStudio.TextManager.Interop.8.0

    • Microsoft.MSXML

  3. Para registrar os trechos de código, o projeto deve criar um arquivo de .pkgdef. Para mais informações, consulte Registering VSPackages.

    No projeto, abra o arquivo source.extension.vsixmanifest.

  4. No conteúdo seção, clique Adicionar conteúdo, selecione o Pacote VS tipo de conteúdo, selecione a projeto opção e selecione TestCompletion na lista suspensa.

    Deve aparecer a seguinte linha no arquivo:

    TestCompletion;PkgdefProjectOutputGroup|
    
  5. Salve o arquivo source.extension.vsixmanifest e fechá-lo.

  6. Adicionar um estático SnippetUtilities classe ao projeto.

    Module SnippetUtilities
    
    static class SnippetUtilities
    
  7. Na classe SnippetUtilities, definir um GUID e atribua a ele o valor usado no arquivo SnippetsIndex.xml.

    Friend Const LanguageServiceGuidStr As String = "00000000-0000-0000-0000-00000000"
    
    internal const string LanguageServiceGuidStr = "00000000-0000-0000-0000-00000000";
    
  8. Adicionar o ProvideLanguageCodeExpansionAttribute para o TestCompletionHandler classe. Esse atributo pode ser adicionado a qualquer classe de público ou interno (não estático) no projeto. (Talvez você precise adicionar um using declaração do namespace Microsoft.VisualStudio.Shell.)

    <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. Criar e executar o projeto. O trecho registrado apenas na instância experimental do Visual Studio que é iniciado quando o projeto for executado, deverá ser exibido na Gerenciador de trechos de código sob o TestSnippets idioma.

Adicionando o comando de trecho de inserir no menu de atalho

O Insert Snippet comando não está incluído no menu de atalho para um arquivo de texto. Portanto, você deve ativar o comando.

Para adicionar o comando Insert Snippet no menu de atalho

  1. Abrir o TestCompletionCommandHandler arquivo de classe.

    Porque essa classe implementa IOleCommandTarget, você pode ativar o Insert Snippet comando na QueryStatus método. Antes de ativar o comando, verifique se esse método não está sendo chamado dentro de uma função de automação porque quando o Insert Snippet comando é clicado, ele exibirá a interface do usuário trecho seletor (UI).

    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. Criar e executar o projeto. Instância experimental, abrir um arquivo que possui a extensão de nome de arquivo. zzz e clique em qualquer lugar nela. O Insert Snippet comando deverá aparecer no menu de atalho.

Implementando a expansão do trecho no selecionador de trecho de interface do usuário

Esta seção mostra como implementar a expansão do trecho de código para que o selecionador de trecho de interface do usuário é exibido quando Insert Snippet é clicado no menu de atalho. Um trecho de código também é expandido quando um usuário digita o atalho do trecho de código e, em seguida, pressiona TAB.

Para exibir o selecionador de trecho de interface do usuário e permitir a navegação e a aceitação do trecho post-insertion, use o Exec método. A própria inserção é manipulada pelo OnItemChosen método.

A implementação de expansão do trecho de código usa legacy Microsoft.VisualStudio.TextManager.Interop interfaces. Ao traduzir de classes atuais do editor para código herdado, lembre-se de que as interfaces herdadas usar uma combinação de números de linha e coluna para especificar locais em um buffer de texto, mas as classes atuais usam um índice. Portanto, se um buffer tem três linhas, cada qual com dez caracteres (mais uma nova linha, que conta como um caractere), o quarto caractere na terceira linha está na posição 27 na implementação atual, mas é na linha 2, posição 3 antiga implementação.

Para implementar a expansão do trecho

  1. O arquivo que contém o TestCompletionCommandHandler da classe, adicione o seguinte using instruções.

    Imports Microsoft.VisualStudio.Text.Operations
    Imports MSXML
    
    using Microsoft.VisualStudio.Text.Operations;
    using MSXML;
    using System.ComponentModel.Composition;
    
  2. Verifique o TestCompletionCommandHandler classe implementar o IVsExpansionClient interface.

    <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. No TestCompletionCommandHandlerProvider classe, importar o ITextStructureNavigatorSelectorService.

    <Import()>
    Friend Property NavigatorService As ITextStructureNavigatorSelectorService
    
    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  4. Adicionar alguns campos privados para interfaces de expansão do código e a IVsTextView.

    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. No construtor do TestCompletionCommandHandler classe, definir os campos a seguir.

    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. Para exibir o selecionador de trecho de código quando o usuário clica o Insert Snippet comando, adicione o seguinte código para o Exec método. (Para fazer essa explicação mais legível, o EXEC () código que é usado para a conclusão da instrução não é mostrado; em vez disso, blocos de código são adicionados ao método existente.) Adicione o seguinte bloco de código após o código que verifica se um caractere.

    '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. Se um trecho possui campos que podem ser navegados, a sessão de expansão é mantida aberta até que a expansão é explicitamente aceito; Se o trecho não possui campos, a sessão é fechada e é retornada como null , o InvokeInsertionUI método. No Exec método, após o selecionador de trecho de código de interface do usuário que você adicionou na etapa anterior, adicione o seguinte código para manipular a navegação trecho (quando o usuário pressiona TAB ou SHIFT + TAB após a inserção de trecho de código).

    '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. Para inserir o trecho de código quando o usuário digita o atalho correspondente e, em seguida, pressiona TAB, adicione código para o Exec método. O método particular que insere o trecho de código será mostrado em uma etapa posterior. Adicione o seguinte código após o código de navegação que você adicionou na etapa anterior.

    '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. Implementar os métodos de IVsExpansionClient interface. Nessa implementação, os únicos métodos de interesse são EndExpansion e OnItemChosen. Outros métodos devem retornar apenas S_OK.

    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. Implemente o método OnItemChosen. O método auxiliar que realmente insere as expansões será abordado em uma etapa posterior. O TextSpan fornece informações de linha e coluna, que você pode obter o IVsTextView.

    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. O seguinte método privado insere um trecho de código com base no atalho ou no título e no caminho. Em seguida, chama o InsertNamedExpansion método com o trecho.

    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;
    }
    

Criar e testar a expansão do trecho de código

Você pode testar se a expansão do trecho funciona no seu projeto.

Para criar e testar a expansão do trecho de código

  1. Crie a solução. Quando você executar este projeto no depurador, uma segunda instância do Visual Studio é instanciada.

  2. Abra um arquivo de texto e digite algum texto.

  3. Clique com o botão direito em algum lugar no texto e clique em Insert Snippet.

  4. Selecionador de trecho de interface do usuário deve aparecer e exibir a seqüência de caracteres "Campos de substituição de teste". Clique duas vezes essa seqüência de caracteres.

    O trecho a seguir deve ser inserido.

    MessageBox.Show("first");
    MessageBox.Show("second");
    

    Não pressione ENTER ou ESC.

  5. Pressione TAB e SHIFT + TAB para alternar entre "primeiro" e "segundo".

  6. Aceite a inserção pressionando ENTER ou ESC.

  7. Em uma parte diferente do texto, digite "teste" e, em seguida, pressione TAB. Como "teste" é o atalho do trecho de código, o trecho de código deve ser inserido novamente.