Skip to content

Commit 1e8804a

Browse files
committed
Avoid recording debugger commands in the history
This changes how we decide to run a given command through `ExecuteInDebugger` or `ExecuteNormally`. It now restricts the former such that it is only used for PowerShell's intrinsic debugger commands (like `s`, `c`, etc.) and the latter is used for any other user command or, more importantly, our own implementation's debugger commands (like when we call `Get-Variable`).
1 parent d9e6fb5 commit 1e8804a

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

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

+27-6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public SynchronousPowerShellTask(
4343

4444
public override ExecutionOptions ExecutionOptions => PowerShellExecutionOptions;
4545

46+
// These are PowerShell's intrinsic debugger commands that must be run via
47+
// `ProcessDebugCommand`.
48+
private static readonly string[] DebuggerCommands = {"continue", "c", "k", "h", "?", "list", "l", "stepInto", "s", "stepOut", "o", "stepOver", "v", "quit", "q", "detach", "d"};
49+
4650
public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
4751
{
4852
_pwsh = _psesHost.CurrentPowerShell;
@@ -53,6 +57,7 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
5357
}
5458

5559
return _pwsh.Runspace.Debugger.InBreakpoint
60+
&& Array.Exists(DebuggerCommands, c => c == _psCommand.GetInvocationText())
5661
? ExecuteInDebugger(cancellationToken)
5762
: ExecuteNormally(cancellationToken);
5863
}
@@ -87,9 +92,15 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
8792
result = _pwsh.InvokeCommand<TResult>(_psCommand, invocationSettings);
8893
cancellationToken.ThrowIfCancellationRequested();
8994
}
90-
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
95+
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
96+
// effectively means the pipeline was stopped.
9197
catch (Exception e) when (cancellationToken.IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException)
9298
{
99+
// ExecuteNormally handles user commands in a debug session. Perhaps we should clean all this up somehow.
100+
if (_pwsh.Runspace.Debugger.InBreakpoint)
101+
{
102+
StopDebuggerIfRemoteDebugSessionFailed();
103+
}
93104
throw new OperationCanceledException();
94105
}
95106
// We only catch RuntimeExceptions here in case writing errors to output was requested
@@ -122,6 +133,8 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
122133

123134
private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationToken)
124135
{
136+
// TODO: How much of this method can we remove now that it only processes PowerShell's
137+
// intrinsic debugger commands?
125138
cancellationToken.Register(CancelDebugExecution);
126139

127140
var outputCollection = new PSDataCollection<PSObject>();
@@ -146,14 +159,22 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
146159
DebuggerCommandResults debuggerResult = null;
147160
try
148161
{
149-
// In the PowerShell debugger, extra debugger commands are made available, like "l", "s", "c", etc.
150-
// Executing those commands produces a result that needs to be set on the debugger stop event args.
151-
// So we use the Debugger.ProcessCommand() API to properly execute commands in the debugger
152-
// and then call DebugContext.ProcessDebuggerResult() later to handle the command appropriately
162+
// In the PowerShell debugger, intrinsic debugger commands are made available, like
163+
// "l", "s", "c", etc. Executing those commands produces a result that needs to be
164+
// set on the debugger stop event args. So we use the Debugger.ProcessCommand() API
165+
// to properly execute commands in the debugger and then call
166+
// DebugContext.ProcessDebuggerResult() later to handle the command appropriately
167+
//
168+
// Unfortunately, this API does not allow us to pass in the InvocationSettings,
169+
// which means (for instance) that we cannot instruct it to avoid adding our
170+
// debugger implmentation's commands to the history. So instead we now only call
171+
// `ExecuteInDebugger` for PowerShell's own intrinsic debugger commands.
153172
debuggerResult = _pwsh.Runspace.Debugger.ProcessCommand(_psCommand, outputCollection);
154173
cancellationToken.ThrowIfCancellationRequested();
155174
}
156-
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
175+
176+
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
177+
// effectively means the pipeline was stopped.
157178
catch (Exception e) when (cancellationToken.IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException)
158179
{
159180
StopDebuggerIfRemoteDebugSessionFailed();

test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -581,10 +581,9 @@ await debugService.SetLineBreakpointsAsync(
581581
VariableDetailsBase[] variables = GetVariables(VariableContainerDetails.LocalScopeName);
582582

583583
// Test set of a local string variable (not strongly typed)
584-
const string newStrValue = "Goodbye";
584+
const string newStrValue = "\"Goodbye\"";
585585
VariableScope localScope = Array.Find(scopes, s => s.Name == VariableContainerDetails.LocalScopeName);
586-
// TODO: Fix this so it has the second quotes again?
587-
string setStrValue = await debugService.SetVariableAsync(localScope.Id, "$strVar", '"' + newStrValue + '"').ConfigureAwait(true);
586+
string setStrValue = await debugService.SetVariableAsync(localScope.Id, "$strVar", newStrValue).ConfigureAwait(true);
588587
Assert.Equal(newStrValue, setStrValue);
589588

590589
// Test set of script scope int variable (not strongly typed)

0 commit comments

Comments
 (0)