명령줄 예측자를 만드는 방법
PSReadLine 2.1.0에서는 예측 IntelliSense 기능을 구현하여 스마트 명령줄 예측 변수의 개념을 도입했습니다. PSReadLine 2.2.2는 고유한 명령줄 예측 변수를 만들 수 있는 플러그 인 모델을 추가하여 해당 기능을 확장했습니다.
Predictive IntelliSense는 명령줄에 입력하는 동안 제안을 제공하여 탭 완성을 향상시킵니다. 예측 제안은 커서 뒤에 색이 지정된 텍스트로 나타납니다. 이렇게 하면 명령 기록 또는 추가 도메인별 플러그 인에서 일치하는 예측을 기반으로 전체 명령을 검색, 편집 및 실행할 수 있습니다.
시스템 요구 사항
플러그 인 예측자를 만들고 사용하려면 다음 버전의 소프트웨어를 사용해야 합니다.
- PowerShell 7.2 이상 - 명령 예측자를 만드는 데 필요한 API를 제공합니다.
- PSReadLine 2.2.2 이상 - 플러그 인을 사용하도록 PSReadLine을 구성할 수 있습니다.
예측자 개요
Predictor는 PowerShell 바이너리 모듈입니다. 모듈은 System.Management.Automation.Subsystem.Prediction.ICommandPredictor
인터페이스를 구현해야 합니다. 이 인터페이스는 예측 결과를 쿼리하고 피드백을 제공하는 데 사용되는 메서드를 선언합니다.
예측 모듈은 로드될 때 CommandPredictor
하위 시스템을 PowerShell의 SubsystemManager
에 등록해야 하며, 언로드될 때 등록을 취소해야 합니다.
다음 다이어그램은 PowerShell에서 예측자의 아키텍처를 보여줍니다.
코드 만들기
예측자를 만들려면 플랫폼에 .NET 6 SDK가 설치되어 있어야 합니다. 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>
dotnet
만든 기본Class1.cs
파일을 삭제하고 다음 코드를 프로젝트 폴더의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 인터페이스는 예측 변수의 응답에 대해 20ms의 시간 초과를 갖습니다. 예측 코드는 20ms 미만의 결과를 반환하여 표시해야 합니다.
예측 플러그 인 사용
새 예측자를 사용해 보려면 새 PowerShell 7.2 세션을 열고 다음 명령을 실행합니다.
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Import-Module .\bin\Debug\net6.0\SamplePredictor.dll
어셈블리가 세션에 로드되면 터미널에 입력할 때 "HELLO WORLD" 텍스트가 표시됩니다.
F2 눌러 Inline
보기와 List
보기 간에 전환할 수 있습니다.
PSReadLine 옵션에 대한 자세한 내용은 Set-PSReadLineOption참조하세요.
다음 명령을 사용하여 설치된 예측 변수 목록을 가져올 수 있습니다.
Get-PSSubsystem -Kind CommandPredictor
Kind SubsystemType IsRegistered Implementations
---- ------------- ------------ ---------------
CommandPredictor ICommandPredictor True {SamplePredictor}
메모
Get-PSSubsystem
PowerShell 7.1에서 도입된 실험적 cmdlet입니다. 이 cmdlet을 사용하려면 PSSubsystemPluginModel
실험적 기능을 사용하도록 설정해야 합니다. 자세한 내용은 의실험적 기능 사용을 참조하세요.
PowerShell