diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs index 5d32451ed..906b9fe4d 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs @@ -497,10 +497,22 @@ public async Task EvaluateExpressionAsync( bool writeResultAsOutput) { PSCommand command = new PSCommand().AddScript(expressionString); - IReadOnlyList results = await _executionService.ExecutePSCommandAsync( - command, - CancellationToken.None, - new PowerShellExecutionOptions { WriteOutputToHost = writeResultAsOutput, ThrowOnError = !writeResultAsOutput }).ConfigureAwait(false); + IReadOnlyList results; + try + { + results = await _executionService.ExecutePSCommandAsync( + command, + CancellationToken.None, + new PowerShellExecutionOptions { WriteOutputToHost = writeResultAsOutput, ThrowOnError = !writeResultAsOutput }).ConfigureAwait(false); + } + catch (Exception e) + { + // If a watch expression throws we want to show the exception. + // TODO: Show the exception as an expandable object. + return new VariableDetails( + expressionString, + $"{e.GetType().Name}: {e.Message}"); + } // Since this method should only be getting invoked in the debugger, // we can assume that Out-String will be getting used to format results diff --git a/src/PowerShellEditorServices/Services/PowerShell/Debugging/PowerShellDebugContext.cs b/src/PowerShellEditorServices/Services/PowerShell/Debugging/PowerShellDebugContext.cs index 36aaad0e2..236403e5a 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Debugging/PowerShellDebugContext.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Debugging/PowerShellDebugContext.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Context; using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host; using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility; @@ -145,15 +146,27 @@ public void SetDebugResuming(DebuggerResumeAction debuggerResumeAction) // TODO: We need to assign cancellation tokens to each frame, because the current // logic results in a deadlock here when we try to cancel the scopes...which // includes ourself (hence running it in a separate thread). - Task.Run(() => _psesHost.UnwindCallStack()); + _ = Task.Run(() => _psesHost.UnwindCallStack()); return; } // Otherwise we're continuing or stepping (i.e. resuming) so we need to cancel the // debugger REPL. - if (_psesHost.CurrentFrame.IsRepl) + PowerShellFrameType frameType = _psesHost.CurrentFrame.FrameType; + if (frameType.HasFlag(PowerShellFrameType.Repl)) { _psesHost.CancelIdleParentTask(); + return; + } + + // If the user is running something via the REPL like `while ($true) { sleep 1 }` + // and then tries to step, we want to stop that so that execution can resume. + // + // This also applies to anything we're running on debugger stop like watch variables. + if (frameType.HasFlag(PowerShellFrameType.Debug | PowerShellFrameType.Nested)) + { + _psesHost.ForceSetExit(); + _psesHost.CancelIdleParentTask(); } } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs b/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs index 0661ce962..2fdefbfdc 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs @@ -382,7 +382,7 @@ internal void MaybeAddToHistory() private void CancelDebugExecution() { - if (_pwsh.Runspace.RunspaceStateInfo.IsUsable()) + if (!_pwsh.Runspace.RunspaceStateInfo.IsUsable()) { return; }