Skip to content

Commit 4b545ca

Browse files
committed
Added a -UseHostReadKey switch to instruct LegacyReadLine to use the ReadKey provided by the host instead of Console.ReadKey
1 parent 8aa9e11 commit 4b545ca

File tree

12 files changed

+173
-28
lines changed

12 files changed

+173
-28
lines changed

module/PowerShellEditorServices/Start-EditorServices.ps1

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,20 @@ param(
5252
[ValidateSet("Diagnostic", "Verbose", "Normal", "Warning", "Error")]
5353
$LogLevel,
5454

55-
[Parameter(Mandatory=$true)]
56-
[ValidateNotNullOrEmpty()]
57-
[string]
58-
$SessionDetailsPath,
55+
[Parameter(Mandatory=$true)]
56+
[ValidateNotNullOrEmpty()]
57+
[string]
58+
$SessionDetailsPath,
5959

6060
[switch]
6161
$EnableConsoleRepl,
6262

6363
[switch]
6464
$UseLegacyReadLine,
6565

66+
[switch]
67+
$UseHostReadKey,
68+
6669
[switch]
6770
$DebugServiceOnly,
6871

src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ public StartEditorServicesCommand()
161161
[Parameter]
162162
public SwitchParameter UseLegacyReadLine { get; set; }
163163

164+
/// <summary>
165+
/// When set and the console is enabled and legacy readline
166+
/// is enabled, console operations will use PSHostreadline implementation will be used instead of PSReadLine.
167+
/// </summary>
168+
[Parameter]
169+
public SwitchParameter UseHostReadKey { get; set; }
164170
/// <summary>
165171
/// When set, do not enable LSP service, only the debug adapter.
166172
/// </summary>
@@ -345,8 +351,9 @@ private EditorServicesConfig CreateConfigObject()
345351
hostInfo,
346352
Host,
347353
SessionDetailsPath,
348-
bundledModulesPath,
349-
LogPath)
354+
bundledModulesPath,
355+
LogPath,
356+
UseHostReadKey)
350357
{
351358
FeatureFlags = FeatureFlags,
352359
LogLevel = LogLevel,

src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public enum ConsoleReplKind
1717
/// <summary>Use a REPL with the legacy readline implementation. This is generally used when PSReadLine is unavailable.</summary>
1818
LegacyReadLine = 1,
1919
/// <summary>Use a REPL with the PSReadLine module for console interaction.</summary>
20-
PSReadLine = 2,
20+
PSReadLine = 2
2121
}
2222

2323
/// <summary>
@@ -39,13 +39,15 @@ public EditorServicesConfig(
3939
PSHost psHost,
4040
string sessionDetailsPath,
4141
string bundledModulePath,
42-
string logPath)
42+
string logPath,
43+
bool useHostReadKey)
4344
{
4445
HostInfo = hostInfo;
4546
PSHost = psHost;
4647
SessionDetailsPath = sessionDetailsPath;
4748
BundledModulePath = bundledModulePath;
4849
LogPath = logPath;
50+
UseHostReadKey = useHostReadKey;
4951
}
5052

5153
/// <summary>
@@ -72,6 +74,7 @@ public EditorServicesConfig(
7274
/// The path to use for logging for Editor Services.
7375
/// </summary>
7476
public string LogPath { get; }
77+
public bool UseHostReadKey { get; }
7578

7679
/// <summary>
7780
/// Names of or paths to any additional modules to load on startup.
@@ -88,7 +91,7 @@ public EditorServicesConfig(
8891
/// (including none to disable the integrated console).
8992
/// </summary>
9093
public ConsoleReplKind ConsoleRepl { get; set; } = ConsoleReplKind.None;
91-
94+
9295
/// <summary>
9396
/// The minimum log level to log events with.
9497
/// </summary>

src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ public static EditorServicesLoader Create(
107107
// We only want the Editor Services DLL; the new ALC will lazily load its dependencies automatically
108108
if (!string.Equals(asmName.Name, "Microsoft.PowerShell.EditorServices", StringComparison.Ordinal))
109109
{
110-
return null;
110+
//return null;
111111
}
112112

113113
string asmPath = Path.Combine(s_psesDependencyDirPath, $"{asmName.Name}.dll");
114114

115-
logger.Log(PsesLogLevel.Verbose, "Loading PSES DLL using new assembly load context");
115+
logger.Log(PsesLogLevel.Verbose, $"Loading {asmName.Name}.dll using new assembly load context");
116116

117117
return psesLoadContext.LoadFromAssemblyPath(asmPath);
118118
};

src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ private HostStartupInfo CreateHostStartupInfo()
290290
(int)_config.LogLevel,
291291
consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None,
292292
usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine,
293+
useHostReadKey: _config.UseHostReadKey,
293294
bundledModulePath: _config.BundledModulePath);
294295
}
295296

src/PowerShellEditorServices/Hosting/HostStartupInfo.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ public sealed class HostStartupInfo
8080
/// If the console REPL is not enabled, this setting will be ignored.
8181
/// </summary>
8282
public bool UsesLegacyReadLine { get; }
83-
83+
/// <summary>
84+
/// If true, the legacy PSES readline implementation but calls ReadKey in the provided host
85+
/// If the console REPL is not enabled, this setting will be ignored.
86+
/// </summary>
87+
public bool UseHostReadKey { get; }
8488
/// <summary>
8589
/// The PowerShell host to use with Editor Services.
8690
/// </summary>
@@ -153,6 +157,7 @@ public HostStartupInfo(
153157
int logLevel,
154158
bool consoleReplEnabled,
155159
bool usesLegacyReadLine,
160+
bool useHostReadKey,
156161
string bundledModulePath)
157162
{
158163
Name = name ?? DefaultHostName;
@@ -167,6 +172,7 @@ public HostStartupInfo(
167172
LogLevel = logLevel;
168173
ConsoleReplEnabled = consoleReplEnabled;
169174
UsesLegacyReadLine = usesLegacyReadLine;
175+
UseHostReadKey = useHostReadKey;
170176
BundledModulePath = bundledModulePath;
171177
}
172178

src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@ internal class LegacyReadLine : TerminalReadLine
2424

2525
private readonly Action<CancellationToken> _onIdleAction;
2626

27+
private IConsoleOperations _consoleOperations;
28+
2729
public LegacyReadLine(
2830
PsesInternalHost psesHost,
2931
Func<bool, ConsoleKeyInfo> readKeyFunc,
30-
Action<CancellationToken> onIdleAction)
32+
Action<CancellationToken> onIdleAction,
33+
IConsoleOperations consoleOperations)
3134
{
3235
_psesHost = psesHost;
3336
_readKeyTasks = new Task[2];
3437
_readKeyFunc = readKeyFunc;
3538
_onIdleAction = onIdleAction;
39+
_consoleOperations = consoleOperations;
3640
}
3741

3842
public override string ReadLine(CancellationToken cancellationToken)
@@ -46,12 +50,12 @@ public override string ReadLine(CancellationToken cancellationToken)
4650

4751
StringBuilder inputLine = new();
4852

49-
int initialCursorCol = Console.CursorLeft;
50-
int initialCursorRow = Console.CursorTop;
53+
int initialCursorCol = _consoleOperations?.GetCursorLeft(cancellationToken) ?? _psesHost.UI.RawUI.CursorPosition.X;
54+
int initialCursorRow = _consoleOperations?.GetCursorTop(cancellationToken) ?? _psesHost.UI.RawUI.CursorPosition.Y; ;
5155

5256
int currentCursorIndex = 0;
53-
54-
Console.TreatControlCAsInput = true;
57+
if(_consoleOperations != null)
58+
Console.TreatControlCAsInput = true;
5559

5660
try
5761
{
@@ -63,7 +67,8 @@ public override string ReadLine(CancellationToken cancellationToken)
6367
// because the window could have been resized before then
6468
int promptStartCol = initialCursorCol;
6569
int promptStartRow = initialCursorRow;
66-
int consoleWidth = Console.WindowWidth;
70+
71+
int consoleWidth = _consoleOperations is not null ? Console.WindowWidth : _psesHost.UI.RawUI.WindowSize.Width;
6772

6873
switch (keyInfo.Key)
6974
{

src/PowerShellEditorServices/Services/PowerShell/Console/PsrlReadLine.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,22 @@ internal class PsrlReadLine : TerminalReadLine
1717
private readonly PsesInternalHost _psesHost;
1818

1919
private readonly EngineIntrinsics _engineIntrinsics;
20+
private IConsoleOperations _consoleOperations;
2021

2122
public PsrlReadLine(
2223
PSReadLineProxy psrlProxy,
2324
PsesInternalHost psesHost,
2425
EngineIntrinsics engineIntrinsics,
2526
Func<bool, ConsoleKeyInfo> readKeyFunc,
26-
Action<CancellationToken> onIdleAction)
27+
Action<CancellationToken> onIdleAction,
28+
IConsoleOperations consoleOperations)
2729
{
2830
_psrlProxy = psrlProxy;
2931
_psesHost = psesHost;
3032
_engineIntrinsics = engineIntrinsics;
3133
_psrlProxy.OverrideReadKey(readKeyFunc);
3234
_psrlProxy.OverrideIdleHandler(onIdleAction);
35+
_consoleOperations = consoleOperations;
3336
}
3437

3538
public override string ReadLine(CancellationToken cancellationToken) => _psesHost.InvokeDelegate(
@@ -40,6 +43,15 @@ public override string ReadLine(CancellationToken cancellationToken) => _psesHos
4043

4144
protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken) => _psesHost.ReadKey(intercept: true, cancellationToken);
4245

46+
protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken)
47+
{
48+
return _consoleOperations.ReadKey(intercept: true, cancellationToken);
49+
}
50+
51+
#endregion
52+
53+
#region Private Methods
54+
4355
private string InvokePSReadLine(CancellationToken cancellationToken)
4456
{
4557
EngineIntrinsics engineIntrinsics = _psesHost.IsRunspacePushed ? null : _engineIntrinsics;

src/PowerShellEditorServices/Services/PowerShell/Console/TerminalReadLine.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Console
99

1010
internal abstract class TerminalReadLine : IReadLine
1111
{
12+
private IConsoleOperations _consoleOperations;
13+
1214
public abstract string ReadLine(CancellationToken cancellationToken);
1315

1416
protected abstract ConsoleKeyInfo ReadKey(CancellationToken cancellationToken);

src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostRawUserInterface.cs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ internal class EditorServicesConsolePSHostRawUserInterface : PSHostRawUserInterf
2424
/// </summary>
2525
public EditorServicesConsolePSHostRawUserInterface(
2626
ILoggerFactory loggerFactory,
27-
PSHostRawUserInterface internalRawUI)
27+
PSHostRawUserInterface internalRawUI,
28+
IConsoleOperations consoleOperations)
2829
{
2930
_logger = loggerFactory.CreateLogger<EditorServicesConsolePSHostRawUserInterface>();
3031
_internalRawUI = internalRawUI;
32+
_consoleOperations = consoleOperations;
3133
}
3234

3335
#endregion
@@ -39,17 +41,57 @@ public EditorServicesConsolePSHostRawUserInterface(
3941
/// </summary>
4042
public override ConsoleColor BackgroundColor
4143
{
42-
get => System.Console.BackgroundColor;
43-
set => System.Console.BackgroundColor = value;
44+
get
45+
{
46+
if (_consoleOperations is not null)
47+
{
48+
return System.Console.BackgroundColor;
49+
}
50+
else
51+
{
52+
return _internalRawUI.BackgroundColor;
53+
}
54+
}
55+
set
56+
{
57+
if (_consoleOperations is not null)
58+
{
59+
System.Console.BackgroundColor = value;
60+
}
61+
else
62+
{
63+
_internalRawUI.BackgroundColor = value;
64+
}
65+
}
4466
}
4567

4668
/// <summary>
4769
/// Gets or sets the foreground color of the console.
4870
/// </summary>
4971
public override ConsoleColor ForegroundColor
5072
{
51-
get => System.Console.ForegroundColor;
52-
set => System.Console.ForegroundColor = value;
73+
get
74+
{
75+
if (_consoleOperations is not null)
76+
{
77+
return System.Console.ForegroundColor;
78+
}
79+
else
80+
{
81+
return _internalRawUI.ForegroundColor;
82+
}
83+
}
84+
set
85+
{
86+
if (_consoleOperations is not null)
87+
{
88+
System.Console.ForegroundColor = value;
89+
}
90+
else
91+
{
92+
_internalRawUI.ForegroundColor = value;
93+
}
94+
}
5395
}
5496

5597
/// <summary>

src/PowerShellEditorServices/Services/PowerShell/Host/EditorServicesConsolePSHostUserInterface.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ public EditorServicesConsolePSHostUserInterface(
2727
PSHostUserInterface underlyingHostUI)
2828
{
2929
_underlyingHostUI = underlyingHostUI;
30-
RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI);
30+
RawUI = new EditorServicesConsolePSHostRawUserInterface(loggerFactory, underlyingHostUI.RawUI, consoleOperations);
31+
32+
_consoleHostUI = GetConsoleHostUI(_underlyingHostUI);
33+
34+
if (_consoleHostUI != null)
35+
{
36+
SetConsoleHostUIToInteractive(_consoleHostUI);
37+
}
3138
}
3239

3340
public override bool SupportsVirtualTerminal => _underlyingHostUI.SupportsVirtualTerminal;

0 commit comments

Comments
 (0)