@@ -45,6 +45,10 @@ public SynchronousPowerShellTask(
4545
4646 public override ExecutionOptions ExecutionOptions => PowerShellExecutionOptions ;
4747
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+
4852 public override IReadOnlyList < TResult > Run ( CancellationToken cancellationToken )
4953 {
5054 _pwsh = _psesHost . CurrentPowerShell ;
@@ -55,6 +59,8 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
5559 }
5660
5761 return _pwsh . Runspace . Debugger . InBreakpoint
62+ // TODO: Case insensitive?
63+ && Array . Exists ( DebuggerCommands , c => c == _psCommand . GetInvocationText ( ) )
5864 ? ExecuteInDebugger ( cancellationToken )
5965 : ExecuteNormally ( cancellationToken ) ;
6066 }
@@ -89,9 +95,15 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
8995 result = _pwsh . InvokeCommand < TResult > ( _psCommand , invocationSettings ) ;
9096 cancellationToken . ThrowIfCancellationRequested ( ) ;
9197 }
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.
93100 catch ( Exception e ) when ( cancellationToken . IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException )
94101 {
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+ }
95107 throw new OperationCanceledException ( ) ;
96108 }
97109 // We only catch RuntimeExceptions here in case writing errors to output was requested
@@ -124,6 +136,8 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
124136
125137 private IReadOnlyList < TResult > ExecuteInDebugger ( CancellationToken cancellationToken )
126138 {
139+ // TODO: How much of this method can we remove now that it only processes PowerShell's
140+ // intrinsic debugger commands?
127141 cancellationToken . Register ( CancelDebugExecution ) ;
128142
129143 var outputCollection = new PSDataCollection < PSObject > ( ) ;
@@ -148,14 +162,22 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
148162 DebuggerCommandResults debuggerResult = null ;
149163 try
150164 {
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.
155175 debuggerResult = _pwsh . Runspace . Debugger . ProcessCommand ( _psCommand , outputCollection ) ;
156176 cancellationToken . ThrowIfCancellationRequested ( ) ;
157177 }
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.
159181 catch ( Exception e ) when ( cancellationToken . IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException )
160182 {
161183 StopDebuggerIfRemoteDebugSessionFailed ( ) ;
0 commit comments