Skip to content

Commit ba94845

Browse files
Move PSReadLine logic to cmdlets (#1255)
* Move PSReadLine logic to cmdlets * move to delegate
1 parent 66065e8 commit ba94845

File tree

5 files changed

+91
-14
lines changed

5 files changed

+91
-14
lines changed

module/PowerShellEditorServices/PowerShellEditorServices.psd1

+5-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ Copyright = '(c) 2017 Microsoft. All rights reserved.'
7676
FunctionsToExport = @()
7777

7878
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
79-
CmdletsToExport = @('Start-EditorServices')
79+
CmdletsToExport = @(
80+
'Start-EditorServices',
81+
'__Invoke-ReadLineForEditorServices',
82+
'__Invoke-ReadLineConstructor'
83+
)
8084

8185
# Variables to export from this module
8286
VariablesToExport = @()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
using System.Management.Automation;
8+
using System.Runtime.CompilerServices;
9+
10+
namespace Microsoft.PowerShell.EditorServices.Commands
11+
{
12+
/// <summary>
13+
/// The Start-EditorServices command, the conventional entrypoint for PowerShell Editor Services.
14+
/// </summary>
15+
[Cmdlet("__Invoke", "ReadLineConstructor")]
16+
public sealed class InvokeReadLineConstructorCommand : PSCmdlet
17+
{
18+
protected override void EndProcessing()
19+
{
20+
Type type = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2");
21+
RuntimeHelpers.RunClassConstructor(type.TypeHandle);
22+
}
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
using System.Management.Automation;
8+
using System.Management.Automation.Runspaces;
9+
using System.Reflection;
10+
using System.Threading;
11+
12+
namespace Microsoft.PowerShell.EditorServices.Commands
13+
{
14+
/// <summary>
15+
/// The Start-EditorServices command, the conventional entrypoint for PowerShell Editor Services.
16+
/// </summary>
17+
[Cmdlet("__Invoke", "ReadLineForEditorServices")]
18+
public sealed class InvokeReadLineForEditorServicesCommand : PSCmdlet
19+
{
20+
private delegate string ReadLineInvoker(
21+
Runspace runspace,
22+
EngineIntrinsics engineIntrinsics,
23+
CancellationToken cancellationToken);
24+
25+
private static Lazy<ReadLineInvoker> s_readLine = new Lazy<ReadLineInvoker>(() =>
26+
{
27+
Type type = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2");
28+
MethodInfo method = type?.GetMethod(
29+
"ReadLine",
30+
new[] { typeof(Runspace), typeof(EngineIntrinsics), typeof(CancellationToken) });
31+
32+
// TODO: Handle method being null here. This shouldn't ever happen.
33+
34+
return (ReadLineInvoker)method.CreateDelegate(typeof(ReadLineInvoker));
35+
});
36+
37+
/// <summary>
38+
/// The ID to give to the host's profile.
39+
/// </summary>
40+
[Parameter(Mandatory = true)]
41+
[ValidateNotNullOrEmpty]
42+
public CancellationToken CancellationToken { get; set; }
43+
44+
protected override void EndProcessing()
45+
{
46+
// This returns a string.
47+
object result = s_readLine.Value(
48+
Runspace.DefaultRunspace,
49+
SessionState.PSVariable.Get("ExecutionContext").Value as EngineIntrinsics,
50+
CancellationToken
51+
);
52+
53+
WriteObject(result);
54+
}
55+
}
56+
}

src/PowerShellEditorServices/Server/PsesDebugServer.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using System;
77
using System.IO;
8+
using System.Management.Automation;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using Microsoft.Extensions.DependencyInjection;
@@ -80,8 +81,9 @@ public async Task StartAsync()
8081
if (_usePSReadLine && _useTempSession && Interlocked.Exchange(ref s_hasRunPsrlStaticCtor, 1) == 0)
8182
{
8283
// This must be run synchronously to ensure debugging works
84+
var command = new PSCommand().AddCommand("__Invoke-ReadLineConstructor");
8385
_powerShellContextService
84-
.ExecuteScriptStringAsync("[System.Runtime.CompilerServices.RuntimeHelpers]::RunClassConstructor([Microsoft.PowerShell.PSConsoleReadLine].TypeHandle)")
86+
.ExecuteCommandAsync<object>(command, sendOutputToHost: true, sendErrorToHost: true)
8587
.GetAwaiter()
8688
.GetResult();
8789
}

src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs

+3-12
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShellContext
1818

1919
internal class PSReadLinePromptContext : IPromptContext
2020
{
21-
private const string ReadLineScript = @"
22-
[System.Diagnostics.DebuggerHidden()]
23-
[System.Diagnostics.DebuggerStepThrough()]
24-
param()
25-
return [Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]::ReadLine(
26-
$Host.Runspace,
27-
$ExecutionContext,
28-
$args[0])";
29-
3021
private const string ReadLineInitScript = @"
3122
[System.Diagnostics.DebuggerHidden()]
3223
[System.Diagnostics.DebuggerStepThrough()]
@@ -41,7 +32,7 @@ internal class PSReadLinePromptContext : IPromptContext
4132
}
4233
4334
Import-Module -ModuleInfo $module
44-
return [Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]
35+
return [Microsoft.PowerShell.PSConsoleReadLine]
4536
}";
4637

4738
private static ExecutionOptions s_psrlExecutionOptions = new ExecutionOptions
@@ -138,8 +129,8 @@ public async Task<string> InvokeReadLineAsync(bool isCommandLine, CancellationTo
138129
}
139130

140131
var readLineCommand = new PSCommand()
141-
.AddScript(ReadLineScript)
142-
.AddArgument(_readLineCancellationSource.Token);
132+
.AddCommand("__Invoke-ReadLineForEditorServices")
133+
.AddParameter("CancellationToken", _readLineCancellationSource.Token);
143134

144135
IEnumerable<string> readLineResults = await _powerShellContext.ExecuteCommandAsync<string>(
145136
readLineCommand,

0 commit comments

Comments
 (0)