Saisie semi-automatique de membre dans un service de langage héritéMember Completion in a Legacy Language Service

La saisie semi-automatique de membres IntelliSense est une info-bulle qui affiche une liste de membres possibles d’une étendue particulière tel qu’une classe, structure, énumération ou espace de noms.The IntelliSense Member Completion is a tool tip that displays a list of possible members of a particular scope such as a class, structure, enumeration, or namespace. Par exemple, en c#, si l’utilisateur tape « this » suivi d’un point, une liste de tous les membres de la classe ou structure dans la portée actuelle est présentée dans une liste à partir de laquelle l’utilisateur peut sélectionner.For example, in C#, if the user types "this" followed by a period, a list of all members of the class or structure at the current scope is presented in a list from which the user can select.

L’infrastructure de package managé (MPF) fournit la prise en charge pour l’info-bulle et la gestion de la liste dans l’info-bulle ; tout ce qui est nécessaire est coopération à partir de l’analyseur pour fournir les données qui apparaissent dans la liste.The managed package framework (MPF) provides support for the tool tip and managing the list in the tool tip; all that is needed is cooperation from the parser to supply the data that appears in the list.

Services de langage hérité sont implémentés en tant que partie d’un VSPackage, mais la plus récente pour implémenter des fonctionnalités de service de langage consiste à utiliser des extensions MEF.Legacy language services are implemented as part of a VSPackage, but the newer way to implement language service features is to use MEF extensions. Pour plus d’informations, consultez extension de l’éditeur et les Services de langage.To find out more, see Extending the Editor and Language Services.

Note

Nous vous recommandons de commencer à utiliser le nouvel éditeur API dès que possible.We recommend that you begin to use the new editor API as soon as possible. Cela améliorer les performances de votre service de langage et vous permettent de tirer parti des nouvelles fonctionnalités de l’éditeur.This will improve the performance of your language service and let you take advantage of new editor features.

Son fonctionnementHow It Works

Voici les deux façons dans lequel une liste de membres est indiquée en utilisant les classes MPF :The following are the two ways in which a member list is shown using the MPF classes:

  • Positionner le signe insertion sur un identificateur ou après un caractère de saisie semi-automatique de membre et en sélectionnant liste des membres à partir de la IntelliSense menu.Positioning the caret on an identifier or after a member completion character and selecting List Members from the IntelliSense menu.

  • Le IScanner scanneur détecte un caractère de saisie semi-automatique de membre et définit un déclencheur de jeton de TokenTriggers.MemberSelect pour ce caractère.The IScanner scanner detects a member completion character and sets a token trigger of TokenTriggers.MemberSelect for that character.

Un caractère de saisie semi-automatique de membre indique qu’un membre d’une classe, une structure ou une énumération consiste à suivre.A member completion character indicates that a member of a class, structure, or enumeration is to follow. Par exemple, en c# ou Visual Basic, le caractère de saisie semi-automatique de membre est un ., tandis que dans C++ le caractère est un . ou un ->.For example, in C# or Visual Basic the member completion character is a ., while in C++ the character is either a . or a ->. La valeur du déclencheur est définie lorsque le caractère de sélection de membre est analysé.The trigger value is set when the member select character is scanned.

La commande de liste de membres IntelliSenseThe IntelliSense Member List Command

Le VSConstants.VSStd2KCmdID commande lance un appel à la Completion méthode sur le Source classe et le Completion (méthode), à son tour, appelle le ParseSource Analyseur de méthode avec le motif de l’analyse de ParseReason.DisplayMemberList .The VSConstants.VSStd2KCmdID command initiates a call to the Completion method on the Source class and the Completion method, in turn, calls the ParseSource method parser with the parse reason of ParseReason.DisplayMemberList.

L’analyseur détermine le contexte de la position actuelle, ainsi que le jeton sous ou immédiatement avant la position actuelle.The parser determines the context of the current position as well as the token under or immediately before the current position. Une liste des déclarations en fonction de ce jeton, est présentée.Based on this token, a list of declarations is presented. Par exemple, en c#, si vous positionnez le point d’insertion sur un membre de classe, puis sélectionnez liste des membres, vous obtenez une liste de tous les membres de la classe.For example, in C#, if you position the caret on a class member and select List Members, you get a list of all members of the class. Si vous placez le signe insertion après une période qui suit une variable objet, vous obtenez une liste de tous les membres de la classe qui représente l’objet.If you position the caret after a period that follows an object variable, you get a list of all members of the class that object represents. Notez que si le signe insertion est positionné sur un membre lors de l’affichage de la liste des membres, vous sélectionnez un membre dans la liste remplace le membre le signe insertion sur avec celle de la liste.Note that if the caret is positioned on a member when the member list is shown, selecting a member from the list replaces the member the caret is on with the one in the list.

Le déclencheur de jetonThe Token Trigger

Le TokenTriggers.MemberSelect déclencheur lance un appel à la Completion méthode sur le Source classe et le Completion (méthode), appelle à son tour, l’analyseur avec le motif de l’analyse de ParseReason.MemberSelect.The TokenTriggers.MemberSelect trigger initiates a call to the Completion method on the Source class and the Completion method, in turn, calls the parser with the parse reason of ParseReason.MemberSelect. Si le déclencheur de jeton est également inclus la TokenTriggers.MatchBraces indicateur, la raison de l’analyse est ParseReason.MemberSelectAndHighlightBraces, qui combine la sélection de membre et la mise en surbrillance des accolades .If the token trigger also included the TokenTriggers.MatchBraces flag, the parse reason is ParseReason.MemberSelectAndHighlightBraces, which combines member selection and brace highlighting.

L’analyseur détermine le contexte du courant de position, ainsi que ce qui a été tapé avant le membre Sélectionnez caractère.The parser determines the context of the current position as well as what has been typed before the member select character. À partir de ces informations, l’analyseur crée une liste de tous les membres de la portée demandée.From this information, the parser creates a list of all members of the requested scope. Cette liste de déclarations est stockée dans le AuthoringScope objet qui est retourné à partir de la ParseSource (méthode).This list of declarations is stored in the AuthoringScope object that is returned from the ParseSource method. Si toutes les déclarations sont retournées, l’info-bulle Saisie semi-automatique de membre s’affiche.If any declarations are returned, the member completion tool tip is displayed. L’info-bulle est géré par une instance de la CompletionSet classe.The tool tip is managed by an instance of the CompletionSet class.

Activer la prise en charge de la saisie semi-automatique de membresEnable Support for Member Completion

Vous devez avoir le CodeSense entrée de Registre est définie sur 1 pour prendre en charge une opération IntelliSense.You must have the CodeSense registry entry set to 1 to support any IntelliSense operation. Cette entrée de Registre peut être définie avec un paramètre nommé transmis à la ProvideLanguageServiceAttribute un attribut utilisateur associé au package de langage.This registry entry can be set with a named parameter passed to the ProvideLanguageServiceAttribute user attribute associated with the language package. Les classes de service de langage lire la valeur de cette entrée de Registre à partir de la EnableCodeSense propriété sur le LanguagePreferences classe.The language service classes read the value of this registry entry from the EnableCodeSense property on the LanguagePreferences class.

Si le scanneur retourne le jeton déclencheur de TokenTriggers.MemberSelect, votre analyseur retourne une liste des déclarations, puis la liste de saisie semi-automatique de membre s’affiche.If your scanner returns the token trigger of TokenTriggers.MemberSelect, and your parser returns a list of declarations, then the member completion list is displayed.

Prise en charge de la saisie semi-automatique de membres dans l’analyseurSupport Member Completion in the Scanner

Le scanneur doit être en mesure de détecter un caractère de saisie semi-automatique de membre et définissez le déclencheur de jeton de TokenTriggers.MemberSelect lorsque ce caractère est analysé.The scanner must be able to detect a member completion character and set the token trigger of TokenTriggers.MemberSelect when that character is parsed.

Exemple de l’analyseurScanner example

Voici un exemple simplifié de détecter le caractère de saisie semi-automatique de membre et de configuration approprié TokenTriggers indicateur.Here is a simplified example of detecting the member completion character and setting the appropriate TokenTriggers flag. Cet exemple est uniquement à des fins d’illustration.This example is for illustrative purposes only. Il suppose que le scanneur contient une méthode GetNextToken qui identifie et retourne les jetons à partir d’une ligne de texte.It assumes that your scanner contains a method GetNextToken that identifies and returns tokens from a line of text. L’exemple de code se contente de définir le déclencheur lorsqu’il détecte le type de caractère correct.The example code simply sets the trigger whenever it sees the right kind of character.

using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.TextManager.Interop;

namespace TestLanguagePackage
{
    public class TestScanner : IScanner
    {
        private Lexer lex;
        private const char memberSelectChar = '.';

        public bool ScanTokenAndProvideInfoAboutIt(TokenInfo tokenInfo,
                                                   ref int state)
        {
            bool foundToken = false
            string token = lex.GetNextToken();
            if (token != null)
            {
                foundToken = true;
                char c = token[0];
                if (c == memberSelectChar)
                {
                        tokenInfo.Trigger |= TokenTriggers.MemberSelect;
                }
            }
            return foundToken;
        }
    }
}

Prise en charge de la saisie semi-automatique de membres dans l’analyseurSupport Member Completion in the Parser

Pour la saisie semi-automatique de membres, le Source classe appelle le GetDeclarations (méthode).For member completion, the Source class calls the GetDeclarations method. Vous devez implémenter la liste dans une classe dérivée de la Declarations classe.You must implement the list in a class that is derived from the Declarations class. Consultez la Declarations classe pour plus d’informations sur les méthodes que vous devez implémenter.See the Declarations class for details about the methods you must implement.

L’analyseur est appelé avec ParseReason.MemberSelect ou ParseReason.MemberSelectAndHighlightBraces quand un caractère de sélection de membre est tapé.The parser is called with ParseReason.MemberSelect or ParseReason.MemberSelectAndHighlightBraces when a member select character is typed. L’emplacement indiqué le ParseRequest objet est immédiatement une fois que le membre sélectionné caractère.The location given in the ParseRequest object is immediately after the member select character. L’analyseur doit collecter les noms de tous les membres qui peuvent apparaître dans une liste des membres à ce moment précis dans le code source.The parser must collect the names of all members that can appear in a member list at that particular point in the source code. Puis l’analyseur doit analyser la ligne actuelle pour déterminer la portée de que l’utilisateur veut associé avec le caractère de sélection de membre.Then the parser must parse the current line to determine the scope the user wants associated with the member select character.

Cette étendue est basée sur le type de l’identificateur avant que le membre Sélectionnez caractère.This scope is based on the type of the identifier before the member select character. Par exemple, en c#, étant donné la variable membre languageService qui a un type de LanguageService, en tapant languageService.For example, in C#, given the member variable languageService that has a type of LanguageService, typing languageService. génère une liste de tous les membres de la LanguageService classe.produces a list of all the members of the LanguageService class. Également dans c#, en tapant cela.Also in C#, typing this. génère une liste de tous les membres de la classe dans la portée actuelle.produces a list of all the members of the class in the current scope.

Exemple de l’analyseurParser example

L’exemple suivant montre comment remplir un Declarations liste.The following example shows one way to populate a Declarations list. Ce code part du principe que l’analyseur construit une déclaration et l’ajoute à la liste en appelant un AddDeclaration méthode sur le TestAuthoringScope classe.This code assumes that the parser constructs a declaration and adds it to the list by calling an AddDeclaration method on the TestAuthoringScope class.

using System.Collections;
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.TextManager.Interop;

namespace TestLanguagePackage
{
    internal class TestDeclaration
    {
        public string Name;            // Name of declaration
        public int     TypeImageIndex; // Glyph index
        public string Description;     // Description of declaration

        public TestDeclaration(string name, int typeImageIndex, string description)
        {
            this.Name = name;
            this.TypeImageIndex = typeImageIndex;
            this.Description = description;
        }
    }

    //===================================================
    internal class TestDeclarations : Declarations
    {
        private ArrayList declarations;

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

        public void AddDeclaration(TestDeclaration declaration)
        {
            declarations.Add(declaration);
        }

        //////////////////////////////////////////////////////////////////////
        // Declarations of class methods that must be implemented.
        public override int GetCount()
        {
            // Return the number of declarations to show.
            return declarations.Count;
        }

        public override string GetDescription(int index)
        {
            // Return the description of the specified item.
            string description = "";
            if (index >= 0 && index < declarations.Count)
            {
                description = ((TestDeclaration)declarations[index]).Description;
            }
            return description;
        }

        public override string GetDisplayText(int index)
        {
            // Determine what is displayed in the tool tip list.
            string text = null;
            if (index >= 0 && index < declarations.Count)
            {
                text = ((TestDeclaration)declarations[index]).Name;
            }
            return text;
        }

        public override int GetGlyph(int index)
        {
            // Return index of image to display next to the display text.
            int imageIndex = -1;
            if (index >= 0 && index < declarations.Count)
            {
                imageIndex = ((TestDeclaration)declarations[index]).TypeImageIndex;
            }
            return imageIndex;
        }

        public override string GetName(int index)
        {
            string name = null;
            if (index >= 0 && index < declarations.Count)
            {
                name = ((TestDeclaration)declarations[index]).Name;
            }
            return name;
        }
    }

    //===================================================
    public class TestAuthoringScope : AuthoringScope
    {
        private TestDeclarations declarationsList;

        public void AddDeclaration(TestDeclaration declaration)
        {
            if (declaration != null)
            {
                if (declarationsList == null)
                {
                    declarationsList = new TestDeclarations();
                }
                declarationsList.AddDeclaration(declaration);
            }
        }

        public override Declarations GetDeclarations(IVsTextView view,
                                                     int line,
                                                     int col,
                                                     TokenInfo info,
                                                     ParseReason reason)
        {
            return declarationsList;
        }

        /////////////////////////////////////////////////
        // Remainder of AuthoringScope methods not shown.
        /////////////////////////////////////////////////
    }

    //===================================================
    class TestLanguageService : LanguageService
    {
        public override AuthoringScope ParseSource(ParseRequest req)
        {
            TestAuthoringScope scope = new TestAuthoringScope();
            if (req.Reason == ParseReason.MemberSelect ||
                req.Reason == ParseReason.MemberSelectAndHighlightBraces)
            {
                // Gather list of declarations based on what the user
                // has typed so far. In this example, this list is an array of
                // MemberDeclaration objects (a helper class you might implement
                // to hold member declarations).
                // How this list is gathered is dependent on the parser
                // and is not shown here.
                MemberDeclarations memberDeclarations;
                memberDeclarations = GetDeclarationsForScope();

                // Now populate the Declarations list in the authoring scope.
                // GetImageIndexBasedOnType() is a helper method you
                // might implement to convert a member type to an index into
                // the image list returned from the language service.
                foreach (MemberDeclaration dec in memberDeclarations)
                {
                    scope.AddDeclaration(new TestDeclaration(
                                             dec.Name,
                                             GetImageIndexBasedOnType(dec.Type),
                                             dec.Description));
                }
            }
            return scope;
        }
    }
}