Partilhar via


Suporte para trechos de código (estrutura de pacote gerenciado)

Um trecho de código é um trecho de código é inserido no arquivo de origem. O trecho de código em si é um modelo baseado em XML com um conjunto de campos. Esses campos serão realçados depois que o trecho de código é inserido e pode ter valores diferentes dependendo do contexto em que o trecho de código é inserido. Imediatamente depois de inserido o trecho, o serviço de linguagem pode formatar o trecho.

O trecho de código é inserido em um modo de edição especial que permite que os campos do trecho para ser navegado, usando a tecla TAB. Os campos podem oferecer suporte a menus suspensos de estilo IntelliSense. O usuário confirma o trecho de código ao arquivo de origem, digitando ou a tecla ENTER ou ESC. Para saber mais sobre os trechos de código, consulte Trechos de código.

Gerenciado de suporte de estrutura de pacote para trechos de código

A estrutura de pacote gerenciado (MPF) oferece suporte a mais funcionalidade do trecho, leia o modelo para inserir o trecho de código e permitindo que a sintaxe especial de modo de edição. Suporte é gerenciado por meio do ExpansionProvider classe.

Quando o Source classe é instanciada, o CreateExpansionProvider método no LanguageService classe é chamado para obter um ExpansionProvider objeto (Observe que a base de LanguageService classe sempre retorna uma nova ExpansionProvider objeto para cada Source objeto).

O MPF não oferece suporte a funções de expansão. Uma função de expansão é uma função nomeada que é incorporada em um modelo de trecho de código e retorna um ou mais valores sejam colocados em um campo. Os valores são retornados pelo idioma próprio através do serviço um ExpansionFunction objeto. O ExpansionFunction objeto deve ser implementado pelo serviço de linguagem para oferecer suporte a funções de expansão.

Fornecendo suporte para trechos de código

Para ativar o suporte para trechos de código, você deve fornecer ou instalar os trechos e você deve fornecer os meios para que o usuário inserir esses trechos. Existem três etapas para ativar o suporte para trechos de código:

  1. Instalando os arquivos de trecho de código.

  2. Habilitando os trechos de código para o serviço de linguagem.

  3. Chamar o ExpansionProvider objeto.

Instalando os arquivos de trecho

Todos os trechos de código para um idioma são armazenados como modelos em arquivos XML, normalmente um modelo de trecho de código por arquivo. Para obter detalhes sobre o esquema XML usado para modelos de trecho de código, consulte Referência de esquema dos trechos de código. Cada modelo de trecho de código é identificado com uma identificação de idioma. Este idioma ID é especificado no registro e é colocada na Language atributo do <Code> marca no modelo.

Há normalmente dois locais onde estão armazenados os arquivos de modelo de trecho: 1) em que o idioma foi instalado e 2) na pasta do usuário. Esses locais são adicionados ao registro assim que o Visual Studio Gerenciador de trechos de código pode encontrar os trechos. A pasta do usuário é onde são armazenados os trechos criados pelo usuário.

O layout de pasta comum para os arquivos de modelo de trecho de código instalado tem esta aparência: [Raiz_da_instalação]\[TestLanguage]\Snippets\[LCID]\Snippets.

[Raiz_da_instalação] é o seu idioma estiver instalado na pasta.

[TestLanguage] é o nome do seu idioma como um nome de pasta.

[LCID] é a identificação de localidade. Esta é a versões localizadas como trechos de código são armazenados. Por exemplo, a identificação de local para o inglês é 1033, então, [LCID] é substituído pelo 1033.

Um arquivo adicional deve ser fornecido e que é um arquivo de índice, geralmente chamado de SnippetsIndex.xml ou ExpansionsIndex.xml (você pode usar qualquer arquivo com extensão. XML válido). Normalmente, este arquivo é armazenado na [Raiz_da_instalação]\[TestLanguage] pasta e especifica o local exato da pasta de snippets bem como a identificação de idioma e o GUID do serviço de linguagem que usa os trechos. O caminho exato do arquivo de índice é colocado no registro, conforme descrito posteriormente "Instalando o entradas de registro". Aqui está um exemplo de um arquivo de SnippetsIndex.xml:

<?xml version="1.0" encoding="utf-8" ?>
<SnippetCollection>
    <Language Lang="Testlanguage" Guid="{b614a40a-80d9-4fac-a6ad-fc2868fff7cd}">
        <SnippetDir>
            <OnOff>On</OnOff>
            <Installed>true</Installed>
            <Locale>1033</Locale>
            <DirPath>%InstallRoot%\TestLanguage\Snippets\%LCID%\Snippets\</DirPath>
            <LocalizedName>Snippets</LocalizedName>
        </SnippetDir>
    </Language>
</SnippetCollection>

O <Language> marca Especifica a identificação de idioma (o Lang atributo) e o serviço de linguagem GUID.

Este exemplo assume que você instalou o serviço de linguagem na pasta de instalação Visual Studio. O LCID de % % será substituído pelo ID atual localidade. do usuário Vários <SnippetDir> as marcas podem ser adicionados, uma para cada localidade e um diretório diferente. Além disso, uma pasta de trecho pode conter subpastas, cada um deles é identificada no arquivo de índice com <SnippetSubDir> marca que está incorporada em um <SnippetDir> marca.

Os usuários também podem criar seus próprios trechos de código para o seu idioma. Eles geralmente são armazenados na pasta de configurações do usuário, por exemplo [TestDocs]\Code Snippets\[TestLanguage]\Test trechos de código, onde [TestDocs] é o local da pasta de configurações do usuário para Visual Studio.

Os seguintes elementos de substituição podem ser colocados no caminho armazenado em <DirPath> marca no arquivo de índice.

Elemento

Descrição

LCID DE % %

ID de localidade.

% Raiz_da_instalação %

Pasta de instalação de raiz para Visual Studio, por exemplo, C:\Program 8 de Visual Studio da Files\Microsoft.

% ProjDir %

Pasta que contém o projeto atual.

% ProjItem %

Pasta que contém o item de projeto atual.

% TestDocs %

A pasta na pasta de configurações do usuário, por exemplo, C:\Documents and Settings \[usuário]\My Documents\Visual Studio\8.

A ativação de trechos de código para o serviço de linguagem

Você pode ativar os trechos de código para o serviço de linguagem, adicionando a ProvideLanguageCodeExpansionAttribute de atributo para seu VSPackage (consulte Registrando um serviço de linguagem (estrutura de pacote gerenciado) para obter detalhes). O ShowRoots e SearchPaths parâmetros são opcionais, mas você deve incluir a SearchPaths nomeado o parâmetro para informar o Gerenciador de trechos de código da localização dos trechos de código.

Este é um exemplo de como usar esse atributo:

[ProvideLanguageCodeExpansion(
         typeof(TestSnippetLanguageService),
         "Test Snippet Language",          // Name of language used as registry key
         0,                               // Resource ID of localized name of language service
         "Test Snippet Language",        // Name of Language attribute in snippet template
         @"%InstallRoot%\Test Snippet Language\Snippets\%LCID%\SnippetsIndex.xml",  // Path to snippets index
         SearchPaths = @"%InstallRoot%\Test Snippet Language\Snippets\%LCID%\")]    // Path to snippets

O provedor de expansão

O serviço de linguagem controla a inserção de qualquer trecho de código, bem como o modo de inserção é invocada.

Chamar o provedor de expansão para trechos de código

Há duas maneiras para chamar o provedor de expansão: usando um comando de menu ou usando um atalho de uma lista de conclusão.

Inserindo um trecho de código usando um comando de Menu

Para usar um comando de menu para exibir o navegador de trecho de código, você pode adicionar um comando de menu e chamar o DisplayExpansionBrowser método na ExpansionProvider interface em resposta a esse comando de menu.

  1. Adicione um comando e um botão para o arquivo .vsct. Você pode encontrar instruções sobre como fazer assim, Passo a passo: Criando um comando de Menu usando o modelo de pacote de Visual Studio.

  2. Derivar uma classe a partir de ViewFilter de classe e substituir o QueryCommandStatus método para indicar o suporte para o novo comando de menu. Este exemplo sempre ativa o comando de menu.

    using Microsoft.VisualStudio.Package;
    
    namespace TestLanguagePackage
    {
        class TestViewFilter : ViewFilter
        {
            public TestViewFilter(CodeWindowManager mgr, IVsTextView view)
                : base(mgr, view)
            {
            }
    
            protected override int QueryCommandStatus(ref Guid guidCmdGroup,
                                                      uint nCmdId)
            {
                int hr = base.QueryCommandStatus(ref guidCmdGroup, nCmdId);
                // If the base class did not recognize the command then
                // see if we can handle the command.
                if (hr == (int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_UNKNOWNGROUP)
                {
                    if (guidCmdGroup == GuidList.guidTestLanguagePackageCmdSet)
                    {
                        if (nCmdId == PkgCmdIDList.InvokeCodeSnippetsBrowser)
                        {
                            hr = (int)(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED);
                        }
                    }
                }
                return hr;
            }
        }
    }
    
  3. Substituir o HandlePreExec método na ViewFilter classe para obter o ExpansionProvider objeto e a chamada a DisplayExpansionBrowser método nesse objeto.

    using Microsoft.VisualStudio.Package;
    
    namespace TestLanguagePackage
    {
        class TestViewFilter : ViewFilter
        {
            public override bool HandlePreExec(ref Guid guidCmdGroup,
                                               uint nCmdId,
                                               uint nCmdexecopt,
                                               IntPtr pvaIn,
                                               IntPtr pvaOut)
            {
                if (base.HandlePreExec(ref guidCmdGroup,
                                       nCmdId,
                                       nCmdexecopt,
                                       pvaIn,
                                       pvaOut))
                {
                    // Base class handled the command.  Do nothing more here.
                    return true;
                }
    
                if (guidCmdGroup == GuidList.guidTestLanguagePackageCmdSet)
                {
                    if (nCmdId == PkgCmdIDList.InvokeCodeSnippetsBrowser)
                    {
                        ExpansionProvider ep = this.GetExpansionProvider();
                        if (this.TextView != null && ep != null)
                        {
                            bool bDisplayed = ep.DisplayExpansionBrowser(
                                this.TextView,
                                "TestLanguagePackage Snippet:",
                                null,
                                false,
                                null,
                                false);
                        }
                        return true;   // Handled the command.
                    }
                }
                return false;   // Did not handle the command.
            }
        }
    }
    

    Os seguintes métodos na ExpansionProvider classe são chamados por Visual Studio na ordem determinada durante o processo de inserir o trecho:

  4. OnItemChosen

  5. IsValidKind

  6. OnBeforeInsertion

  7. FormatSpan

  8. OnAfterInsertion

    Após a OnAfterInsertion método é chamado, o trecho de código foi inserido e o ExpansionProvider objeto está em um modo de edição especial usado para modificar um trecho que apenas foi inserido.

Inserindo um trecho de código usando um atalho

Implementação de um atalho de uma lista de conclusão é muito mais atrativo que a implementação de um comando de menu. Primeiro, você deve adicionar atalhos de trecho para a lista de conclusão de palavras IntelliSense. Em seguida, você deve detectar quando foi inserido um nome de atalho do trecho como resultado da conclusão. Finalmente, você deve obter o título do trecho de código e o caminho usando o nome do atalho e passar essa informação para o InsertNamedExpansion método sobre o ExpansionProvider método.

Para adicionar atalhos de trecho de código para a lista de conclusão de palavras, adicioná-los para o Declarations de objeto no seu AuthoringScope classe. Você deve se certificar de que você pode identificar o atalho como um nome de trecho de código. Para um exemplo, consulte Passo a passo: Obtendo uma lista de trechos de código instalado (estrutura de pacote gerenciado).

Você pode detectar a inserção do atalho do trecho de código na OnAutoComplete método da Declarations classe. Porque o nome do trecho já foi inserido no arquivo de origem, ele deve ser removido quando a expansão é inserida. O InsertNamedExpansion método usa um intervalo que descreve o ponto de inserção para o trecho de código; Se o intervalo inclui o nome inteiro do trecho de código no arquivo de origem, esse nome é substituído pelo trecho.

Aqui está uma versão de um Declarations classe que manipula a inserção de trechos recebe um nome de atalho. Outros métodos de Declarations classe foram omitidos por motivos de clareza. Observe que o construtor dessa classe utiliza um LanguageService objeto. Isso poderá ser passado da versão do AuthoringScope objeto (por exemplo, a implementação da AuthoringScope classe pode levar a LanguageService em seu construtor de objetos e passar esse objeto para seu TestDeclarations construtor de classe).

[C#]
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.TextManager.Interop;

namespace TestLanguagePackage
{
    internal class TestDeclarations : Declarations
    {
        private ArrayList       declarations;
        private LanguageService languageService;
        private TextSpan        commitSpan;

        public TestDeclarations(LanguageService langService)
            : base()
        {
            languageService = langService;
            declarations = new ArrayList();
        }

        // This method is used to add declarations to the internal list.
        public void AddDeclaration(TestDeclaration declaration)
        {
            declarations.Add(declaration);
        }

        

        // This method is called to get the string to commit to the source buffer.
        // Note that the initial extent is only what the user has typed so far.
        public override string OnCommit(IVsTextView textView,
                                        string textSoFar,
                                        char commitCharacter,
                                        int index,
                                        ref TextSpan initialExtent)
        {
            // We intercept this call only to get the initial extent
            // of what was committed to the source buffer.
            commitSpan = initialExtent;

            return base.OnCommit(textView,
                                 textSoFar,
                                 commitCharacter,
                                 index,
                                 ref initialExtent);
        }

        // This method is called after the string has been committed to the source buffer.
        public override char OnAutoComplete(IVsTextView textView,
                                            string committedText,
                                            char commitCharacter,
                                            int index)
        {
            TestDeclaration item = declarations[index] as TestDeclaration;
            if (item != null)
            {
                // In this example, TestDeclaration identifies types with a string.
                // You can choose a different approach.
                if (item.Type == "snippet")
                {
                    Source src = languageService.GetSource(textView);
                    if (src != null)
                    {
                        ExpansionProvider ep = src.GetExpansionProvider();
                        if (ep != null)
                        {
                            string title;
                            string path;
                            int commitLength = commitSpan.iEndIndex - commitSpan.iStartIndex;
                            if (commitLength < committedText.Length)
                            {
                                // Replace everything that was inserted
                                // so calculate the span of the full
                                // insertion, taking into account what
                                // was inserted when the commitSpan
                                // was obtained in the first place.
                                commitSpan.iEndIndex += (committedText.Length - commitLength);
                            }

                            if (ep.FindExpansionByShortcut(textView,
                                                           committedText,
                                                           commitSpan,
                                                           true,
                                                           out title,
                                                           out path))
                            {
                                ep.InsertNamedExpansion(textView,
                                                        title,
                                                        path,
                                                        commitSpan,
                                                        false);
                            }
                        }
                    }
                }
            }
            return '\0';
        }
    }
}

Quando o serviço de linguagem obtém o nome do atalho, ele chama o FindExpansionByShortcut método para obter o título de trecho de código e nome do arquivo. O serviço de linguagem, em seguida, chama o InsertNamedExpansion método na ExpansionProvider classe para inserir o trecho de código. Os seguintes métodos são chamados por Visual Studio na ordem determinada na ExpansionProvider classe durante o processo de inserir o trecho:

  1. IsValidKind

  2. OnBeforeInsertion

  3. FormatSpan

  4. OnAfterInsertion

Para obter mais informações sobre como obter uma lista de trechos de código instalado para o serviço de linguagem, consulte Passo a passo: Obtendo uma lista de trechos de código instalado (estrutura de pacote gerenciado).

Implementando a classe ExpansionFunction

Uma função de expansão é uma função nomeada que é incorporada em um modelo de trecho de código e retorna um ou mais valores sejam colocados em um campo. Para oferecer suporte a funções de expansão no seu serviço de idioma, você deve derivar uma classe a partir de ExpansionFunction de classe e implementar o GetCurrentValue método. Em seguida, você deve substituir o CreateExpansionFunction método na LanguageService classe para retornar uma nova instanciação de sua versão do ExpansionFunction classe para cada função de expansão que oferecem suporte para você. Se você oferecer suporte a uma lista dos valores possíveis de uma função de expansão, você também deverá substituir o GetIntellisenseList método na ExpansionFunction classe para retornar uma lista desses valores.

Uma função de expansão que leva argumentos ou precise acessar outros campos não deve ser associada um campo editável, como o provedor de expansão não pode ser totalmente inicializado no momento em que a função de expansão é chamada. Como resultado, a função de expansão não é capaz de obter o valor de seus argumentos ou qualquer outro campo.

Exemplo

Aqui está um exemplo de como uma função de expansão simples chamado GetName pode ser implementado. Essa função de expansão anexa um número para um nome de classe base sempre que a função de expansão é instanciada (que corresponde a cada vez que o trecho de código associado é inserido).

using Microsoft.VisualStudio.Package;

namespace TestLanguagePackage
{
    public class TestLanguageService : LanguageService
    {
        private int classNameCounter = 0;

        public override ExpansionFunction CreateExpansionFunction(
            ExpansionProvider provider,
            string functionName)
        {
            ExpansionFunction function = null;
            if (functionName == "GetName")
            {
                ++classNameCounter;
                function = new TestGetNameExpansionFunction(provider, classNameCounter);
            }
            return function;
        }
    }

    internal class TestGetNameExpansionFunction : ExpansionFunction
    {
        private int nameCount;

        TestGetNameExpansionFunction(ExpansionProvider provider, int counter)
            : base(provider)
        {
            nameCount = counter;
        }

        public override string GetCurrentValue()
        {
            string name = "TestClass";
            name += nameCount.ToString();
            return name;
        }
    }
}

Consulte também

Tarefas

Passo a passo: Obtendo uma lista de trechos de código instalado (estrutura de pacote gerenciado)

Conceitos

Registrando um serviço de linguagem (estrutura de pacote gerenciado)

Outros recursos

Recursos de serviço de linguagem (estrutura de pacote gerenciado)

Trechos de código