From dcb5f3bc5f1407e8b201a5b6991d3f302947fe48 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 16 May 2017 07:46:13 -0700 Subject: [PATCH] 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. --- .../LanguageServer/StartDebuggerEvent.cs | 16 ++++++++ .../Server/DebugAdapter.cs | 21 ++++++++-- .../Server/LanguageServer.cs | 11 +++++ .../Debugging/DebugService.cs | 40 +++++++++++++++++-- 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/PowerShellEditorServices.Protocol/LanguageServer/StartDebuggerEvent.cs diff --git a/src/PowerShellEditorServices.Protocol/LanguageServer/StartDebuggerEvent.cs b/src/PowerShellEditorServices.Protocol/LanguageServer/StartDebuggerEvent.cs new file mode 100644 index 000000000..49adef43a --- /dev/null +++ b/src/PowerShellEditorServices.Protocol/LanguageServer/StartDebuggerEvent.cs @@ -0,0 +1,16 @@ +// +// 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 StartDebuggerEvent + { + public static readonly + NotificationType Type = + NotificationType.Create("powerShell/startDebugger"); + } +} \ No newline at end of file diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs index cdc059e43..dd24032e9 100644 --- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs +++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs @@ -162,6 +162,8 @@ private async Task OnExecutionCompleted(Task executeTask) } } + this.editorSession.DebugService.IsClientAttached = false; + if (this.disconnectRequestContext != null) { // Respond to the disconnect request and stop the server @@ -207,6 +209,8 @@ protected async Task HandleConfigurationDoneRequest( object args, RequestContext requestContext) { + this.editorSession.DebugService.IsClientAttached = true; + if (!string.IsNullOrEmpty(this.scriptToLaunch)) { if (this.editorSession.PowerShellContext.SessionState == PowerShellContextState.Ready) @@ -225,6 +229,16 @@ protected async Task HandleConfigurationDoneRequest( } await requestContext.SendResult(null); + + if (this.isInteractiveDebugSession && + this.editorSession.DebugService.IsDebuggerStopped) + { + // If this is an interactive session and there's a pending breakpoint, + // send that information along to the debugger client + this.DebugService_DebuggerStopped( + this, + this.editorSession.DebugService.CurrentDebuggerStoppedEventArgs); + } } protected async Task HandleLaunchRequest( @@ -270,8 +284,8 @@ protected async Task HandleLaunchRequest( #endif } - // TODO: What's the right approach here? - if (this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Local) + if (this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Local && + !this.editorSession.DebugService.IsDebuggerStopped) { await editorSession.PowerShellContext.SetWorkingDirectory(workingDir); Logger.Write(LogLevel.Verbose, "Working dir set to: " + workingDir); @@ -294,7 +308,8 @@ protected async Task HandleLaunchRequest( // If the current session is remote, map the script path to the remote // machine if necessary - if (this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Remote) + if (this.scriptToLaunch != null && + this.editorSession.PowerShellContext.CurrentRunspace.Location == RunspaceLocation.Remote) { this.scriptToLaunch = this.editorSession.RemoteFileManager.GetMappedPath( diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index b22c11504..bec59a8f0 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using Microsoft.PowerShell.EditorServices.Debugging; using Microsoft.PowerShell.EditorServices.Extensions; using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; @@ -82,6 +83,7 @@ public LanguageServer( this); this.editorSession.StartDebugService(this.editorOperations); + this.editorSession.DebugService.DebuggerStopped += DebugService_DebuggerStopped; if (enableConsoleRepl) { @@ -1193,6 +1195,15 @@ await this.SendEvent( }); } + private async void DebugService_DebuggerStopped(object sender, DebuggerStoppedEventArgs e) + { + if (!this.editorSession.DebugService.IsClientAttached) + { + await this.SendEvent( + StartDebuggerEvent.Type, + new StartDebuggerEvent()); + } + } #endregion diff --git a/src/PowerShellEditorServices/Debugging/DebugService.cs b/src/PowerShellEditorServices/Debugging/DebugService.cs index e601d2037..6d4c92510 100644 --- a/src/PowerShellEditorServices/Debugging/DebugService.cs +++ b/src/PowerShellEditorServices/Debugging/DebugService.cs @@ -48,6 +48,28 @@ public class DebugService #endregion + #region Properties + + /// + /// Gets or sets a boolean that indicates whether a debugger client is + /// currently attached to the debugger. + /// + public bool IsClientAttached { get; set; } + + /// + /// Gets a boolean that indicates whether the debugger is currently + /// stopped at a breakpoint. + /// + public bool IsDebuggerStopped => this.powerShellContext.IsDebuggerStopped; + + /// + /// Gets the current DebuggerStoppedEventArgs when the debugger + /// is stopped. + /// + public DebuggerStoppedEventArgs CurrentDebuggerStoppedEventArgs { get; private set; } + + #endregion + #region Constructors /// @@ -80,6 +102,8 @@ public DebugService( this.powerShellContext = powerShellContext; this.powerShellContext.DebuggerStop += this.OnDebuggerStop; + this.powerShellContext.DebuggerResumed += this.OnDebuggerResumed; + this.powerShellContext.BreakpointUpdated += this.OnBreakpointUpdated; this.remoteFileManager = remoteFileManager; @@ -1126,13 +1150,21 @@ await this.remoteFileManager.FetchRemoteFile( } } - // Notify the host that the debugger is stopped - this.DebuggerStopped?.Invoke( - sender, + this.CurrentDebuggerStoppedEventArgs = new DebuggerStoppedEventArgs( e, this.powerShellContext.CurrentRunspace, - localScriptPath)); + localScriptPath); + + // Notify the host that the debugger is stopped + this.DebuggerStopped?.Invoke( + sender, + this.CurrentDebuggerStoppedEventArgs); + } + + private void OnDebuggerResumed(object sender, DebuggerResumeAction e) + { + this.CurrentDebuggerStoppedEventArgs = null; } ///