Skip to content

Commit ad9595e

Browse files
committed
Implement remote debugger waiting
1 parent 9902562 commit ad9595e

File tree

3 files changed

+103
-2
lines changed

3 files changed

+103
-2
lines changed

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

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
7979
cancellationToken.ThrowIfCancellationRequested();
8080
}
8181
}
82-
catch (Exception e) when (e is PipelineStoppedException || e is PSRemotingDataStructureException)
82+
catch (PipelineStoppedException)
83+
{
84+
throw new OperationCanceledException();
85+
}
86+
catch (PSRemotingDataStructureException e)
8387
{
8488
string message = $"Pipeline stopped while executing command:{Environment.NewLine}{Environment.NewLine}{e}";
8589
Logger.LogError(message);
@@ -131,7 +135,58 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
131135
};
132136
}
133137

134-
DebuggerCommandResults debuggerResult = _pwsh.Runspace.Debugger.ProcessCommand(_psCommand, outputCollection);
138+
DebuggerCommandResults debuggerResult = null;
139+
try
140+
{
141+
debuggerResult = _pwsh.Runspace.Debugger.ProcessCommand(_psCommand, outputCollection);
142+
143+
if (_executionOptions.PropagateCancellationToCaller)
144+
{
145+
cancellationToken.ThrowIfCancellationRequested();
146+
}
147+
}
148+
catch (PipelineStoppedException)
149+
{
150+
throw new OperationCanceledException();
151+
}
152+
catch (PSRemotingDataStructureException e)
153+
{
154+
string message = $"Pipeline stopped while executing command:{Environment.NewLine}{Environment.NewLine}{e}";
155+
Logger.LogError(message);
156+
throw new ExecutionCanceledException(message, e);
157+
}
158+
catch (RuntimeException e)
159+
{
160+
Logger.LogWarning($"Runtime exception occurred while executing command:{Environment.NewLine}{Environment.NewLine}{e}");
161+
162+
if (!_executionOptions.WriteOutputToHost)
163+
{
164+
throw;
165+
}
166+
167+
var errorOutputCollection = new PSDataCollection<PSObject>();
168+
errorOutputCollection.DataAdded += (object sender, DataAddedEventArgs args) =>
169+
{
170+
for (int i = args.Index; i < outputCollection.Count; i++)
171+
{
172+
_psHost.UI.WriteLine(outputCollection[i].ToString());
173+
}
174+
};
175+
176+
var command = new PSCommand()
177+
.AddDebugOutputCommand()
178+
.AddParameter("InputObject", e.ErrorRecord.AsPSObject());
179+
180+
_pwsh.Runspace.Debugger.ProcessCommand(command, errorOutputCollection);
181+
}
182+
finally
183+
{
184+
if (_pwsh.HadErrors)
185+
{
186+
_pwsh.Streams.Error.Clear();
187+
}
188+
}
189+
135190
_psRunspaceContext.ProcessDebuggerResult(debuggerResult);
136191

137192
// Optimisation to save wasted computation if we're going to throw the output away anyway

src/PowerShellEditorServices/Services/PowerShell/PowerShellExecutionService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,10 @@ private void RunPowerShellLoop(PowerShellFrameType powerShellFrameType)
649649

650650
private void OnDebuggerStopped(object sender, DebuggerStopEventArgs debuggerStopEventArgs)
651651
{
652+
CurrentPowerShell.WaitForRemoteOutputIfNeeded();
652653
_debuggingContext.OnDebuggerStop(sender, debuggerStopEventArgs);
653654
PushDebugPowerShell();
655+
CurrentPowerShell.ResumeRemoteOutputIfNeeded();
654656
}
655657

656658
private void SetDebuggerResuming(DebuggerResumeAction resumeAction)

src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,36 @@
33
using System.ComponentModel;
44
using System.Management.Automation;
55
using System.Management.Automation.Runspaces;
6+
using System.Reflection;
7+
using System.Runtime.CompilerServices;
68
using System.Text;
79
using SMA = System.Management.Automation;
810

911
namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility
1012
{
1113
internal static class PowerShellExtensions
1214
{
15+
private static readonly Action<SMA.PowerShell> s_waitForServicingComplete;
16+
17+
private static readonly Action<SMA.PowerShell> s_suspendIncomingData;
18+
19+
private static readonly Action<SMA.PowerShell> s_resumeIncomingData;
20+
21+
static PowerShellExtensions()
22+
{
23+
s_waitForServicingComplete = (Action<SMA.PowerShell>)Delegate.CreateDelegate(
24+
typeof(Action<SMA.PowerShell>),
25+
typeof(SMA.PowerShell).GetMethod("WaitForServicingComplete", BindingFlags.Instance | BindingFlags.NonPublic));
26+
27+
s_suspendIncomingData = (Action<SMA.PowerShell>)Delegate.CreateDelegate(
28+
typeof(Action<SMA.PowerShell>),
29+
typeof(SMA.PowerShell).GetMethod("SuspendIncomingData", BindingFlags.Instance | BindingFlags.NonPublic));
30+
31+
s_resumeIncomingData = (Action<SMA.PowerShell>)Delegate.CreateDelegate(
32+
typeof(Action<SMA.PowerShell>),
33+
typeof(SMA.PowerShell).GetMethod("ResumeIncomingData", BindingFlags.Instance | BindingFlags.NonPublic));
34+
}
35+
1336
public static Collection<TResult> InvokeAndClear<TResult>(this SMA.PowerShell pwsh)
1437
{
1538
try
@@ -46,6 +69,27 @@ public static void InvokeCommand(this SMA.PowerShell pwsh, PSCommand psCommand)
4669
pwsh.InvokeAndClear();
4770
}
4871

72+
public static void WaitForRemoteOutputIfNeeded(this SMA.PowerShell pwsh)
73+
{
74+
if (!pwsh.Runspace.RunspaceIsRemote)
75+
{
76+
return;
77+
}
78+
79+
s_waitForServicingComplete(pwsh);
80+
s_suspendIncomingData(pwsh);
81+
}
82+
83+
public static void ResumeRemoteOutputIfNeeded(this SMA.PowerShell pwsh)
84+
{
85+
if (!pwsh.Runspace.RunspaceIsRemote)
86+
{
87+
return;
88+
}
89+
90+
s_resumeIncomingData(pwsh);
91+
}
92+
4993
public static string GetErrorString(this SMA.PowerShell pwsh)
5094
{
5195
var sb = new StringBuilder(capacity: 1024)

0 commit comments

Comments
 (0)