Создание прогнозатора командной строки
PSReadLine 2.1.0 представила концепцию интеллектуального прогнозатора командной строки, реализуя функцию Predictive IntelliSense. PSReadLine 2.2.2 расширил эту функцию, добавив плагиновую модель, которая позволяет создавать собственные прогнозаторы командной строки.
Прогнозная функция IntelliSense улучшает завершение вкладки, предоставляя предложения в командной строке по мере ввода. Предложение прогнозирования отображается как цветной текст после курсора. Это позволяет обнаруживать, изменять и выполнять полные команды на основе предсказаний из журнала команд или дополнительных плагинов для конкретного домена.
Требования к системе
Чтобы создать и использовать прогнозатор подключаемых модулей, необходимо использовать следующие версии программного обеспечения:
- PowerShell 7.2 (или более поздней версии) предоставляет API, необходимые для создания прогнозатора команд.
- PSReadLine 2.2.2 (или более поздней версии) позволяет настроить PSReadLine для использования плагина.
Обзор прогнозатора
Прогнозатор — это двоичный модуль PowerShell. Модуль должен реализовать интерфейс System.Management.Automation.Subsystem.Prediction.ICommandPredictor
. Этот интерфейс объявляет методы, используемые для запроса результатов прогнозирования и предоставления отзывов.
Модуль прогнозировщика должен зарегистрировать подсистему CommandPredictor
в компоненте SubsystemManager
PowerShell при загрузке и отменить регистрацию при выгрузке.
На следующей схеме показана архитектура прогнозатора в PowerShell.
архитектура
Создание кода
Чтобы создать прогнозатор, необходимо установить пакет SDK для .NET 6 для своей платформы. Дополнительные сведения о пакете SDK см. в статье Скачать.NET 6.0.
Создайте проект модуля PowerShell, выполнив следующие действия.
Используйте средство командной строки
dotnet
для создания начального проекта classlib.dotnet new classlib --name SamplePredictor
Измените
SamplePredictor.csproj
, чтобы содержать следующие сведения:<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.0" /> </ItemGroup> </Project>
Удалите файл
Class1.cs
по умолчанию, созданныйdotnet
, и скопируйте следующий код в файлSamplePredictorClass.cs
в папку проекта.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)); } } }
В следующем примере кода для всех пользовательских данных возвращается текстовая строка "HELLO WORLD" в качестве результата предсказания. Так как пример прогнозатора не обрабатывает никаких отзывов, код не реализует методы обратной связи из интерфейса. Измените код прогнозирования и обратной связи в соответствии с потребностями прогнозатора.
Заметка
Представление списка PSReadLine не поддерживает многостроочные предложения. Каждое предложение должно быть одной строкой. Если в вашем коде есть многострочное предложение, следует разделить строки на отдельные предложения или объединить их посредством точки с запятой (
;
).Запустите
dotnet build
для создания сборки. Скомпилированную сборку можно найти вbin/Debug/net6.0
расположении папки проекта.Заметка
Чтобы обеспечить быстрый пользовательский интерфейс, интерфейс ICommandPredictor имеет время ожидания 20 мс для ответов от прогнозаторов. Код прогнозатора должен возвращать результаты менее чем за 20 мс, чтобы быть отображённым.
Использование подключаемого модуля прогнозатора
Чтобы попробовать новый прогнозатор, откройте новый сеанс PowerShell 7.2 и выполните следующие команды:
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Import-Module .\bin\Debug\net6.0\SamplePredictor.dll
Когда сборка загружается в сеансе, в процессе ввода в терминале появляется текст "HELLO WORLD". Чтобы переключиться между представлением Inline
и представлением List
, нажмите клавишу F2 F2.
Дополнительные сведения о параметрах PSReadLine см. в разделе Set-PSReadLineOption.
Список установленных прогнозаторов можно получить с помощью следующей команды:
Get-PSSubsystem -Kind CommandPredictor
Kind SubsystemType IsRegistered Implementations
---- ------------- ------------ ---------------
CommandPredictor ICommandPredictor True {SamplePredictor}
Заметка
Get-PSSubsystem
является экспериментальным командлетом, представленным в PowerShell 7.1, необходимо включить экспериментальную функцию PSSubsystemPluginModel
для использования этого командлета. Дополнительные сведения см. в разделе Использование экспериментальных функций.
PowerShell