Búsqueda de sitios web

Cómo crear un predictor de línea de comandos


PSReadLine 2.1.0 introdujo el concepto de un predictor de línea de comandos inteligente mediante la implementación de la función Predictive IntelliSense. PSReadLine 2.2.2 amplió esa característica agregando un modelo de complemento que le permite crear sus propios predictores de línea de comandos.

Predictive IntelliSense mejora la finalización de pestañas al proporcionar sugerencias, en la línea de comando, a medida que escribe. La sugerencia de predicción aparece como texto en color después del cursor. Esto le permite descubrir, editar y ejecutar comandos completos basados en predicciones coincidentes de su historial de comandos o complementos adicionales específicos del dominio.

Requisitos del sistema

Para crear y utilizar un predictor de complemento, debe utilizar las siguientes versiones de software:

  • PowerShell 7.2 (o superior): proporciona las API necesarias para crear un predictor de comandos
  • PSReadLine 2.2.2 (o superior): le permite configurar PSReadLine para usar el complemento

Descripción general de un predictor

Un predictor es un módulo binario de PowerShell. El módulo debe implementar la interfaz System.Management.Automation.Subsystem.Prediction.ICommandPredictor. Esta interfaz declara los métodos utilizados para consultar los resultados de la predicción y proporcionar comentarios.

Un módulo predictor debe registrar un subsistema CommandPredictor con SubsystemManager de PowerShell cuando se carga y cancelar su registro cuando se descarga.

El siguiente diagrama muestra la arquitectura de un predictor en PowerShell.

Creando el código

Para crear un predictor, debe tener instalado el SDK de .NET 6 para su plataforma. Para obtener más información sobre el SDK, consulte Descargar .NET 6.0.

Cree un nuevo proyecto de módulo de PowerShell siguiendo estos pasos:

  1. Utilice la herramienta de línea de comandos dotnet para crear un proyecto classlib inicial.

    dotnet new classlib --name SamplePredictor
    
  2. Edite SamplePredictor.csproj para que contenga la siguiente información:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.0" />
      </ItemGroup>
    
    </Project>
    
  3. Elimine el archivo Class1.cs predeterminado creado por dotnet y copie el siguiente código en un archivo SamplePredictorClass.cs en la carpeta de su proyecto.

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

    El siguiente código de ejemplo devuelve la cadena "HELLO WORLD" para el resultado de la predicción de todas las entradas del usuario. Dado que el predictor de muestra no procesa ninguna retroalimentación, el código no implementa los métodos de retroalimentación desde la interfaz. Cambie el código de predicción y retroalimentación para satisfacer las necesidades de su predictor.

    Nota

    La vista de lista de PSReadLine no admite sugerencias de varias líneas. Cada sugerencia debe ser una sola línea. Si su código tiene una sugerencia de varias líneas, debe dividir las líneas en sugerencias separadas o unir las líneas con un punto y coma (;).

  4. Ejecute dotnet build para producir el ensamblaje. Puede encontrar el ensamblado compilado en la ubicación bin/Debug/net6.0 de la carpeta de su proyecto.

    Nota

    Para garantizar una experiencia de usuario receptiva, la interfaz ICommandPredictor tiene un tiempo de espera de 20 ms para las respuestas de los Predictores. Su código de predicción debe devolver resultados en menos de 20 ms para que se muestre.

Usando su complemento predictor

Para probar su nuevo predictor, abra una nueva sesión de PowerShell 7.2 y ejecute los siguientes comandos:

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

Con el ensamblaje cargado en la sesión, verá aparecer el texto "HOLA MUNDO" a medida que escribe en la terminal. Puede presionar F2 para cambiar entre la vista Inline y la vista Lista.

Para obtener más información sobre las opciones de PSReadLine, consulte Set-PSReadLineOption.

Puede obtener una lista de predictores instalados utilizando el siguiente comando:

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

Nota

Get-PSSubsystem es un cmdlet experimental que se introdujo en PowerShell 7.1. Debe habilitar la característica experimental PSSubsystemPluginModel para usar este cmdlet. Para obtener más información, consulte Uso de funciones experimentales.

Artículos relacionados