diff --git a/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs b/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs index 24f117699..185a1aac0 100644 --- a/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs +++ b/src/PowerShellEditorServices.Protocol/DebugAdapter/AttachRequest.cs @@ -20,7 +20,7 @@ public class AttachRequestArguments public string ProcessId { get; set; } - public int RunspaceId { get; set; } + public string RunspaceId { get; set; } public string CustomPipeName { get; set; } } diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/GetRunspaceRequest.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/GetRunspaceRequest.cs new file mode 100644 index 000000000..e151aa7f0 --- /dev/null +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/GetRunspaceRequest.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; + +namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer +{ + public class GetRunspaceRequest + { + public static readonly + RequestType Type = + RequestType.Create("powerShell/getRunspace"); + } + + public class GetRunspaceResponse + { + public int Id { get; set; } + + public string Name { get; set; } + + public string Availability { get; set; } + } +} diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs index 88fc797e1..5db738b80 100644 --- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs +++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs @@ -450,7 +450,7 @@ await requestContext.SendErrorAsync( return; } } - else + else if (attachParams.ProcessId != "current") { Logger.Write( LogLevel.Error, @@ -469,7 +469,20 @@ await requestContext.SendErrorAsync( // will block the debug adapter initialization process. The // InitializedEvent will be sent as soon as the RunspaceChanged // event gets fired with the attached runspace. - int runspaceId = attachParams.RunspaceId > 0 ? attachParams.RunspaceId : 1; + + var runspaceId = 1; + if (!int.TryParse(attachParams.RunspaceId, out runspaceId) || runspaceId <= 0) + { + Logger.Write( + LogLevel.Error, + $"Attach request failed, '{attachParams.RunspaceId}' is an invalid value for the processId."); + + await requestContext.SendErrorAsync( + "A positive integer must be specified for the RunspaceId field."); + + return; + } + _waitingForAttach = true; Task nonAwaitedTask = _editorSession.PowerShellContext .ExecuteScriptStringAsync($"\nDebug-Runspace -Id {runspaceId}") diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index d325b2d65..37e5ae742 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Management.Automation; using System.Management.Automation.Language; +using System.Management.Automation.Runspaces; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -161,6 +162,8 @@ public void Start() this.messageHandlers.SetRequestHandler(GetPSHostProcessesRequest.Type, this.HandleGetPSHostProcessesRequestAsync); this.messageHandlers.SetRequestHandler(CommentHelpRequest.Type, this.HandleCommentHelpRequestAsync); + this.messageHandlers.SetRequestHandler(GetRunspaceRequest.Type, this.HandleGetRunspaceRequestAsync); + // Initialize the extension service // TODO: This should be made awaited once Initialize is async! this.editorSession.ExtensionService.InitializeAsync( @@ -1218,6 +1221,54 @@ protected async Task HandleCommentHelpRequestAsync( await requestContext.SendResultAsync(result); } + protected async Task HandleGetRunspaceRequestAsync( + string processId, + RequestContext requestContext) + { + var runspaceResponses = new List(); + + if (this.editorSession.PowerShellContext.LocalPowerShellVersion.Version.Major >= 5) + { + if (processId == null) { + processId = "current"; + } + + var isNotCurrentProcess = processId != null && processId != "current"; + + var psCommand = new PSCommand(); + + if (isNotCurrentProcess) { + psCommand.AddCommand("Enter-PSHostProcess").AddParameter("Id", processId).AddStatement(); + } + + psCommand.AddCommand("Get-Runspace"); + + StringBuilder sb = new StringBuilder(); + IEnumerable runspaces = await editorSession.PowerShellContext.ExecuteCommandAsync(psCommand, sb); + if (runspaces != null) + { + foreach (var p in runspaces) + { + runspaceResponses.Add( + new GetRunspaceResponse + { + Id = p.Id, + Name = p.Name, + Availability = p.RunspaceAvailability.ToString() + }); + } + } + + if (isNotCurrentProcess) { + var exitCommand = new PSCommand(); + exitCommand.AddCommand("Exit-PSHostProcess"); + await editorSession.PowerShellContext.ExecuteCommandAsync(exitCommand); + } + } + + await requestContext.SendResultAsync(runspaceResponses.ToArray()); + } + private bool IsQueryMatch(string query, string symbolName) { return symbolName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;