Partager via


Guide pratique pour créer un module de prédiction de ligne de commande

La version 2.1.0 de PSReadLine a introduit le concept de module intelligent de prédiction de ligne de commande en implémentant la fonctionnalité Predictive IntelliSense. La version 2.2.2 a développé cette fonctionnalité en ajoutant un modèle de plug-in qui vous permet de créer vos propres modules de prédiction de ligne de commande.

La fonctionnalité Predictive IntelliSense améliore la saisie semi-automatique par tabulation en formulant des suggestions, en ligne de commande, au fur et à mesure que vous tapez. La suggestion de prédiction apparaît sous forme de texte coloré à la suite de votre curseur. Cela vous permet de découvrir, de modifier et d’exécuter des commandes complètes basées sur des prédictions en correspondance avec votre historique de commandes ou d’autres plug-ins propres à un domaine.

Configuration système requise

Pour créer et utiliser un module de prédiction de plug-in, vous devez utiliser les versions logicielles suivantes :

  • Version 7.2 ou plus récente de PowerShell : fournit les API nécessaires à la création d’un module de prédiction de commande.
  • Version 2.2.2 ou plus récente de PSReadLine : vous permet de configurer PSReadLine de façon à utiliser le plug-in.

Vue d’ensemble d’un module de prédiction

Un module de prédiction est un module PowerShell binaire. Il doit implémenter l’interface System.Management.Automation.Subsystem.Prediction.ICommandPredictor. Cette interface déclare les méthodes utilisées pour interroger les résultats de prédiction et formuler des commentaires.

Un module de prédiction doit inscrire un sous-système CommandPredictor auprès du SubsystemManager de PowerShell lorsqu’il est chargé, et se désinscrire lorsqu’il est déchargé.

Le diagramme suivant illustre l’architecture d’un module de prédiction dans PowerShell.

Architecture

Création du code

Pour créer un module de prédiction, la version 6 du kit de développement logiciel (SDK, Software Development Kit) .NET doit être installée pour votre plateforme. Pour plus d’informations sur le kit SDK, consultez Téléchargement de .NET 6.0.

Créez un projet de module PowerShell en procédant comme suit :

  1. Utilisez l’outil en ligne de commande dotnet pour créer un projet classlib de démarrage.

    dotnet new classlib --name SamplePredictor
    
  2. Modifiez SamplePredictor.csproj de sorte qu’il contienne les informations suivantes :

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.0" />
      </ItemGroup>
    
    </Project>
    
  3. Supprimez le fichier Class1.cs par défaut créé par dotnet et copiez le code suivant dans un fichier SamplePredictorClass.cs au sein de votre dossier de projet.

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Management.Automation;
    using System.Management.Automation.Subsystem;
    using System.Management.Automation.Subsystem.Prediction;
    
    namespace PowerShell.Sample
    {
        public class SamplePredictor : ICommandPredictor
        {
            private readonly Guid _guid;
    
            internal SamplePredictor(string guid)
            {
                _guid = new Guid(guid);
            }
    
            /// <summary>
            /// Gets the unique identifier for a subsystem implementation.
            /// </summary>
            public Guid Id => _guid;
    
            /// <summary>
            /// Gets the name of a subsystem implementation.
            /// </summary>
            public string Name => "SamplePredictor";
    
            /// <summary>
            /// Gets the description of a subsystem implementation.
            /// </summary>
            public string Description => "A sample predictor";
    
            /// <summary>
            /// Get the predictive suggestions. It indicates the start of a suggestion rendering session.
            /// </summary>
            /// <param name="client">Represents the client that initiates the call.</param>
            /// <param name="context">The <see cref="PredictionContext"/> object to be used for prediction.</param>
            /// <param name="cancellationToken">The cancellation token to cancel the prediction.</param>
            /// <returns>An instance of <see cref="SuggestionPackage"/>.</returns>
            public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken)
            {
                string input = context.InputAst.Extent.Text;
                if (string.IsNullOrWhiteSpace(input))
                {
                    return default;
                }
    
                return new SuggestionPackage(new List<PredictiveSuggestion>{
                    new PredictiveSuggestion(string.Concat(input, " HELLO WORLD"))
                });
            }
    
            #region "interface methods for processing feedback"
    
            /// <summary>
            /// Gets a value indicating whether the predictor accepts a specific kind of feedback.
            /// </summary>
            /// <param name="client">Represents the client that initiates the call.</param>
            /// <param name="feedback">A specific type of feedback.</param>
            /// <returns>True or false, to indicate whether the specific feedback is accepted.</returns>
            public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback) => false;
    
            /// <summary>
            /// One or more suggestions provided by the predictor were displayed to the user.
            /// </summary>
            /// <param name="client">Represents the client that initiates the call.</param>
            /// <param name="session">The mini-session where the displayed suggestions came from.</param>
            /// <param name="countOrIndex">
            /// When the value is greater than 0, it's the number of displayed suggestions from the list
            /// returned in <paramref name="session"/>, starting from the index 0. When the value is
            /// less than or equal to 0, it means a single suggestion from the list got displayed, and
            /// the index is the absolute value.
            /// </param>
            public void OnSuggestionDisplayed(PredictionClient client, uint session, int countOrIndex) { }
    
            /// <summary>
            /// The suggestion provided by the predictor was accepted.
            /// </summary>
            /// <param name="client">Represents the client that initiates the call.</param>
            /// <param name="session">Represents the mini-session where the accepted suggestion came from.</param>
            /// <param name="acceptedSuggestion">The accepted suggestion text.</param>
            public void OnSuggestionAccepted(PredictionClient client, uint session, string acceptedSuggestion) { }
    
            /// <summary>
            /// A command line was accepted to execute.
            /// The predictor can start processing early as needed with the latest history.
            /// </summary>
            /// <param name="client">Represents the client that initiates the call.</param>
            /// <param name="history">History command lines provided as references for prediction.</param>
            public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList<string> history) { }
    
            /// <summary>
            /// A command line was done execution.
            /// </summary>
            /// <param name="client">Represents the client that initiates the call.</param>
            /// <param name="commandLine">The last accepted command line.</param>
            /// <param name="success">Shows whether the execution was successful.</param>
            public void OnCommandLineExecuted(PredictionClient client, string commandLine, bool success) { }
    
            #endregion;
        }
    
        /// <summary>
        /// Register the predictor on module loading and unregister it on module un-loading.
        /// </summary>
        public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup
        {
            private const string Identifier = "843b51d0-55c8-4c1a-8116-f0728d419306";
    
            /// <summary>
            /// Gets called when assembly is loaded.
            /// </summary>
            public void OnImport()
            {
                var predictor = new SamplePredictor(Identifier);
                SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor, predictor);
            }
    
            /// <summary>
            /// Gets called when the binary module is unloaded.
            /// </summary>
            public void OnRemove(PSModuleInfo psModuleInfo)
            {
                SubsystemManager.UnregisterSubsystem(SubsystemKind.CommandPredictor, new Guid(Identifier));
            }
        }
    }
    

    L’exemple de code suivant retourne la chaîne « HELLO WORLD » comme résultat de prédiction pour toutes les entrées utilisateur. Étant donné que l’exemple de module de prédiction ne traite aucun commentaire, le code n’implémente pas les méthodes de commentaires de l’interface. Modifiez le code de prédiction et de commentaires pour répondre aux besoins de votre module de prédiction.

    Notes

    La vue Liste de PSReadLine ne prend pas en charge les suggestions multilignes. Chaque suggestion doit être constituée d’une seule ligne. Si votre code comporte une suggestion multiligne, vous devez diviser les lignes en suggestions distinctes ou joindre les lignes avec un point-virgule (;).

  4. Exécutez dotnet build pour produire l’assembly. L’assembly compilé se trouve à l’emplacement bin/Debug/net6.0 dans votre dossier de projet.

    Notes

    Pour garantir une expérience utilisateur réactive, l’interface ICommandPredictor a une expiration du délai d’attente de 20 ms pour les réponses des prédicteurs. Le code de votre prédicteur doit retourner des résultats en moins de 20 ms pour être affiché.

Utilisation du plug-in de prédiction

Pour tester votre nouveau module de prédiction, ouvrez une nouvelle session PowerShell 7.2 et exécutez les commandes suivantes :

Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Import-Module .\bin\Debug\net6.0\SamplePredictor.dll

Une fois l’assembly chargé dans la session, le texte « HELLO WORLD » s’affiche à mesure que vous tapez dans le terminal. Appuyez sur F2 pour basculer entre la vue Inline et la vue List.

Pour plus d’informations sur les options PSReadLine, consultez Set-PSReadLineOption.

Pour afficher la liste des modules de prédiction installés, utilisez la commande suivante :

Get-PSSubsystem -Kind CommandPredictor
Kind              SubsystemType      IsRegistered Implementations
----              -------------      ------------ ---------------
CommandPredictor  ICommandPredictor          True {SamplePredictor}

Notes

Get-PSSubsystem est une cmdlet expérimentale introduite dans PowerShell 7.1. Vous devez activer la fonctionnalité expérimentale PSSubsystemPluginModel pour utiliser cette cmdlet. Pour plus d’informations, consultez Utilisation des fonctionnalités expérimentales.