@@ -94,7 +94,7 @@ public void EnableDebugMode()
9494 _psesHost . Runspace . Debugger . SetDebugMode ( DebugModes . LocalScript | DebugModes . RemoteScript ) ;
9595 }
9696
97- public void Abort ( ) => SetDebugResuming ( DebuggerResumeAction . Stop , isDisconnect : true ) ;
97+ public void Abort ( ) => SetDebugResuming ( DebuggerResumeAction . Stop ) ;
9898
9999 public void BreakExecution ( ) => _psesHost . Runspace . Debugger . SetDebuggerStepMode ( enabled : true ) ;
100100
@@ -106,10 +106,12 @@ public void EnableDebugMode()
106106
107107 public void StepOver ( ) => SetDebugResuming ( DebuggerResumeAction . StepOver ) ;
108108
109- public void SetDebugResuming ( DebuggerResumeAction debuggerResumeAction , bool isDisconnect = false )
109+ public void SetDebugResuming ( DebuggerResumeAction debuggerResumeAction )
110110 {
111- // NOTE: We exit because the paused/stopped debugger is currently in a prompt REPL, and
112- // to resume the debugger we must exit that REPL.
111+ // We exit because the paused/stopped debugger is currently in a prompt REPL, and to
112+ // resume the debugger we must exit that REPL. If we're continued from 'c' or 's', this
113+ // is already set and so is a no-op; but if the user clicks the continue or step button,
114+ // then this came over LSP and we need to set it.
113115 _psesHost . SetExit ( ) ;
114116
115117 if ( LastStopEventArgs is not null )
@@ -127,23 +129,31 @@ public void SetDebugResuming(DebuggerResumeAction debuggerResumeAction, bool isD
127129 return ;
128130 }
129131
130- if ( debuggerResumeAction is DebuggerResumeAction . Stop )
132+ // If we're stopping (or disconnecting, which is the same thing in LSP-land), then we
133+ // want to cancel any debug prompts, remote prompts, debugged scripts, etc. However, if
134+ // the debugged script has exited normally (or was quit with 'q'), we still get an LSP
135+ // notification that eventually lands here with a stop event. In this case, the debug
136+ // context is NOT active and we do not want to cancel the regular REPL.
137+ if ( ! _psesHost . DebugContext . IsActive )
131138 {
132- // If we're disconnecting we want to unwind all the way back to the default, local
133- // state. So we use UnwindCallStack here to ensure every context frame is cancelled.
134- if ( isDisconnect )
135- {
136- _psesHost . UnwindCallStack ( ) ;
137- return ;
138- }
139+ return ;
140+ }
139141
140- _psesHost . CancelIdleParentTask ( ) ;
142+ // If the debugger is active and we're stopping, we need to unwind everything.
143+ if ( debuggerResumeAction is DebuggerResumeAction . Stop )
144+ {
145+ // TODO: We need to assign cancellation tokens to each frame, because the current
146+ // logic results in a deadlock here when we try to cancel the scopes...which
147+ // includes ourself (hence running it in a separate thread).
148+ Task . Run ( ( ) => _psesHost . UnwindCallStack ( ) ) ;
141149 return ;
142150 }
143151
152+ // Otherwise we're continuing or stepping (i.e. resuming) so we need to cancel the
153+ // debugger REPL.
144154 if ( _psesHost . CurrentFrame . IsRepl )
145155 {
146- _psesHost . CancelCurrentTask ( ) ;
156+ _psesHost . CancelIdleParentTask ( ) ;
147157 }
148158 }
149159
@@ -166,15 +176,14 @@ public void ProcessDebuggerResult(DebuggerCommandResults debuggerResult)
166176 {
167177 if ( debuggerResult ? . ResumeAction is not null )
168178 {
169- SetDebugResuming ( debuggerResult . ResumeAction . Value ) ;
170-
171- // If a debugging command like `c` is specified in a nested remote
172- // debugging prompt we need to unwind the nested execution loop.
173- if ( _psesHost . CurrentFrame . IsRemote )
179+ // Since we're processing a command like 'c' or 's' remotely, we need to tell the
180+ // host to stop the remote REPL loop.
181+ if ( debuggerResult . ResumeAction is not DebuggerResumeAction . Stop || _psesHost . CurrentFrame . IsRemote )
174182 {
175183 _psesHost . ForceSetExit ( ) ;
176184 }
177185
186+ SetDebugResuming ( debuggerResult . ResumeAction . Value ) ;
178187 RaiseDebuggerResumingEvent ( new DebuggerResumingEventArgs ( debuggerResult . ResumeAction . Value ) ) ;
179188
180189 // The Terminate exception is used by the engine for flow control
0 commit comments