Skip to content

Exit debugger stop early if cause is PSE #1818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 8, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Globalization;
using System.IO;
using System.Management.Automation.Host;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -39,6 +40,8 @@ internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRuns
private static string CommandsModulePath => Path.GetFullPath(Path.Combine(
s_bundledModulePath, "PowerShellEditorServices", "Commands", "PowerShellEditorServices.Commands.psd1"));

private static readonly PropertyInfo s_scriptDebuggerTriggerObjectProperty;

private readonly ILoggerFactory _loggerFactory;

private readonly ILogger _logger;
Expand Down Expand Up @@ -89,6 +92,21 @@ internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRuns

private bool _resettingRunspace;

static PsesInternalHost()
{
Type scriptDebuggerType = typeof(PSObject).Assembly
.GetType("System.Management.Automation.ScriptDebugger");

if (scriptDebuggerType is null)
{
return;
}

s_scriptDebuggerTriggerObjectProperty = scriptDebuggerType.GetProperty(
"TriggerObject",
BindingFlags.Instance | BindingFlags.NonPublic);
}

public PsesInternalHost(
ILoggerFactory loggerFactory,
ILanguageServerFacade languageServer,
Expand Down Expand Up @@ -1142,6 +1160,34 @@ internal void WaitForExternalDebuggerStops()

private void OnDebuggerStopped(object sender, DebuggerStopEventArgs debuggerStopEventArgs)
{
// If ErrorActionPreference is set to Break, any engine exception is going to trigger a
// pipeline stop. Technically this is the same behavior as a standalone PowerShell
// process, but we use pipeline stops with greater frequency due to features like run
// selection and terminating the debugger. Without this, if the "Stop" button is pressed
// then we hit this repeatedly.
//
// This info is publically accessible via `PSDebugContext` but we'd need to access it
// via a script. At this point in the call I'd prefer this to be as light as possible so
// we can escape ASAP but we may want to consider switching to that at some point.
if (!Runspace.RunspaceIsRemote && s_scriptDebuggerTriggerObjectProperty is not null)
{
object triggerObject = null;
try
{
triggerObject = s_scriptDebuggerTriggerObjectProperty.GetValue(Runspace.Debugger);
}
catch
{
// Ignore all exceptions. There shouldn't be any, but as this is implementation
// detail that is subject to change it's best to be overly cautious.
}

if (triggerObject is PipelineStoppedException pse)
{
throw pse;
}
}

// The debugger has officially started. We use this to later check if we should stop it.
DebugContext.IsActive = true;

Expand Down