Condividi tramite


Come creare un predictor della riga di comando

PSReadLine 2.1.0 ha introdotto il concetto di predictor della riga di comando intelligente implementando la funzionalità Predittiva intelliSense. PSReadLine 2.2.2 espanso su tale funzionalità aggiungendo un modello di plug-in che consente di creare i propri predittori della riga di comando.

IntelliSense predittivo migliora il completamento delle schede fornendo suggerimenti, nella riga di comando, durante la digitazione. Il suggerimento di stima viene visualizzato come testo colorato dopo il cursore. In questo modo è possibile individuare, modificare ed eseguire comandi completi in base alle stime corrispondenti dalla cronologia dei comandi o da plug-in specifici del dominio aggiuntivi.

Requisiti di sistema

Per creare e usare un predictor plug-in, è necessario usare le versioni seguenti del software:

  • PowerShell 7.2 (o versione successiva): fornisce le API necessarie per la creazione di un predictor dei comandi
  • PSReadLine 2.2.2 (o versione successiva): consente di configurare PSReadLine per l'uso del plug-in

Panoramica di un predictor

Un predictor è un modulo binario di PowerShell. Il modulo deve implementare l'interfaccia System.Management.Automation.Subsystem.Prediction.ICommandPredictor . Questa interfaccia dichiara i metodi usati per eseguire query sui risultati della stima e fornire feedback.

Un modulo predictor deve registrare un CommandPredictor sottosistema con PowerShell SubsystemManager quando viene caricato e annulla la registrazione quando viene scaricato.

Il diagramma seguente illustra l'architettura di un predictor in PowerShell.

Architettura

Creazione del codice

Per creare un predictor, è necessario che .NET 6 SDK sia installato per la piattaforma. Per altre informazioni sull'SDK, vedere Scaricare .NET 6.0.

Creare un nuovo progetto di modulo di PowerShell seguendo questa procedura:

  1. Usare lo strumento da dotnet riga di comando per creare un progetto classlib iniziale.

    dotnet new classlib --name SamplePredictor
    
  2. Modificare per SamplePredictor.csproj contenere le informazioni seguenti:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.0" />
      </ItemGroup>
    
    </Project>
    
  3. Eliminare il file predefinito Class1.cs creato da dotnet e copiare il codice seguente in un SamplePredictorClass.cs file nella cartella del progetto.

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

    Il codice di esempio seguente restituisce la stringa "HELLO WORLD" per il risultato della stima per tutti gli input dell'utente. Poiché il predictor di esempio non elabora alcun feedback, il codice non implementa i metodi di feedback dall'interfaccia. Modificare il codice di previsione e feedback per soddisfare le esigenze del predictor.

    Nota

    La visualizzazione elenco di PSReadLine non supporta i suggerimenti su più righe. Ogni suggerimento deve essere una singola riga. Se il codice include un suggerimento su più righe, è necessario suddividere le righe in suggerimenti separati o unire le righe con un punto e virgola (;).

  4. Eseguire dotnet build per produrre l'assembly. È possibile trovare l'assembly compilato nel bin/Debug/net6.0 percorso della cartella del progetto.

    Nota

    Per garantire un'esperienza utente reattiva, l'interfaccia ICommandPredictor ha un timeout di 20 ms per le risposte dei predictor. Il codice del predictor deve restituire risultati inferiori a 20 ms da visualizzare.

Uso del plug-in predictor

Per provare il nuovo predictor, aprire una nuova sessione di PowerShell 7.2 ed eseguire i comandi seguenti:

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

Quando l'assembly viene caricato nella sessione, viene visualizzato il testo "HELLO WORLD" durante la digitazione nel terminale. È possibile premere F2 per passare dalla Inline visualizzazione alla List visualizzazione.

Per altre informazioni sulle opzioni PSReadLine, vedere Set-PSReadLineOption.

È possibile ottenere un elenco di predittori installati usando il comando seguente:

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

Nota

Get-PSSubsystem è un cmdlet sperimentale introdotto in PowerShell 7.1 Per usare questo cmdlet, è necessario abilitare la PSSubsystemPluginModel funzionalità sperimentale. Per altre informazioni, vedere Uso delle funzionalità sperimentali.