@@ -45,6 +45,10 @@ public SynchronousPowerShellTask(
45
45
46
46
public override ExecutionOptions ExecutionOptions => PowerShellExecutionOptions ;
47
47
48
+ // These are PowerShell's intrinsic debugger commands that must be run via
49
+ // `ProcessDebugCommand`.
50
+ private static readonly string [ ] DebuggerCommands = { "continue" , "c" , "k" , "h" , "?" , "list" , "l" , "stepInto" , "s" , "stepOut" , "o" , "stepOver" , "v" , "quit" , "q" , "detach" , "d" } ;
51
+
48
52
public override IReadOnlyList < TResult > Run ( CancellationToken cancellationToken )
49
53
{
50
54
_pwsh = _psesHost . CurrentPowerShell ;
@@ -55,6 +59,8 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
55
59
}
56
60
57
61
return _pwsh . Runspace . Debugger . InBreakpoint
62
+ // TODO: Case insensitive?
63
+ && Array . Exists ( DebuggerCommands , c => c == _psCommand . GetInvocationText ( ) )
58
64
? ExecuteInDebugger ( cancellationToken )
59
65
: ExecuteNormally ( cancellationToken ) ;
60
66
}
@@ -89,9 +95,15 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
89
95
result = _pwsh . InvokeCommand < TResult > ( _psCommand , invocationSettings ) ;
90
96
cancellationToken . ThrowIfCancellationRequested ( ) ;
91
97
}
92
- // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
98
+ // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
99
+ // effectively means the pipeline was stopped.
93
100
catch ( Exception e ) when ( cancellationToken . IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException )
94
101
{
102
+ // ExecuteNormally handles user commands in a debug session. Perhaps we should clean all this up somehow.
103
+ if ( _pwsh . Runspace . Debugger . InBreakpoint )
104
+ {
105
+ StopDebuggerIfRemoteDebugSessionFailed ( ) ;
106
+ }
95
107
throw new OperationCanceledException ( ) ;
96
108
}
97
109
// We only catch RuntimeExceptions here in case writing errors to output was requested
@@ -124,6 +136,8 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
124
136
125
137
private IReadOnlyList < TResult > ExecuteInDebugger ( CancellationToken cancellationToken )
126
138
{
139
+ // TODO: How much of this method can we remove now that it only processes PowerShell's
140
+ // intrinsic debugger commands?
127
141
cancellationToken . Register ( CancelDebugExecution ) ;
128
142
129
143
var outputCollection = new PSDataCollection < PSObject > ( ) ;
@@ -148,14 +162,22 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
148
162
DebuggerCommandResults debuggerResult = null ;
149
163
try
150
164
{
151
- // In the PowerShell debugger, extra debugger commands are made available, like "l", "s", "c", etc.
152
- // Executing those commands produces a result that needs to be set on the debugger stop event args.
153
- // So we use the Debugger.ProcessCommand() API to properly execute commands in the debugger
154
- // and then call DebugContext.ProcessDebuggerResult() later to handle the command appropriately
165
+ // In the PowerShell debugger, intrinsic debugger commands are made available, like
166
+ // "l", "s", "c", etc. Executing those commands produces a result that needs to be
167
+ // set on the debugger stop event args. So we use the Debugger.ProcessCommand() API
168
+ // to properly execute commands in the debugger and then call
169
+ // DebugContext.ProcessDebuggerResult() later to handle the command appropriately
170
+ //
171
+ // Unfortunately, this API does not allow us to pass in the InvocationSettings,
172
+ // which means (for instance) that we cannot instruct it to avoid adding our
173
+ // debugger implmentation's commands to the history. So instead we now only call
174
+ // `ExecuteInDebugger` for PowerShell's own intrinsic debugger commands.
155
175
debuggerResult = _pwsh . Runspace . Debugger . ProcessCommand ( _psCommand , outputCollection ) ;
156
176
cancellationToken . ThrowIfCancellationRequested ( ) ;
157
177
}
158
- // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
178
+
179
+ // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
180
+ // effectively means the pipeline was stopped.
159
181
catch ( Exception e ) when ( cancellationToken . IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException )
160
182
{
161
183
StopDebuggerIfRemoteDebugSessionFailed ( ) ;
0 commit comments