Skip to content

Avoid recording debugger commands in the history #1704

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
Feb 16, 2022
Merged
Show file tree
Hide file tree
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 @@ -45,6 +45,10 @@ public SynchronousPowerShellTask(

public override ExecutionOptions ExecutionOptions => PowerShellExecutionOptions;

// These are PowerShell's intrinsic debugger commands that must be run via
// `ProcessDebugCommand`.
private static readonly string[] DebuggerCommands = {"continue", "c", "k", "h", "?", "list", "l", "stepInto", "s", "stepOut", "o", "stepOver", "v", "quit", "q", "detach", "d"};

public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
{
_pwsh = _psesHost.CurrentPowerShell;
Expand All @@ -55,6 +59,9 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
}

return _pwsh.Runspace.Debugger.InBreakpoint
&& Array.Exists(
DebuggerCommands,
c => c.Equals(_psCommand.GetInvocationText(), StringComparison.CurrentCultureIgnoreCase))
? ExecuteInDebugger(cancellationToken)
: ExecuteNormally(cancellationToken);
}
Expand Down Expand Up @@ -89,9 +96,15 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
result = _pwsh.InvokeCommand<TResult>(_psCommand, invocationSettings);
cancellationToken.ThrowIfCancellationRequested();
}
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
// effectively means the pipeline was stopped.
catch (Exception e) when (cancellationToken.IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException)
{
// ExecuteNormally handles user commands in a debug session. Perhaps we should clean all this up somehow.
if (_pwsh.Runspace.Debugger.InBreakpoint)
{
StopDebuggerIfRemoteDebugSessionFailed();
}
throw new OperationCanceledException();
}
// We only catch RuntimeExceptions here in case writing errors to output was requested
Expand Down Expand Up @@ -124,6 +137,8 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok

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

var outputCollection = new PSDataCollection<PSObject>();
Expand All @@ -148,14 +163,22 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
DebuggerCommandResults debuggerResult = null;
try
{
// In the PowerShell debugger, extra debugger commands are made available, like "l", "s", "c", etc.
// Executing those commands produces a result that needs to be set on the debugger stop event args.
// So we use the Debugger.ProcessCommand() API to properly execute commands in the debugger
// and then call DebugContext.ProcessDebuggerResult() later to handle the command appropriately
// In the PowerShell debugger, intrinsic debugger commands are made available, like
// "l", "s", "c", etc. Executing those commands produces a result that needs to be
// set on the debugger stop event args. So we use the Debugger.ProcessCommand() API
// to properly execute commands in the debugger and then call
// DebugContext.ProcessDebuggerResult() later to handle the command appropriately
//
// Unfortunately, this API does not allow us to pass in the InvocationSettings,
// which means (for instance) that we cannot instruct it to avoid adding our
// debugger implmentation's commands to the history. So instead we now only call
// `ExecuteInDebugger` for PowerShell's own intrinsic debugger commands.
debuggerResult = _pwsh.Runspace.Debugger.ProcessCommand(_psCommand, outputCollection);
cancellationToken.ThrowIfCancellationRequested();
}
// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.

// Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
// effectively means the pipeline was stopped.
catch (Exception e) when (cancellationToken.IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException)
{
StopDebuggerIfRemoteDebugSessionFailed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,9 @@ await debugService.SetLineBreakpointsAsync(
VariableDetailsBase[] variables = GetVariables(VariableContainerDetails.LocalScopeName);

// Test set of a local string variable (not strongly typed)
const string newStrValue = "Goodbye";
const string newStrValue = "\"Goodbye\"";
VariableScope localScope = Array.Find(scopes, s => s.Name == VariableContainerDetails.LocalScopeName);
// TODO: Fix this so it has the second quotes again?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quotes are back!

string setStrValue = await debugService.SetVariableAsync(localScope.Id, "$strVar", '"' + newStrValue + '"').ConfigureAwait(true);
string setStrValue = await debugService.SetVariableAsync(localScope.Id, "$strVar", newStrValue).ConfigureAwait(true);
Assert.Equal(newStrValue, setStrValue);

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