Skip to content

Commit 13d8f8a

Browse files
adamdriscollTylerLeonhardt
authored andcommitted
Add attach to local runspace. (#875)
* Add attach to local runspace. * Remove comment. * Use single runspaceId property. * Remove unnecessary processId check. * Factored if. * Update src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs It's neat that we can just commit a suggestion. Co-Authored-By: adamdriscoll <adamdriscoll@users.noreply.github.com> * Use runspace rather than dynamic. * Accept process ID for GetRunspaceRequest. * Clean up.
1 parent 0b51e07 commit 13d8f8a

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class AttachRequestArguments
2020

2121
public string ProcessId { get; set; }
2222

23-
public int RunspaceId { get; set; }
23+
public string RunspaceId { get; set; }
2424

2525
public string CustomPipeName { get; set; }
2626
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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 Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
7+
8+
namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer
9+
{
10+
public class GetRunspaceRequest
11+
{
12+
public static readonly
13+
RequestType<string, GetRunspaceResponse[], object, object> Type =
14+
RequestType<string, GetRunspaceResponse[], object, object>.Create("powerShell/getRunspace");
15+
}
16+
17+
public class GetRunspaceResponse
18+
{
19+
public int Id { get; set; }
20+
21+
public string Name { get; set; }
22+
23+
public string Availability { get; set; }
24+
}
25+
}

src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

+15-2
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ await requestContext.SendErrorAsync(
450450
return;
451451
}
452452
}
453-
else
453+
else if (attachParams.ProcessId != "current")
454454
{
455455
Logger.Write(
456456
LogLevel.Error,
@@ -469,7 +469,20 @@ await requestContext.SendErrorAsync(
469469
// will block the debug adapter initialization process. The
470470
// InitializedEvent will be sent as soon as the RunspaceChanged
471471
// event gets fired with the attached runspace.
472-
int runspaceId = attachParams.RunspaceId > 0 ? attachParams.RunspaceId : 1;
472+
473+
var runspaceId = 1;
474+
if (!int.TryParse(attachParams.RunspaceId, out runspaceId) || runspaceId <= 0)
475+
{
476+
Logger.Write(
477+
LogLevel.Error,
478+
$"Attach request failed, '{attachParams.RunspaceId}' is an invalid value for the processId.");
479+
480+
await requestContext.SendErrorAsync(
481+
"A positive integer must be specified for the RunspaceId field.");
482+
483+
return;
484+
}
485+
473486
_waitingForAttach = true;
474487
Task nonAwaitedTask = _editorSession.PowerShellContext
475488
.ExecuteScriptStringAsync($"\nDebug-Runspace -Id {runspaceId}")

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

+51
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Linq;
1919
using System.Management.Automation;
2020
using System.Management.Automation.Language;
21+
using System.Management.Automation.Runspaces;
2122
using System.Text;
2223
using System.Text.RegularExpressions;
2324
using System.Threading;
@@ -161,6 +162,8 @@ public void Start()
161162
this.messageHandlers.SetRequestHandler(GetPSHostProcessesRequest.Type, this.HandleGetPSHostProcessesRequestAsync);
162163
this.messageHandlers.SetRequestHandler(CommentHelpRequest.Type, this.HandleCommentHelpRequestAsync);
163164

165+
this.messageHandlers.SetRequestHandler(GetRunspaceRequest.Type, this.HandleGetRunspaceRequestAsync);
166+
164167
// Initialize the extension service
165168
// TODO: This should be made awaited once Initialize is async!
166169
this.editorSession.ExtensionService.InitializeAsync(
@@ -1218,6 +1221,54 @@ protected async Task HandleCommentHelpRequestAsync(
12181221
await requestContext.SendResultAsync(result);
12191222
}
12201223

1224+
protected async Task HandleGetRunspaceRequestAsync(
1225+
string processId,
1226+
RequestContext<GetRunspaceResponse[]> requestContext)
1227+
{
1228+
var runspaceResponses = new List<GetRunspaceResponse>();
1229+
1230+
if (this.editorSession.PowerShellContext.LocalPowerShellVersion.Version.Major >= 5)
1231+
{
1232+
if (processId == null) {
1233+
processId = "current";
1234+
}
1235+
1236+
var isNotCurrentProcess = processId != null && processId != "current";
1237+
1238+
var psCommand = new PSCommand();
1239+
1240+
if (isNotCurrentProcess) {
1241+
psCommand.AddCommand("Enter-PSHostProcess").AddParameter("Id", processId).AddStatement();
1242+
}
1243+
1244+
psCommand.AddCommand("Get-Runspace");
1245+
1246+
StringBuilder sb = new StringBuilder();
1247+
IEnumerable<Runspace> runspaces = await editorSession.PowerShellContext.ExecuteCommandAsync<Runspace>(psCommand, sb);
1248+
if (runspaces != null)
1249+
{
1250+
foreach (var p in runspaces)
1251+
{
1252+
runspaceResponses.Add(
1253+
new GetRunspaceResponse
1254+
{
1255+
Id = p.Id,
1256+
Name = p.Name,
1257+
Availability = p.RunspaceAvailability.ToString()
1258+
});
1259+
}
1260+
}
1261+
1262+
if (isNotCurrentProcess) {
1263+
var exitCommand = new PSCommand();
1264+
exitCommand.AddCommand("Exit-PSHostProcess");
1265+
await editorSession.PowerShellContext.ExecuteCommandAsync(exitCommand);
1266+
}
1267+
}
1268+
1269+
await requestContext.SendResultAsync(runspaceResponses.ToArray());
1270+
}
1271+
12211272
private bool IsQueryMatch(string query, string symbolName)
12221273
{
12231274
return symbolName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;

0 commit comments

Comments
 (0)