From 4b545cad1f496f65244c9f43aa948536f70f277d Mon Sep 17 00:00:00 2001
From: dkattan <1424395+dkattan@users.noreply.github.com>
Date: Thu, 24 Mar 2022 15:16:40 -0500
Subject: [PATCH 1/3] Added a -UseHostReadKey switch to instruct LegacyReadLine
to use the ReadKey provided by the host instead of Console.ReadKey
---
.../Start-EditorServices.ps1 | 11 ++--
.../Commands/StartEditorServicesCommand.cs | 11 +++-
.../Configuration/EditorServicesConfig.cs | 9 ++-
.../EditorServicesLoader.cs | 4 +-
.../Internal/EditorServicesRunner.cs | 1 +
.../Hosting/HostStartupInfo.cs | 8 ++-
.../PowerShell/Console/LegacyReadLine.cs | 17 +++--
.../PowerShell/Console/PsrlReadLine.cs | 14 ++++-
.../PowerShell/Console/TerminalReadLine.cs | 2 +
...orServicesConsolePSHostRawUserInterface.cs | 52 +++++++++++++--
...ditorServicesConsolePSHostUserInterface.cs | 9 ++-
.../PowerShell/Host/PsesInternalHost.cs | 63 ++++++++++++++++++-
12 files changed, 173 insertions(+), 28 deletions(-)
diff --git a/module/PowerShellEditorServices/Start-EditorServices.ps1 b/module/PowerShellEditorServices/Start-EditorServices.ps1
index 47ba523c2..9721cf536 100644
--- a/module/PowerShellEditorServices/Start-EditorServices.ps1
+++ b/module/PowerShellEditorServices/Start-EditorServices.ps1
@@ -52,10 +52,10 @@ param(
[ValidateSet("Diagnostic", "Verbose", "Normal", "Warning", "Error")]
$LogLevel,
- [Parameter(Mandatory=$true)]
- [ValidateNotNullOrEmpty()]
- [string]
- $SessionDetailsPath,
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $SessionDetailsPath,
[switch]
$EnableConsoleRepl,
@@ -63,6 +63,9 @@ param(
[switch]
$UseLegacyReadLine,
+ [switch]
+ $UseHostReadKey,
+
[switch]
$DebugServiceOnly,
diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
index 3d31ede06..599b14662 100644
--- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
+++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
@@ -161,6 +161,12 @@ public StartEditorServicesCommand()
[Parameter]
public SwitchParameter UseLegacyReadLine { get; set; }
+ ///
+ /// When set and the console is enabled and legacy readline
+ /// is enabled, console operations will use PSHostreadline implementation will be used instead of PSReadLine.
+ ///
+ [Parameter]
+ public SwitchParameter UseHostReadKey { get; set; }
///
/// When set, do not enable LSP service, only the debug adapter.
///
@@ -345,8 +351,9 @@ private EditorServicesConfig CreateConfigObject()
hostInfo,
Host,
SessionDetailsPath,
- bundledModulesPath,
- LogPath)
+ bundledModulesPath,
+ LogPath,
+ UseHostReadKey)
{
FeatureFlags = FeatureFlags,
LogLevel = LogLevel,
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
index f8b6ef30f..81c70dd3e 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
@@ -17,7 +17,7 @@ public enum ConsoleReplKind
/// Use a REPL with the legacy readline implementation. This is generally used when PSReadLine is unavailable.
LegacyReadLine = 1,
/// Use a REPL with the PSReadLine module for console interaction.
- PSReadLine = 2,
+ PSReadLine = 2
}
///
@@ -39,13 +39,15 @@ public EditorServicesConfig(
PSHost psHost,
string sessionDetailsPath,
string bundledModulePath,
- string logPath)
+ string logPath,
+ bool useHostReadKey)
{
HostInfo = hostInfo;
PSHost = psHost;
SessionDetailsPath = sessionDetailsPath;
BundledModulePath = bundledModulePath;
LogPath = logPath;
+ UseHostReadKey = useHostReadKey;
}
///
@@ -72,6 +74,7 @@ public EditorServicesConfig(
/// The path to use for logging for Editor Services.
///
public string LogPath { get; }
+ public bool UseHostReadKey { get; }
///
/// Names of or paths to any additional modules to load on startup.
@@ -88,7 +91,7 @@ public EditorServicesConfig(
/// (including none to disable the integrated console).
///
public ConsoleReplKind ConsoleRepl { get; set; } = ConsoleReplKind.None;
-
+
///
/// The minimum log level to log events with.
///
diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
index 924619283..204de1b55 100644
--- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
+++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
@@ -107,12 +107,12 @@ public static EditorServicesLoader Create(
// We only want the Editor Services DLL; the new ALC will lazily load its dependencies automatically
if (!string.Equals(asmName.Name, "Microsoft.PowerShell.EditorServices", StringComparison.Ordinal))
{
- return null;
+ //return null;
}
string asmPath = Path.Combine(s_psesDependencyDirPath, $"{asmName.Name}.dll");
- logger.Log(PsesLogLevel.Verbose, "Loading PSES DLL using new assembly load context");
+ logger.Log(PsesLogLevel.Verbose, $"Loading {asmName.Name}.dll using new assembly load context");
return psesLoadContext.LoadFromAssemblyPath(asmPath);
};
diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
index 3e6626f20..d7743b96a 100644
--- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
+++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
@@ -290,6 +290,7 @@ private HostStartupInfo CreateHostStartupInfo()
(int)_config.LogLevel,
consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None,
usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine,
+ useHostReadKey: _config.UseHostReadKey,
bundledModulePath: _config.BundledModulePath);
}
diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
index e34df5912..d35a87b91 100644
--- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
+++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
@@ -80,7 +80,11 @@ public sealed class HostStartupInfo
/// If the console REPL is not enabled, this setting will be ignored.
///
public bool UsesLegacyReadLine { get; }
-
+ ///
+ /// If true, the legacy PSES readline implementation but calls ReadKey in the provided host
+ /// If the console REPL is not enabled, this setting will be ignored.
+ ///
+ public bool UseHostReadKey { get; }
///
/// The PowerShell host to use with Editor Services.
///
@@ -153,6 +157,7 @@ public HostStartupInfo(
int logLevel,
bool consoleReplEnabled,
bool usesLegacyReadLine,
+ bool useHostReadKey,
string bundledModulePath)
{
Name = name ?? DefaultHostName;
@@ -167,6 +172,7 @@ public HostStartupInfo(
LogLevel = logLevel;
ConsoleReplEnabled = consoleReplEnabled;
UsesLegacyReadLine = usesLegacyReadLine;
+ UseHostReadKey = useHostReadKey;
BundledModulePath = bundledModulePath;
}
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
index 39e12974b..fbc72f39f 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
@@ -24,15 +24,19 @@ internal class LegacyReadLine : TerminalReadLine
private readonly Action _onIdleAction;
+ private IConsoleOperations _consoleOperations;
+
public LegacyReadLine(
PsesInternalHost psesHost,
Func readKeyFunc,
- Action onIdleAction)
+ Action onIdleAction,
+ IConsoleOperations consoleOperations)
{
_psesHost = psesHost;
_readKeyTasks = new Task[2];
_readKeyFunc = readKeyFunc;
_onIdleAction = onIdleAction;
+ _consoleOperations = consoleOperations;
}
public override string ReadLine(CancellationToken cancellationToken)
@@ -46,12 +50,12 @@ public override string ReadLine(CancellationToken cancellationToken)
StringBuilder inputLine = new();
- int initialCursorCol = Console.CursorLeft;
- int initialCursorRow = Console.CursorTop;
+ int initialCursorCol = _consoleOperations?.GetCursorLeft(cancellationToken) ?? _psesHost.UI.RawUI.CursorPosition.X;
+ int initialCursorRow = _consoleOperations?.GetCursorTop(cancellationToken) ?? _psesHost.UI.RawUI.CursorPosition.Y; ;
int currentCursorIndex = 0;
-
- Console.TreatControlCAsInput = true;
+ if(_consoleOperations != null)
+ Console.TreatControlCAsInput = true;
try
{
@@ -63,7 +67,8 @@ public override string ReadLine(CancellationToken cancellationToken)
// because the window could have been resized before then
int promptStartCol = initialCursorCol;
int promptStartRow = initialCursorRow;
- int consoleWidth = Console.WindowWidth;
+
+ int consoleWidth = _consoleOperations is not null ? Console.WindowWidth : _psesHost.UI.RawUI.WindowSize.Width;
switch (keyInfo.Key)
{
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs
index cda3af925..b4ecd583b 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs
@@ -17,19 +17,22 @@ internal class PsrlReadLine : TerminalReadLine
private readonly PsesInternalHost _psesHost;
private readonly EngineIntrinsics _engineIntrinsics;
+ private IConsoleOperations _consoleOperations;
public PsrlReadLine(
PSReadLineProxy psrlProxy,
PsesInternalHost psesHost,
EngineIntrinsics engineIntrinsics,
Func readKeyFunc,
- Action onIdleAction)
+ Action onIdleAction,
+ IConsoleOperations consoleOperations)
{
_psrlProxy = psrlProxy;
_psesHost = psesHost;
_engineIntrinsics = engineIntrinsics;
_psrlProxy.OverrideReadKey(readKeyFunc);
_psrlProxy.OverrideIdleHandler(onIdleAction);
+ _consoleOperations = consoleOperations;
}
public override string ReadLine(CancellationToken cancellationToken) => _psesHost.InvokeDelegate(
@@ -40,6 +43,15 @@ public override string ReadLine(CancellationToken cancellationToken) => _psesHos
protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken) => _psesHost.ReadKey(intercept: true, cancellationToken);
+ protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken)
+ {
+ return _consoleOperations.ReadKey(intercept: true, cancellationToken);
+ }
+
+ #endregion
+
+ #region Private Methods
+
private string InvokePSReadLine(CancellationToken cancellationToken)
{
EngineIntrinsics engineIntrinsics = _psesHost.IsRunspacePushed ? null : _engineIntrinsics;
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs
index 8d05edc18..0dac40546 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs
@@ -9,6 +9,8 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Console
internal abstract class TerminalReadLine : IReadLine
{
+ private IConsoleOperations _consoleOperations;
+
public abstract string ReadLine(CancellationToken cancellationToken);
protected abstract ConsoleKeyInfo ReadKey(CancellationToken cancellationToken);
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs
index 8a90f0503..2bfd3bb08 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs
@@ -24,10 +24,12 @@ internal class EditorServicesConsolePSHostRawUserInterface : PSHostRawUserInterf
///
public EditorServicesConsolePSHostRawUserInterface(
ILoggerFactory loggerFactory,
- PSHostRawUserInterface internalRawUI)
+ PSHostRawUserInterface internalRawUI,
+ IConsoleOperations consoleOperations)
{
_logger = loggerFactory.CreateLogger();
_internalRawUI = internalRawUI;
+ _consoleOperations = consoleOperations;
}
#endregion
@@ -39,8 +41,28 @@ public EditorServicesConsolePSHostRawUserInterface(
///
public override ConsoleColor BackgroundColor
{
- get => System.Console.BackgroundColor;
- set => System.Console.BackgroundColor = value;
+ get
+ {
+ if (_consoleOperations is not null)
+ {
+ return System.Console.BackgroundColor;
+ }
+ else
+ {
+ return _internalRawUI.BackgroundColor;
+ }
+ }
+ set
+ {
+ if (_consoleOperations is not null)
+ {
+ System.Console.BackgroundColor = value;
+ }
+ else
+ {
+ _internalRawUI.BackgroundColor = value;
+ }
+ }
}
///
@@ -48,8 +70,28 @@ public override ConsoleColor BackgroundColor
///
public override ConsoleColor ForegroundColor
{
- get => System.Console.ForegroundColor;
- set => System.Console.ForegroundColor = value;
+ get
+ {
+ if (_consoleOperations is not null)
+ {
+ return System.Console.ForegroundColor;
+ }
+ else
+ {
+ return _internalRawUI.ForegroundColor;
+ }
+ }
+ set
+ {
+ if (_consoleOperations is not null)
+ {
+ System.Console.ForegroundColor = value;
+ }
+ else
+ {
+ _internalRawUI.ForegroundColor = value;
+ }
+ }
}
///
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
index fb6d2c861..166583a66 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
@@ -27,7 +27,14 @@ public EditorServicesConsolePSHostUserInterface(
PSHostUserInterface underlyingHostUI)
{
_underlyingHostUI = underlyingHostUI;
- RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI);
+ RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI, consoleOperations);
+
+ _consoleHostUI = GetConsoleHostUI(_underlyingHostUI);
+
+ if (_consoleHostUI != null)
+ {
+ SetConsoleHostUIToInteractive(_consoleHostUI);
+ }
}
public override bool SupportsVirtualTerminal => _underlyingHostUI.SupportsVirtualTerminal;
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
index 271518add..53eedb935 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
@@ -98,6 +98,7 @@ public PsesInternalHost(
_logger = loggerFactory.CreateLogger();
_languageServer = languageServer;
_hostInfo = hostInfo;
+
// Respect a user provided bundled module path.
if (Directory.Exists(hostInfo.BundledModulePath))
@@ -136,6 +137,14 @@ public PsesInternalHost(
Version = hostInfo.Version;
DebugContext = new PowerShellDebugContext(loggerFactory, this);
+ if (!_hostInfo.UseHostReadKey)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ _consoleOperations = new WindowsConsoleOperations();
+ }
+ _consoleOperations = new UnixConsoleOperations();
+ }
UI = hostInfo.ConsoleReplEnabled
? new EditorServicesConsolePSHostUserInterface(loggerFactory, hostInfo.PSHost.UI)
: new NullPSHostUI();
@@ -955,7 +964,7 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace)
// If we've been configured to use it, or if we can't load PSReadLine, use the legacy readline
if (hostStartupInfo.UsesLegacyReadLine || !TryLoadPSReadLine(pwsh, engineIntrinsics, out IReadLine readLine))
{
- readLine = new LegacyReadLine(this, ReadKey, OnPowerShellIdle);
+ readLine = new LegacyReadLine(this, ReadKey, OnPowerShellIdle, _consoleOperations);
}
readLineProvider.OverrideReadLine(readLine);
@@ -1071,7 +1080,55 @@ private void OnCancelKeyPress(object sender, ConsoleCancelEventArgs args)
StopDebugContext();
}
}
-
+ ///
+ /// This method is sent to PSReadLine as a workaround for issues with the System.Console
+ /// implementation. Functionally it is the same as System.Console.ReadKey,
+ /// with the exception that it will not lock the standard input stream.
+ ///
+ ///
+ /// Determines whether to display the pressed key in the console window.
+ /// true to not display the pressed key; otherwise, false.
+ ///
+ ///
+ /// The that can be used to cancel the request.
+ ///
+ ///
+ /// An object that describes the ConsoleKey constant and Unicode character, if any,
+ /// that correspond to the pressed console key. The ConsoleKeyInfo object also describes,
+ /// in a bitwise combination of ConsoleModifiers values, whether one or more Shift, Alt,
+ /// or Ctrl modifier keys was pressed simultaneously with the console key.
+ ///
+ internal ConsoleKeyInfo SafeReadKey(bool intercept, CancellationToken cancellationToken)
+ {
+ try
+ {
+ if (_consoleOperations is not null)
+ {
+ return _consoleOperations.ReadKey(intercept, cancellationToken);
+ }
+ else
+ {
+ var keyInfo = UI.RawUI.ReadKey(ReadKeyOptions.AllowCtrlC);
+
+ return new ConsoleKeyInfo(
+ keyChar: keyInfo.Character,
+ key: ConsoleKey.DownArrow,
+ shift: (keyInfo.ControlKeyState & ControlKeyStates.ShiftPressed) > 0,
+ alt: (keyInfo.ControlKeyState & (ControlKeyStates.RightAltPressed | ControlKeyStates.LeftAltPressed)) > 0,
+ control: (keyInfo.ControlKeyState > 0)
+ );
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ return new ConsoleKeyInfo(
+ keyChar: ' ',
+ key: ConsoleKey.DownArrow,
+ shift: false,
+ alt: false,
+ control: false);
+ }
+ }
private ConsoleKeyInfo ReadKey(bool intercept)
{
// NOTE: This requests that the client (the Code extension) send a non-printing key back
@@ -1248,7 +1305,7 @@ internal bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsi
try
{
PSReadLineProxy psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, s_bundledModulePath, pwsh);
- psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle);
+ psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle, _consoleOperations);
return true;
}
catch (Exception e)
From b6f3596d302fb95e78159effeada3caf63a5d0d5 Mon Sep 17 00:00:00 2001
From: dkattan <1424395+dkattan@users.noreply.github.com>
Date: Thu, 24 Mar 2022 15:34:05 -0500
Subject: [PATCH 2/3] Corrected build issues. Removed ConsoleProxy. Reverted
changes to EditorServicesLoader
---
.../EditorServicesLoader.cs | 2 +-
.../Host/EditorServicesConsolePSHostUserInterface.cs | 7 -------
test/PowerShellEditorServices.Test/PsesHostFactory.cs | 1 +
3 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
index 204de1b55..e1bc6f24f 100644
--- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
+++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
@@ -107,7 +107,7 @@ public static EditorServicesLoader Create(
// We only want the Editor Services DLL; the new ALC will lazily load its dependencies automatically
if (!string.Equals(asmName.Name, "Microsoft.PowerShell.EditorServices", StringComparison.Ordinal))
{
- //return null;
+ return null;
}
string asmPath = Path.Combine(s_psesDependencyDirPath, $"{asmName.Name}.dll");
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
index 166583a66..bdf867f93 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
@@ -28,13 +28,6 @@ public EditorServicesConsolePSHostUserInterface(
{
_underlyingHostUI = underlyingHostUI;
RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI, consoleOperations);
-
- _consoleHostUI = GetConsoleHostUI(_underlyingHostUI);
-
- if (_consoleHostUI != null)
- {
- SetConsoleHostUIToInteractive(_consoleHostUI);
- }
}
public override bool SupportsVirtualTerminal => _underlyingHostUI.SupportsVirtualTerminal;
diff --git a/test/PowerShellEditorServices.Test/PsesHostFactory.cs b/test/PowerShellEditorServices.Test/PsesHostFactory.cs
index 3f7ab95b9..81852d163 100644
--- a/test/PowerShellEditorServices.Test/PsesHostFactory.cs
+++ b/test/PowerShellEditorServices.Test/PsesHostFactory.cs
@@ -57,6 +57,7 @@ public static PsesInternalHost Create(ILoggerFactory loggerFactory)
logLevel: (int)LogLevel.None,
consoleReplEnabled: false,
usesLegacyReadLine: false,
+ useHostReadKey: false,
bundledModulePath: BundledModulePath);
PsesInternalHost psesHost = new(loggerFactory, null, testHostDetails);
From 46d2732c73e7aa533f6c62f84b76cd10e07fafd6 Mon Sep 17 00:00:00 2001
From: dkattan <1424395+dkattan@users.noreply.github.com>
Date: Fri, 20 May 2022 16:34:17 -0500
Subject: [PATCH 3/3] Rebased. Compiles. Needs testing.
---
.../PowerShell/Console/LegacyReadLine.cs | 16 ++---
.../PowerShell/Console/PsrlReadLine.cs | 19 ++----
.../PowerShell/Console/TerminalReadLine.cs | 2 -
...orServicesConsolePSHostRawUserInterface.cs | 52 ++--------------
...ditorServicesConsolePSHostUserInterface.cs | 2 +-
.../PowerShell/Host/PsesInternalHost.cs | 60 ++++++-------------
6 files changed, 33 insertions(+), 118 deletions(-)
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
index fbc72f39f..4b78931cb 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
@@ -24,19 +24,15 @@ internal class LegacyReadLine : TerminalReadLine
private readonly Action _onIdleAction;
- private IConsoleOperations _consoleOperations;
-
public LegacyReadLine(
PsesInternalHost psesHost,
Func readKeyFunc,
- Action onIdleAction,
- IConsoleOperations consoleOperations)
+ Action onIdleAction)
{
_psesHost = psesHost;
_readKeyTasks = new Task[2];
_readKeyFunc = readKeyFunc;
_onIdleAction = onIdleAction;
- _consoleOperations = consoleOperations;
}
public override string ReadLine(CancellationToken cancellationToken)
@@ -50,12 +46,12 @@ public override string ReadLine(CancellationToken cancellationToken)
StringBuilder inputLine = new();
- int initialCursorCol = _consoleOperations?.GetCursorLeft(cancellationToken) ?? _psesHost.UI.RawUI.CursorPosition.X;
- int initialCursorRow = _consoleOperations?.GetCursorTop(cancellationToken) ?? _psesHost.UI.RawUI.CursorPosition.Y; ;
+ int initialCursorCol = Console.CursorLeft;
+ int initialCursorRow = Console.CursorTop;
int currentCursorIndex = 0;
- if(_consoleOperations != null)
- Console.TreatControlCAsInput = true;
+
+ Console.TreatControlCAsInput = true;
try
{
@@ -68,7 +64,7 @@ public override string ReadLine(CancellationToken cancellationToken)
int promptStartCol = initialCursorCol;
int promptStartRow = initialCursorRow;
- int consoleWidth = _consoleOperations is not null ? Console.WindowWidth : _psesHost.UI.RawUI.WindowSize.Width;
+ int consoleWidth = Console.WindowWidth;
switch (keyInfo.Key)
{
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs
index b4ecd583b..c3513a5fd 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs
@@ -17,22 +17,20 @@ internal class PsrlReadLine : TerminalReadLine
private readonly PsesInternalHost _psesHost;
private readonly EngineIntrinsics _engineIntrinsics;
- private IConsoleOperations _consoleOperations;
+
public PsrlReadLine(
PSReadLineProxy psrlProxy,
PsesInternalHost psesHost,
EngineIntrinsics engineIntrinsics,
Func readKeyFunc,
- Action onIdleAction,
- IConsoleOperations consoleOperations)
+ Action onIdleAction)
{
_psrlProxy = psrlProxy;
_psesHost = psesHost;
_engineIntrinsics = engineIntrinsics;
_psrlProxy.OverrideReadKey(readKeyFunc);
- _psrlProxy.OverrideIdleHandler(onIdleAction);
- _consoleOperations = consoleOperations;
+ _psrlProxy.OverrideIdleHandler(onIdleAction);
}
public override string ReadLine(CancellationToken cancellationToken) => _psesHost.InvokeDelegate(
@@ -42,16 +40,7 @@ public override string ReadLine(CancellationToken cancellationToken) => _psesHos
cancellationToken);
protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken) => _psesHost.ReadKey(intercept: true, cancellationToken);
-
- protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken)
- {
- return _consoleOperations.ReadKey(intercept: true, cancellationToken);
- }
-
- #endregion
-
- #region Private Methods
-
+
private string InvokePSReadLine(CancellationToken cancellationToken)
{
EngineIntrinsics engineIntrinsics = _psesHost.IsRunspacePushed ? null : _engineIntrinsics;
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs
index 0dac40546..8d05edc18 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs
@@ -9,8 +9,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Console
internal abstract class TerminalReadLine : IReadLine
{
- private IConsoleOperations _consoleOperations;
-
public abstract string ReadLine(CancellationToken cancellationToken);
protected abstract ConsoleKeyInfo ReadKey(CancellationToken cancellationToken);
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs
index 2bfd3bb08..8a90f0503 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs
@@ -24,12 +24,10 @@ internal class EditorServicesConsolePSHostRawUserInterface : PSHostRawUserInterf
///
public EditorServicesConsolePSHostRawUserInterface(
ILoggerFactory loggerFactory,
- PSHostRawUserInterface internalRawUI,
- IConsoleOperations consoleOperations)
+ PSHostRawUserInterface internalRawUI)
{
_logger = loggerFactory.CreateLogger();
_internalRawUI = internalRawUI;
- _consoleOperations = consoleOperations;
}
#endregion
@@ -41,28 +39,8 @@ public EditorServicesConsolePSHostRawUserInterface(
///
public override ConsoleColor BackgroundColor
{
- get
- {
- if (_consoleOperations is not null)
- {
- return System.Console.BackgroundColor;
- }
- else
- {
- return _internalRawUI.BackgroundColor;
- }
- }
- set
- {
- if (_consoleOperations is not null)
- {
- System.Console.BackgroundColor = value;
- }
- else
- {
- _internalRawUI.BackgroundColor = value;
- }
- }
+ get => System.Console.BackgroundColor;
+ set => System.Console.BackgroundColor = value;
}
///
@@ -70,28 +48,8 @@ public override ConsoleColor BackgroundColor
///
public override ConsoleColor ForegroundColor
{
- get
- {
- if (_consoleOperations is not null)
- {
- return System.Console.ForegroundColor;
- }
- else
- {
- return _internalRawUI.ForegroundColor;
- }
- }
- set
- {
- if (_consoleOperations is not null)
- {
- System.Console.ForegroundColor = value;
- }
- else
- {
- _internalRawUI.ForegroundColor = value;
- }
- }
+ get => System.Console.ForegroundColor;
+ set => System.Console.ForegroundColor = value;
}
///
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
index bdf867f93..fb6d2c861 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs
@@ -27,7 +27,7 @@ public EditorServicesConsolePSHostUserInterface(
PSHostUserInterface underlyingHostUI)
{
_underlyingHostUI = underlyingHostUI;
- RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI, consoleOperations);
+ RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI);
}
public override bool SupportsVirtualTerminal => _underlyingHostUI.SupportsVirtualTerminal;
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
index 53eedb935..0f267cb5b 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
@@ -137,14 +137,7 @@ public PsesInternalHost(
Version = hostInfo.Version;
DebugContext = new PowerShellDebugContext(loggerFactory, this);
- if (!_hostInfo.UseHostReadKey)
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- _consoleOperations = new WindowsConsoleOperations();
- }
- _consoleOperations = new UnixConsoleOperations();
- }
+
UI = hostInfo.ConsoleReplEnabled
? new EditorServicesConsolePSHostUserInterface(loggerFactory, hostInfo.PSHost.UI)
: new NullPSHostUI();
@@ -964,7 +957,7 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace)
// If we've been configured to use it, or if we can't load PSReadLine, use the legacy readline
if (hostStartupInfo.UsesLegacyReadLine || !TryLoadPSReadLine(pwsh, engineIntrinsics, out IReadLine readLine))
{
- readLine = new LegacyReadLine(this, ReadKey, OnPowerShellIdle, _consoleOperations);
+ readLine = new LegacyReadLine(this, ReadKey, OnPowerShellIdle);
}
readLineProvider.OverrideReadLine(readLine);
@@ -1098,37 +1091,7 @@ private void OnCancelKeyPress(object sender, ConsoleCancelEventArgs args)
/// in a bitwise combination of ConsoleModifiers values, whether one or more Shift, Alt,
/// or Ctrl modifier keys was pressed simultaneously with the console key.
///
- internal ConsoleKeyInfo SafeReadKey(bool intercept, CancellationToken cancellationToken)
- {
- try
- {
- if (_consoleOperations is not null)
- {
- return _consoleOperations.ReadKey(intercept, cancellationToken);
- }
- else
- {
- var keyInfo = UI.RawUI.ReadKey(ReadKeyOptions.AllowCtrlC);
-
- return new ConsoleKeyInfo(
- keyChar: keyInfo.Character,
- key: ConsoleKey.DownArrow,
- shift: (keyInfo.ControlKeyState & ControlKeyStates.ShiftPressed) > 0,
- alt: (keyInfo.ControlKeyState & (ControlKeyStates.RightAltPressed | ControlKeyStates.LeftAltPressed)) > 0,
- control: (keyInfo.ControlKeyState > 0)
- );
- }
- }
- catch (OperationCanceledException)
- {
- return new ConsoleKeyInfo(
- keyChar: ' ',
- key: ConsoleKey.DownArrow,
- shift: false,
- alt: false,
- control: false);
- }
- }
+
private ConsoleKeyInfo ReadKey(bool intercept)
{
// NOTE: This requests that the client (the Code extension) send a non-printing key back
@@ -1151,13 +1114,24 @@ private ConsoleKeyInfo ReadKey(bool intercept)
// we can subscribe in the same way.
DebugServer?.SendNotification("powerShell/sendKeyPress");
});
-
+
// PSReadLine doesn't tell us when CtrlC was sent. So instead we keep track of the last
// key here. This isn't functionally required, but helps us determine when the prompt
// needs a newline added
//
// TODO: We may want to allow users of PSES to override this method call.
- _lastKey = System.Console.ReadKey(intercept);
+ if (!_hostInfo.UseHostReadKey)
+ {
+ _lastKey = System.Console.ReadKey(intercept);
+ }
+ else
+ {
+ KeyInfo keyInfo = _hostInfo.PSHost.UI.RawUI.ReadKey();
+ _lastKey = new(keyInfo.Character, (ConsoleKey)keyInfo.Character, (keyInfo.ControlKeyState & ControlKeyStates.ShiftPressed) > 0,
+ (keyInfo.ControlKeyState & (ControlKeyStates.RightAltPressed | ControlKeyStates.LeftAltPressed)) > 0,
+ (keyInfo.ControlKeyState & (ControlKeyStates.RightCtrlPressed | ControlKeyStates.LeftCtrlPressed)) > 0);
+ }
+
return _lastKey.Value;
}
@@ -1305,7 +1279,7 @@ internal bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsi
try
{
PSReadLineProxy psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, s_bundledModulePath, pwsh);
- psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle, _consoleOperations);
+ psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle);
return true;
}
catch (Exception e)