Skip to content
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

Fix debugging script blocks that aren't in files #2064

Merged
merged 1 commit into from
Sep 12, 2023
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
21 changes: 16 additions & 5 deletions src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -930,13 +930,24 @@ internal async void OnDebuggerStopAsync(object sender, DebuggerStopEventArgs e)
if (_remoteFileManager is not null && string.IsNullOrEmpty(localScriptPath))
{
// Get the current script listing and create the buffer
PSCommand command = new PSCommand().AddScript($"list 1 {int.MaxValue}");
IReadOnlyList<PSObject> scriptListingLines;
await debugInfoHandle.WaitAsync().ConfigureAwait(false);
try
{
// This command must be run through `ExecuteInDebugger`!
PSCommand psCommand = new PSCommand().AddScript($"list 1 {int.MaxValue}");

IReadOnlyList<PSObject> scriptListingLines =
await _executionService.ExecutePSCommandAsync<PSObject>(
command, CancellationToken.None).ConfigureAwait(false);
scriptListingLines =
await _executionService.ExecutePSCommandAsync<PSObject>(
psCommand,
CancellationToken.None).ConfigureAwait(false);
}
finally
{
debugInfoHandle.Release();
}

if (scriptListingLines is not null)
if (scriptListingLines.Count > 0)
{
int linePrefixLength = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
// state that we sync with the LSP debugger. The former commands we want to send
// through PowerShell's `Debugger.ProcessCommand` so that they work as expected, but
// the latter we must not send through it else they pollute the history as this
// PowerShell API does not let us exclude them from it.
// PowerShell API does not let us exclude them from it. Notably we also need to send
// the `prompt` command and our special `list 1 <MaxInt>` through the debugger too.
// The former needs the context in order to show `DBG 1>` etc., and the latter is
// used to gather the lines when debugging a script that isn't in a file.
return _pwsh.Runspace.Debugger.InBreakpoint
&& (PowerShellExecutionOptions.AddToHistory || IsPromptCommand(_psCommand) || _pwsh.Runspace.RunspaceIsRemote)
&& (PowerShellExecutionOptions.AddToHistory || IsPromptOrListCommand(_psCommand) || _pwsh.Runspace.RunspaceIsRemote)
? ExecuteInDebugger(cancellationToken)
: ExecuteNormally(cancellationToken);
}
Expand All @@ -87,7 +90,7 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)

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

private static bool IsPromptCommand(PSCommand command)
private static bool IsPromptOrListCommand(PSCommand command)
{
if (command.Commands.Count is not 1
|| command.Commands[0] is { IsScript: false } or { Parameters.Count: > 0 })
Expand All @@ -96,7 +99,8 @@ private static bool IsPromptCommand(PSCommand command)
}

string commandText = command.Commands[0].CommandText;
return commandText.Equals("prompt", StringComparison.OrdinalIgnoreCase);
return commandText.Equals("prompt", StringComparison.OrdinalIgnoreCase)
|| commandText.Equals($"list 1 {int.MaxValue}", StringComparison.OrdinalIgnoreCase);
}

private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationToken)
Expand Down Expand Up @@ -301,11 +305,10 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
return Array.Empty<TResult>();
}

// If we've been asked for a PSObject, no need to allocate a new collection
if (typeof(TResult) == typeof(PSObject)
&& outputCollection is IReadOnlyList<TResult> resultCollection)
// If we've been asked for a PSObject, no need to convert
if (typeof(TResult) == typeof(PSObject))
{
return resultCollection;
return new List<PSObject>(outputCollection) as IReadOnlyList<TResult>;
}

// Otherwise, convert things over
Expand Down