Skip to content

Commit a4ea69a

Browse files
Fix execution of debug prompt commands (#1803)
Thanks to a brilliant idea from Patrick, this simplifies how we choose which commands to execute through PowerShell's debugger API, and also fixes an issue where a user's custom prompt function wasn't aware that it was in the debugger.
1 parent 090448c commit a4ea69a

File tree

1 file changed

+13
-19
lines changed

1 file changed

+13
-19
lines changed

src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs

+13-19
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@ public SynchronousPowerShellTask(
4848

4949
public override ExecutionOptions ExecutionOptions => PowerShellExecutionOptions;
5050

51-
// These are PowerShell's intrinsic debugger commands that must be run via
52-
// `ProcessDebugCommand`.
53-
private static readonly string[] DebuggerCommands = { "continue", "c", "k", "h", "?", "list", "l", "stepInto", "s", "stepOut", "o", "stepOver", "v", "quit", "q", "detach", "d" };
54-
5551
public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
5652
{
5753
_psesHost.Runspace.ThrowCancelledIfUnusable();
@@ -65,8 +61,14 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
6561
_psesHost.WriteWithPrompt(_psCommand, cancellationToken);
6662
}
6763

64+
// If we're in a breakpoint it means we're executing either interactive commands in
65+
// a debug prompt, or our own special commands to query the PowerShell debugger for
66+
// state that we sync with the LSP debugger. The former commands we want to send
67+
// through PowerShell's `Debugger.ProcessCommand` so that they work as expected, but
68+
// the latter we must not send through it else they pollute the history as this
69+
// PowerShell API does not let us exclude them from it.
6870
return _pwsh.Runspace.Debugger.InBreakpoint
69-
&& (IsDebuggerCommand(_psCommand) || _pwsh.Runspace.RunspaceIsRemote)
71+
&& (PowerShellExecutionOptions.AddToHistory || IsPromptCommand(_psCommand) || _pwsh.Runspace.RunspaceIsRemote)
7072
? ExecuteInDebugger(cancellationToken)
7173
: ExecuteNormally(cancellationToken);
7274
}
@@ -78,7 +80,7 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
7880

7981
public override string ToString() => _psCommand.GetInvocationText();
8082

81-
private static bool IsDebuggerCommand(PSCommand command)
83+
private static bool IsPromptCommand(PSCommand command)
8284
{
8385
if (command.Commands.Count is not 1
8486
|| command.Commands[0] is { IsScript: false } or { Parameters.Count: > 0 })
@@ -87,15 +89,7 @@ private static bool IsDebuggerCommand(PSCommand command)
8789
}
8890

8991
string commandText = command.Commands[0].CommandText;
90-
foreach (string knownCommand in DebuggerCommands)
91-
{
92-
if (commandText.Equals(knownCommand, StringComparison.OrdinalIgnoreCase))
93-
{
94-
return true;
95-
}
96-
}
97-
98-
return false;
92+
return commandText.Equals("prompt", StringComparison.OrdinalIgnoreCase);
9993
}
10094

10195
private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationToken)
@@ -124,7 +118,7 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
124118
result = _pwsh.InvokeCommand<TResult>(_psCommand, invocationSettings);
125119
cancellationToken.ThrowIfCancellationRequested();
126120
}
127-
// Allow terminate exceptions to propogate for flow control.
121+
// Allow terminate exceptions to propagate for flow control.
128122
catch (TerminateException)
129123
{
130124
throw;
@@ -222,12 +216,12 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
222216
//
223217
// Unfortunately, this API does not allow us to pass in the InvocationSettings,
224218
// which means (for instance) that we cannot instruct it to avoid adding our
225-
// debugger implmentation's commands to the history. So instead we now only call
219+
// debugger implementation's commands to the history. So instead we now only call
226220
// `ExecuteInDebugger` for PowerShell's own intrinsic debugger commands.
227221
debuggerResult = _pwsh.Runspace.Debugger.ProcessCommand(_psCommand, outputCollection);
228222
cancellationToken.ThrowIfCancellationRequested();
229223
}
230-
// Allow terminate exceptions to propogate for flow control.
224+
// Allow terminate exceptions to propagate for flow control.
231225
catch (TerminateException)
232226
{
233227
throw;
@@ -281,7 +275,7 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
281275

282276
_psesHost.DebugContext.ProcessDebuggerResult(debuggerResult);
283277

284-
// Optimisation to save wasted computation if we're going to throw the output away anyway
278+
// Optimization to save wasted computation if we're going to throw the output away anyway
285279
if (PowerShellExecutionOptions.WriteOutputToHost)
286280
{
287281
return Array.Empty<TResult>();

0 commit comments

Comments
 (0)