Sdílet prostřednictvím


Vytvoření prediktoru příkazového řádku

PSReadLine 2.1.0 představil koncept prediktivního inteligentního příkazového řádku pomocí implementace funkce IntelliSense. PSReadLine 2.2.2 rozšířil na tuto funkci přidáním modelu plug-in, který umožňuje vytvářet vlastní prediktory příkazového řádku.

Prediktivní IntelliSense vylepšuje dokončování tabulátoru tím, že při psaní poskytuje návrhy na příkazovém řádku. Návrh předpovědi se zobrazí jako barevný text za kurzorem. To umožňuje zjišťovat, upravovat a spouštět úplné příkazy na základě odpovídajících předpovědí z historie příkazů nebo dalších modulů plug-in specifických pro doménu.

Požadavky na systém

Pokud chcete vytvořit a použít prediktor modulu plug-in, musíte používat následující verze softwaru:

  • PowerShell 7.2 (nebo vyšší) – poskytuje rozhraní API potřebná k vytvoření prediktoru příkazů.
  • PSReadLine 2.2.2 (nebo vyšší) – umožňuje nakonfigurovat PSReadLine tak, aby používal modul plug-in.

Přehled prediktoru

Prediktor je binární modul PowerShellu. Modul musí implementovat rozhraní System.Management.Automation.Subsystem.Prediction.ICommandPredictor. Toto rozhraní deklaruje metody použité k dotazování na výsledky předpovědi a poskytnutí zpětné vazby.

Modul prediktoru musí zaregistrovat subsystém CommandPredictor v SubsystemManager PowerShellu při načtení a odregistrovat se při vyložení.

Následující diagram znázorňuje architekturu prediktoru v PowerShellu.

architektura

Vytvoření kódu

Pokud chcete vytvořit prediktor, musíte mít nainstalovanou sadu .NET 6 SDK pro vaši platformu. Další informace o sadě SDK naleznete v tématu Stáhnout .NET 6.0.

Následujícím postupem vytvořte nový projekt modulu PowerShellu:

  1. Pomocí nástroje příkazového řádku dotnet vytvořte počáteční projekt knihovny tříd.

    dotnet new classlib --name SamplePredictor
    
  2. Upravte SamplePredictor.csproj tak, aby obsahoval následující informace:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.0" />
      </ItemGroup>
    
    </Project>
    
  3. Odstraňte výchozí soubor Class1.cs vytvořený dotnet a zkopírujte následující kód do souboru SamplePredictorClass.cs ve složce projektu.

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

    Následující příklad kódu vrátí řetězec "HELLO WORLD" jako výsledek předpovědi pro každý uživatelský vstup. Vzhledem k tomu, že predikátor vzorku nezpracuje žádnou zpětnou vazbu, kód neimplementuje metody zpětné vazby z rozhraní. Změňte kód předpovědi a zpětné vazby tak, aby vyhovoval potřebám prediktoru.

    Poznámka

    Zobrazení seznamu psReadLine nepodporuje víceřádkové návrhy. Každý návrh by měl být jeden řádek. Pokud má váš kód víceřádkový návrh, měli byste řádky rozdělit do samostatných návrhů nebo je spojit středníkem (;).

  4. Spuštěním dotnet build vytvořte sestavení. Kompilované sestavení najdete v umístění bin/Debug/net6.0 ve složce projektu.

    Poznámka

    Pro zajištění responzivního uživatelského prostředí má rozhraní ICommandPredictor časový limit 20 ms pro odpovědi z prediktorů. Aby se výsledky zobrazily, kód prediktoru musí vrátit výsledky za méně než 20 ms.

Použití zásuvného modulu Predictor

Pokud chcete vyzkoušet nový prediktor, otevřete novou relaci PowerShellu 7.2 a spusťte následující příkazy:

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

Když je v relaci načteno sestavení, během psaní v terminálu se zobrazí text „HELLO WORLD“. Stisknutím klávesy F2 můžete přepínat mezi zobrazením Inline a zobrazením List.

Další informace o možnostech PSReadLine naleznete v tématu Set-PSReadLineOption.

Seznam nainstalovaných prediktorů můžete získat pomocí následujícího příkazu:

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

Poznámka

Get-PSSubsystem je experimentální rutina, která byla zavedena v PowerShellu 7.1. Pokud chcete tuto rutinu použít, musíte povolit PSSubsystemPluginModel experimentální funkci. Další informace najdete v tématu Používání experimentálních funkcí.