Skip to content

Commit dcb5f3b

Browse files
committed
Breakpoints hit when debugger isn't active now notify editor
This change is part of the fix for PowerShell/vscode-powershell#619 which states that hitting a breakpoint in the integrated console does not activate the debugger in VS Code. The fix is to check whether a debugger client is connected when a breakpoint is hit, and if not, send a notification through the language server to have the editor connect its debugger client.
1 parent 8bce076 commit dcb5f3b

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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 StartDebuggerEvent
11+
{
12+
public static readonly
13+
NotificationType<object, object> Type =
14+
NotificationType<object, object>.Create("powerShell/startDebugger");
15+
}
16+
}

src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

+18-3
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ private async Task OnExecutionCompleted(Task executeTask)
162162
}
163163
}
164164

165+
this.editorSession.DebugService.IsClientAttached = false;
166+
165167
if (this.disconnectRequestContext != null)
166168
{
167169
// Respond to the disconnect request and stop the server
@@ -207,6 +209,8 @@ protected async Task HandleConfigurationDoneRequest(
207209
object args,
208210
RequestContext<object> requestContext)
209211
{
212+
this.editorSession.DebugService.IsClientAttached = true;
213+
210214
if (!string.IsNullOrEmpty(this.scriptToLaunch))
211215
{
212216
if (this.editorSession.PowerShellContext.SessionState == PowerShellContextState.Ready)
@@ -225,6 +229,16 @@ protected async Task HandleConfigurationDoneRequest(
225229
}
226230

227231
await requestContext.SendResult(null);
232+
233+
if (this.isInteractiveDebugSession &&
234+
this.editorSession.DebugService.IsDebuggerStopped)
235+
{
236+
// If this is an interactive session and there's a pending breakpoint,
237+
// send that information along to the debugger client
238+
this.DebugService_DebuggerStopped(
239+
this,
240+
this.editorSession.DebugService.CurrentDebuggerStoppedEventArgs);
241+
}
228242
}
229243

230244
protected async Task HandleLaunchRequest(
@@ -270,8 +284,8 @@ protected async Task HandleLaunchRequest(
270284
#endif
271285
}
272286

273-
// TODO: What's the right approach here?
274-
if (this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Local)
287+
if (this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Local &&
288+
!this.editorSession.DebugService.IsDebuggerStopped)
275289
{
276290
await editorSession.PowerShellContext.SetWorkingDirectory(workingDir);
277291
Logger.Write(LogLevel.Verbose, "Working dir set to: " + workingDir);
@@ -294,7 +308,8 @@ protected async Task HandleLaunchRequest(
294308

295309
// If the current session is remote, map the script path to the remote
296310
// machine if necessary
297-
if (this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Remote)
311+
if (this.scriptToLaunch != null &&
312+
this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Remote)
298313
{
299314
this.scriptToLaunch =
300315
this.editorSession.RemoteFileManager.GetMappedPath(

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6+
using Microsoft.PowerShell.EditorServices.Debugging;
67
using Microsoft.PowerShell.EditorServices.Extensions;
78
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
89
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
@@ -82,6 +83,7 @@ public LanguageServer(
8283
this);
8384

8485
this.editorSession.StartDebugService(this.editorOperations);
86+
this.editorSession.DebugService.DebuggerStopped += DebugService_DebuggerStopped;
8587

8688
if (enableConsoleRepl)
8789
{
@@ -1193,6 +1195,15 @@ await this.SendEvent(
11931195
});
11941196
}
11951197

1198+
private async void DebugService_DebuggerStopped(object sender, DebuggerStoppedEventArgs e)
1199+
{
1200+
if (!this.editorSession.DebugService.IsClientAttached)
1201+
{
1202+
await this.SendEvent(
1203+
StartDebuggerEvent.Type,
1204+
new StartDebuggerEvent());
1205+
}
1206+
}
11961207

11971208
#endregion
11981209

src/PowerShellEditorServices/Debugging/DebugService.cs

+36-4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,28 @@ public class DebugService
4848

4949
#endregion
5050

51+
#region Properties
52+
53+
/// <summary>
54+
/// Gets or sets a boolean that indicates whether a debugger client is
55+
/// currently attached to the debugger.
56+
/// </summary>
57+
public bool IsClientAttached { get; set; }
58+
59+
/// <summary>
60+
/// Gets a boolean that indicates whether the debugger is currently
61+
/// stopped at a breakpoint.
62+
/// </summary>
63+
public bool IsDebuggerStopped => this.powerShellContext.IsDebuggerStopped;
64+
65+
/// <summary>
66+
/// Gets the current DebuggerStoppedEventArgs when the debugger
67+
/// is stopped.
68+
/// </summary>
69+
public DebuggerStoppedEventArgs CurrentDebuggerStoppedEventArgs { get; private set; }
70+
71+
#endregion
72+
5173
#region Constructors
5274

5375
/// <summary>
@@ -80,6 +102,8 @@ public DebugService(
80102

81103
this.powerShellContext = powerShellContext;
82104
this.powerShellContext.DebuggerStop += this.OnDebuggerStop;
105+
this.powerShellContext.DebuggerResumed += this.OnDebuggerResumed;
106+
83107
this.powerShellContext.BreakpointUpdated += this.OnBreakpointUpdated;
84108

85109
this.remoteFileManager = remoteFileManager;
@@ -1126,13 +1150,21 @@ await this.remoteFileManager.FetchRemoteFile(
11261150
}
11271151
}
11281152

1129-
// Notify the host that the debugger is stopped
1130-
this.DebuggerStopped?.Invoke(
1131-
sender,
1153+
this.CurrentDebuggerStoppedEventArgs =
11321154
new DebuggerStoppedEventArgs(
11331155
e,
11341156
this.powerShellContext.CurrentRunspace,
1135-
localScriptPath));
1157+
localScriptPath);
1158+
1159+
// Notify the host that the debugger is stopped
1160+
this.DebuggerStopped?.Invoke(
1161+
sender,
1162+
this.CurrentDebuggerStoppedEventArgs);
1163+
}
1164+
1165+
private void OnDebuggerResumed(object sender, DebuggerResumeAction e)
1166+
{
1167+
this.CurrentDebuggerStoppedEventArgs = null;
11361168
}
11371169

11381170
/// <summary>

0 commit comments

Comments
 (0)