Condividi tramite


Supporto dei frammenti di codice (managed package Framework)

Un frammento di codice è un frammento di codice inserito nel file di origine. Il frammento stesso è un modello basato su XML con un set di campi. Questi campi sono evidenziati dopo che viene inserito il frammento e può avere valori differenti a seconda del contesto in cui viene inserito il frammento. Subito dopo che viene inserito il frammento, il servizio di linguaggio possibile formattare il frammento.

Viene inserito il frammento di codice in modalità di modifica speciale che consente i campi del frammento da esplorare utilizzando il tasto TAB. i campi possono supportare i menu a discesa stile IntelliSense. L'utente esegue il commit del frammento al file di origine inserendo INVIO o ESC. Per ulteriori informazioni sui frammenti vedere Frammenti di codice.

Supporto gestito del Framework del pacchetto ai frammenti di codice

Il framework gestito del pacchetto (MPF) supporta la maggior parte delle funzionalità del frammento, di leggere il modello a inserire il frammento e ad abilitare la modalità di modifica speciale. Il supporto viene gestito mediante la classe di ExpansionProvider .

Quando la classe di Source viene creata un'istanza, il metodo di CreateExpansionProvider nella classe di LanguageService viene chiamato per ottenere un oggetto di ExpansionProvider (si noti che la classe base di LanguageService restituisce sempre un nuovo oggetto di ExpansionProvider per ogni oggetto di Source ).

Il MPF non supporta le funzioni di espansione. Una funzione di espansione è una funzione denominata che è incorporata nel modello del frammento e restituisce uno o più valori da inserire in un campo. I valori vengono restituiti dal servizio di linguaggio stesso tramite un oggetto di ExpansionFunction . L'oggetto di ExpansionFunction deve essere implementato dal servizio di linguaggio per supportare le funzioni di espansione.

fornendo supporto per i frammenti di codice

Per abilitare il supporto dei frammenti di codice, è necessario fornire o installarvi i frammenti di codice e deve definire un modo affinché l'utente inserisce i frammenti. Esistono tre passaggi per abilitare il supporto dei frammenti di codice:

  1. Installare i file frammento.

  2. abilitare i frammenti di codice per il servizio di linguaggio.

  3. richiamare l'oggetto di ExpansionProvider .

Installare i file frammento

Tutti i frammenti per un linguaggio sono archiviati come modelli in un file XML, in genere un modello del frammento per file. Per le visualizzazioni dinamiche della voce di menu, è necessario modificarlo in OleMenuCommand, come illustrato nel passaggio successivo. Ogni modello del frammento viene identificato con un ID lingua This language ID is specified in the registry and is put into the Language attribute of the <Code> tag in the template.

Esistono in genere due percorsi dei file di modello del frammento sono archiviati: 1) dove il linguaggio è stato installato e 2) nella cartella dell'utente. Questi percorsi vengono aggiunti al Registro di sistema in modo da consentire la ricerca Visual Studio Amministratore dei frammenti di codice i frammenti. La cartella dell'utente in cui sono presenti i frammenti creati dall'utente archiviati.

Il layout tipico di cartella per gli aspetti installati i file di modello del frammento è analogo al seguente: [InstallRoot]\[TestLanguage]\Snippets \[LCID]\Snippets.

[InstallRoot] è la cartella del linguaggio è installato in.

[TestLanguage] è il nome del linguaggio come nome della cartella.

[LCID] rappresenta l'id delle impostazioni locali Questo è il modo in cui le versioni localizzate dei frammenti vengono archiviate. Ad esempio, l'ID delle impostazioni locali per la lingua inglese è 1033, pertanto [LCID] viene sostituito da ora al 1033.

Un file aggiuntivo deve essere specificato e che è un file di indice, in genere chiamato SnippetsIndex.xml o ExpansionsIndex.xml (è possibile utilizzare qualsiasi fine valida del nome file in XML). Questo file viene generalmente archiviato nella cartella[TestLanguage] \ [InstallRoot]e specifica la posizione esatta della cartella dei frammenti nonché l'id lingua e il GUID del servizio di linguaggio che utilizza i frammenti. Il percorso esatto del file di indice viene inserito nel Registro di sistema come descritto più avanti “quando si installano le voci del Registro di sistema„. Di seguito è riportato un esempio di un file di 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>

Il tag di <linguaggio> specifica l'ID lingua (l'attributo di Lang ) e il servizio di linguaggio GUID.

In questo esempio si presuppone che ha installato il servizio di linguaggio nella cartella di installazione di Visual Studio. Il %LCID% viene sostituito con l'id corrente delle impostazioni locali dell'utente I tag più di <SnippetDir> possono essere aggiunti, uno per ogni directory differente e impostazioni locali. Inoltre, una cartella del frammento può contenere le sottocartelle, ciascuno dei quali viene identificata nel file di indice con il tag di <SnippetSubDir> incorporato in un tag di <SnippetDir> .

Gli utenti possono inoltre creare i propri frammenti per il linguaggio. Questi in genere vengono archiviati nella cartella delle impostazioni dell'utente, ad esempio [TestDocs]\Code Snippets \[TestLanguage]\Test Code Snippets, dove [TestDocs] è il percorso della cartella delle impostazioni di Visual Studio.

I seguenti elementi di sostituzione possono essere inseriti nel percorso archiviato nel tag di <DirPath> nel file di indice.

Elemento

Descrizione

%LCID%

ID delle impostazioni locali.

%InstallRoot%

Cartella di installazione radice per Visual Studio, ad esempio, C#: \Program Files\Microsoft Visual Studio 8.

%ProjDir%

Cartella che contiene il progetto corrente.

%ProjItem%

Cartella contenente l'elemento di progetto corrente.

%TestDocs%

Cartella nella cartella delle impostazioni dell'utente, ad esempio, C#: \Documents and Settings \[nome utente]\My Documents\Visual Studio \ 8.

abilitare i frammenti di codice per il servizio di linguaggio

È possibile abilitare i frammenti di codice per il servizio di linguaggio aggiungendo l'attributo di ProvideLanguageCodeExpansionAttribute al package VS ( Registrando un servizio di linguaggio (managed package Framework) per i dettagli). I parametri di SearchPaths e di ShowRoots sono facoltativi, ma è necessario includere il parametro denominato di SearchPaths per notificare a Amministratore dei frammenti di codice della posizione dei frammenti.

Di seguito viene riportato un esempio di come utilizzare questo attributo:

[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

chiamare il provider di espansione

Il servizio di linguaggio controlla l'inserimento di qualsiasi frammento di codice nonché l'inserimento della modalità viene richiamato.

chiamare il provider di espansione per i frammenti di codice

Esistono due modi per richiamare il provider di espansione: tramite un comando di menu o un collegamento da un elenco di completamento.

Inserendo un frammento di codice tramite un comando di menu

Per utilizzare un comando di menu viene visualizzato il browser del frammento, aggiungere un comando di menu e quindi chiamare il metodo di DisplayExpansionBrowser interfaccia di ExpansionProvider in risposta a tale comando di menu.

  1. Aggiungere un comando e un pulsante al file di .vsct. È possibile trovare istruzioni per farlo in procedura dettagliata: Creazione di un comando di menu utilizzando il modello importa pacchetto Visual Studio.

  2. Derivare la classe dalla classe di ViewFilter ed eseguire l'override del metodo di QueryCommandStatus per indicare il supporto per il nuovo comando di menu. Questo esempio consente sempre il comando di 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. Eseguire l'override del metodo di HandlePreExec nella classe di ViewFilter per ottenere l'oggetto di ExpansionProvider e chiamare il metodo di DisplayExpansionBrowser su tale oggetto.

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

    I seguenti metodi nella classe di ExpansionProvider vengono chiamati da Visual Studio nell'ordine specificato nella fase dell'inserimento dei frammenti:

  4. OnItemChosen

  5. IsValidKind

  6. OnBeforeInsertion

  7. FormatSpan

  8. OnAfterInsertion

    Dopo che il metodo di OnAfterInsertion viene chiamato, il frammento di codice è stato inserito e l'oggetto di ExpansionProvider è in modalità di modifica speciale utilizzata per modificare un frammento che è stato inserito.

Inserendo un frammento di codice mediante un collegamento

L'implementazione di un collegamento da un elenco di completamento è molto più complessa dell'implementazione di un comando di menu. È innanzitutto necessario aggiungere collegamenti del frammento all'elenco di completamento delle parole di IntelliSense. È quindi necessario rilevare quando un nome di collegamento del frammento di codice è stato inserito come risultato finale. Infine, è necessario ottenere il titolo e il percorso del frammento utilizzando il nome di collegamento e comunicare tali informazioni al metodo di InsertNamedExpansion il metodo di ExpansionProvider .

Per aggiungere collegamenti del frammento all'elenco di completamento delle parole, aggiungerli a l di Declarations nella classe di AuthoringScope . È necessario verificare che sia possibile identificare il collegamento come nome del frammento. Per un esempio, vedere procedura dettagliata: Ottiene un elenco di frammenti di codice installati (managed package Framework).

È possibile rilevare l'inserimento del collegamento del frammento di codice nel metodo di OnAutoComplete della classe di Declarations . Poiché il nome del frammento è già stato inserito nel file di origine, deve essere rimosso durante l'espansione viene inserita. Il metodo di InsertNamedExpansion accetta un intervallo che descrive il punto di inserimento per il frammento; se l'intervallo include l'intero nome del frammento nel file di origine, il nome verrà sostituito dal frammento.

Di seguito è riportata una versione di una classe di Declarations che gestisce inserendo un frammento fornito un nome di scelta rapida. Altri metodi nella classe di Declarations sono stati omessi per maggiore chiarezza. Si noti che il costruttore della classe accetta un oggetto di LanguageService . Ciò può essere passata dalla versione dell'oggetto di AuthoringScope (ad esempio, l'implementazione della classe di AuthoringScope è possibile che l'oggetto di LanguageService il proprio costruttore e passare tale oggetto al costruttore della classe di TestDeclarations ).

[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 il servizio di linguaggio ottiene il nome del collegamento, chiama il metodo di FindExpansionByShortcut per ottenere il nome file e il titolo del frammento di codice. Il servizio di linguaggio chiama quindi il metodo di InsertNamedExpansion nella classe di ExpansionProvider per inserire il frammento di codice. I seguenti metodi vengono chiamati da Visual Studio nell'ordine specificato nella classe di ExpansionProvider in fase dell'inserimento dei frammenti:

  1. IsValidKind

  2. OnBeforeInsertion

  3. FormatSpan

  4. OnAfterInsertion

Per ulteriori informazioni su come ottenere un elenco di frammenti di codice installati per il servizio di linguaggio, vedere procedura dettagliata: Ottiene un elenco di frammenti di codice installati (managed package Framework).

implementare la classe di ExpansionFunction

Una funzione di espansione è una funzione denominata che è incorporata nel modello del frammento e restituisce uno o più valori da inserire in un campo. Per supportare le funzioni di espansione nel servizio di linguaggio, è necessario derivare una classe dalla classe di ExpansionFunction e implementare il metodo di GetCurrentValue . È quindi necessario eseguire l'override del metodo di CreateExpansionFunction nella classe di LanguageService per restituire una nuova creazione di istanze della versione della classe di ExpansionFunction per ogni funzione di espansione supportate. Se si supportano un elenco di valori possibili da una funzione di espansione, è inoltre necessario eseguire l'override del metodo di GetIntellisenseList nella classe di ExpansionFunction per restituire un elenco di tali valori.

Una funzione di espansione che accetta argomenti e le necessità di accedere ad altri campi non devono essere associate a un campo modificabile, come il provider di espansione non è completamente essere inizializzato prima che la funzione di espansione venga chiamato. Pertanto, la funzione di espansione non può ottenere il valore dei relativi argomenti o qualsiasi altro campo.

Esempio

Di seguito è riportato un esempio di come una funzione semplice di espansione chiamata GetName può essere implementata. Questa funzione di espansione aggiunge un numero a un nome di classe base ogni volta che la funzione di espansione viene creata un'istanza (corrispondente a ogni qualvolta il frammento di codice associato viene inserita).

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

Vedere anche

Attività

procedura dettagliata: Ottiene un elenco di frammenti di codice installati (managed package Framework)

Concetti

Registrando un servizio di linguaggio (managed package Framework)

Altre risorse

Funzionalità del servizio di linguaggio (managed package Framework)

Frammenti di codice