@@ -60,19 +60,23 @@ const isError = function <T> (value: T | MVMError): boolean {
6060
6161export default class MatlabDebugAdaptor {
6262 static _nextId = 1 ;
63- private _debugServices : DebugServices ;
64- private _mvm : IMVM ;
63+ private readonly _debugServices : DebugServices ;
64+ private readonly _mvm : IMVM ;
6565
6666 private _numberOfStackFrames : number = - 1 ;
67+ private _currentMATLABFrame : number = - 1 ;
68+ private _pendingStackPromise ?: ResolvablePromise < void > ;
69+ private _followUpStackRequested : boolean = false ;
70+ private readonly _ignoreWorkspaceUpdates : boolean = false ;
6771
6872 private _pendingSetBreakpointPromise ?: ResolvablePromise < void > ;
69- private _pendingVariablesPromise ?: ResolvablePromise < void > ;
73+ private _pendingTemporaryStackChangePromise ?: ResolvablePromise < void > ;
7074
7175 private _breakpointChangeListeners : Array < ( type : BreakpointChangeType , bp : BreakpointInfo ) => void > = [ ] ;
7276
7377 private _matlabBreakpoints : BreakpointInfo [ ] = [ ] ;
7478
75- private _canonicalizedPathCache : Map < string , ResolvablePromise < string > > = new Map ( ) ;
79+ private readonly _canonicalizedPathCache : Map < string , ResolvablePromise < string > > = new Map ( ) ;
7680
7781 private _isCurrentlyStopped : boolean = false ;
7882 protected _isCurrentlyDebugging : boolean = false ;
@@ -84,7 +88,7 @@ export default class MatlabDebugAdaptor {
8488 this . _debugServices = debugServices ;
8589
8690 this . _pendingSetBreakpointPromise = undefined ;
87- this . _pendingVariablesPromise = undefined ;
91+ this . _pendingTemporaryStackChangePromise = undefined ;
8892
8993 this . _mvm . on ( IMVM . Events . stateChange , ( state : MatlabState ) => {
9094 if ( state === MatlabState . DISCONNECTED ) {
@@ -203,11 +207,15 @@ export default class MatlabDebugAdaptor {
203207 this . _pendingSetBreakpointPromise = createResolvablePromise ( ) ;
204208 }
205209
206- private async _waitForPendingVariablesRequest ( ) : Promise < void > {
207- while ( this . _pendingVariablesPromise !== undefined ) {
208- await this . _pendingVariablesPromise ;
210+ private async _waitForPendingStackChanges ( createNewPendingChange : boolean = true ) : Promise < void > {
211+ while ( this . _pendingTemporaryStackChangePromise !== undefined ) {
212+ await this . _pendingTemporaryStackChangePromise ;
213+ }
214+ this . _pendingTemporaryStackChangePromise = undefined ;
215+
216+ if ( createNewPendingChange ) {
217+ this . _pendingTemporaryStackChangePromise = createResolvablePromise ( ) ;
209218 }
210- this . _pendingVariablesPromise = createResolvablePromise ( ) ;
211219 }
212220
213221 private _clearPendingBreakpointsRequest ( ) : void {
@@ -216,9 +224,9 @@ export default class MatlabDebugAdaptor {
216224 oldPromise ?. resolve ( ) ;
217225 }
218226
219- private _clearPendingVariablesRequest ( ) : void {
220- const oldPromise = this . _pendingVariablesPromise ;
221- this . _pendingVariablesPromise = undefined ;
227+ private _clearPendingStackChanges ( ) : void {
228+ const oldPromise = this . _pendingTemporaryStackChangePromise ;
229+ this . _pendingTemporaryStackChangePromise = undefined ;
222230 oldPromise ?. resolve ( ) ;
223231 }
224232
@@ -280,8 +288,32 @@ export default class MatlabDebugAdaptor {
280288 this . _handleDebuggingStateChange ( ) ;
281289 }
282290
291+ this . _currentMATLABFrame = stack . length ;
292+
293+ void this . _requestStackUpdate ( ) ;
294+
295+ this . sendEvent ( new debug . StoppedEvent ( 'breakpoint' , 0 ) ) ;
296+ } ) ;
297+
298+ this . _debugServices . on ( DebugServices . Events . DBStop , async ( filename : string , lineNumber : number , stack : MatlabData [ ] ) => {
299+ this . _isCurrentlyStopped = true ;
300+
301+ const oldValue = this . _isCurrentlyDebugging ;
302+ this . _isCurrentlyDebugging = true ;
303+ if ( oldValue !== this . _isCurrentlyDebugging ) {
304+ this . _handleDebuggingStateChange ( ) ;
305+ }
306+
307+ this . _currentMATLABFrame = stack . length ;
308+
283309 this . sendEvent ( new debug . StoppedEvent ( 'breakpoint' , 0 ) ) ;
284310 } ) ;
311+
312+ this . _debugServices . on ( DebugServices . Events . DBWorkspaceChanged , ( ) => {
313+ if ( ! this . _ignoreWorkspaceUpdates ) {
314+ void this . _requestStackUpdate ( ) ;
315+ }
316+ } ) ;
285317 }
286318
287319 protected _handleDebuggingStateChange ( ) : void {
@@ -527,7 +559,6 @@ export default class MatlabDebugAdaptor {
527559 const size = stack . mwsize [ 0 ] ;
528560 const newStack = [ ] ;
529561 for ( let i = 0 ; i < size ; i ++ ) {
530-
531562 newStack . push ( new debug . StackFrame ( size - i + 1 , stack . mwdata . name [ i ] , new debug . Source ( stack . mwdata . name [ i ] , stack . mwdata . file [ i ] ) , Math . abs ( stack . mwdata . line [ i ] ) , 1 ) )
532563 }
533564 return newStack ;
@@ -630,7 +661,6 @@ export default class MatlabDebugAdaptor {
630661 }
631662
632663 async evaluateRequest ( response : DebugProtocol . EvaluateResponse , args : DebugProtocol . EvaluateArguments , request ?: DebugProtocol . Request ) : Promise < void > {
633-
634664 let stackChanger ;
635665 try {
636666 stackChanger = await this . _moveToFrame ( args . frameId ) ;
@@ -653,7 +683,7 @@ export default class MatlabDebugAdaptor {
653683 maybeResult = await this . _mvm . feval < MatlabData > ( 'evalc' , 1 , [ "try, datatipinfo('" + args . expression + "'), catch, disp('Error evaluating expression'); end" ] ) ;
654684 }
655685
656- await this . _mvm . feval ( 'feature' , 0 , [ 'HotLinks' , ( ( oldHotlinks as any ) ?. result ?. [ 0 ] ?? true ) ] ) ;
686+ await this . _mvm . feval ( 'feature' , 0 , [ 'HotLinks' , ( ( oldHotlinks as MatlabData ) ?. result ?. [ 0 ] ?? true ) ] ) ;
657687
658688 if ( stackChanger !== null ) {
659689 try {
@@ -679,8 +709,8 @@ export default class MatlabDebugAdaptor {
679709 this . sendResponse ( response ) ;
680710 return ;
681711 }
682- response . body = {
683- result : result ,
712+ response . body = {
713+ result,
684714 variablesReference : 0
685715 } ;
686716 response . body . type = 'string' ;
@@ -700,20 +730,24 @@ export default class MatlabDebugAdaptor {
700730 protected customRequest ( command : string , response : DebugProtocol . Response , args : any , request ?: DebugProtocol . Request ) : void {
701731 if ( command === 'cacheFilePath' ) {
702732 this . _getCanonicalPath ( args . fileName ) . then ( ( ) => { } , ( ) => { } ) ;
733+ } else if ( command === 'StackChange' ) {
734+ void this . _requestStackChange ( args . frame ) ;
703735 }
704736 this . sendResponse ( response ) ;
705737 }
706738
707739 private _cleanup ( ) : void {
708740 this . _numberOfStackFrames = - 1 ;
709- if ( this . _pendingSetBreakpointPromise != null ) {
710- this . _pendingSetBreakpointPromise . reject ( ) ;
711- this . _pendingSetBreakpointPromise = undefined ;
712- }
713- if ( this . _pendingVariablesPromise != null ) {
714- this . _pendingVariablesPromise . reject ( ) ;
715- this . _pendingVariablesPromise = undefined ;
716- }
741+
742+ this . _pendingStackPromise ?. reject ( ) ;
743+ this . _pendingStackPromise = undefined ;
744+ this . _followUpStackRequested = false ;
745+
746+ this . _pendingSetBreakpointPromise ?. reject ( ) ;
747+ this . _pendingSetBreakpointPromise = undefined ;
748+ this . _pendingTemporaryStackChangePromise ?. reject ( ) ;
749+ this . _pendingTemporaryStackChangePromise = undefined ;
750+
717751 this . _breakpointChangeListeners = [ ] ;
718752 }
719753
@@ -730,12 +764,18 @@ export default class MatlabDebugAdaptor {
730764 }
731765
732766 try {
733- await this . _waitForPendingVariablesRequest ( ) ;
767+ await this . _waitForPendingStackChanges ( ) ;
734768 } catch ( e ) {
735769 return null ;
736770 }
737771
738- const dbAmount = this . _numberOfStackFrames - frameId ;
772+ try {
773+ await this . _waitForStack ( ) ;
774+ } catch ( e ) {
775+ return null ;
776+ }
777+
778+ const dbAmount = ( this . _numberOfStackFrames - this . _currentMATLABFrame + 1 ) - frameId ;
739779 if ( dbAmount !== 0 ) {
740780 try {
741781 if ( dbAmount > 0 ) {
@@ -744,14 +784,20 @@ export default class MatlabDebugAdaptor {
744784 await this . _mvm . feval < undefined > ( 'dbdown' , 0 , [ - dbAmount ] ) ;
745785 }
746786 } catch ( e ) {
747- this . _clearPendingVariablesRequest ( ) ;
787+ this . _clearPendingStackChanges ( ) ;
748788 throw e ;
749789 }
750790 }
751791
752792 return {
753793 revert : async ( ) => {
754- const dbAmount = this . _numberOfStackFrames - frameId ;
794+ try {
795+ await this . _waitForStack ( ) ;
796+ } catch ( e ) {
797+ return
798+ }
799+
800+ const dbAmount = ( this . _numberOfStackFrames - this . _currentMATLABFrame + 1 ) - frameId ;
755801 if ( dbAmount !== 0 ) {
756802 try {
757803 if ( dbAmount > 0 ) {
@@ -760,16 +806,88 @@ export default class MatlabDebugAdaptor {
760806 await this . _mvm . feval < undefined > ( 'dbup' , 0 , [ - dbAmount ] ) ;
761807 }
762808 } catch ( e ) {
763- this . _clearPendingVariablesRequest ( ) ;
809+ this . _clearPendingStackChanges ( ) ;
764810 return ;
765811 }
766812 }
767813
768- this . _clearPendingVariablesRequest ( ) ;
814+ this . _clearPendingStackChanges ( ) ;
769815 }
770816 } ;
771817 }
772818
819+ private async _requestStackChange ( frameId : number ) : Promise < void > {
820+ if ( frameId === undefined ) {
821+ return ;
822+ }
823+
824+ try {
825+ await this . _waitForPendingStackChanges ( ) ;
826+ } catch ( e ) {
827+ return ;
828+ }
829+
830+ try {
831+ await this . _waitForStack ( ) ;
832+ } catch ( e ) {
833+ return ;
834+ }
835+
836+ const dbAmount = ( this . _numberOfStackFrames - this . _currentMATLABFrame + 1 ) - frameId ;
837+ if ( dbAmount !== 0 ) {
838+ try {
839+ if ( dbAmount > 0 ) {
840+ await this . _mvm . feval < undefined > ( 'dbup' , 0 , [ dbAmount ] ) ;
841+ } else {
842+ await this . _mvm . feval < undefined > ( 'dbdown' , 0 , [ - dbAmount ] ) ;
843+ }
844+ } catch ( e ) {
845+ }
846+ }
847+
848+ this . _clearPendingStackChanges ( ) ;
849+ }
850+
851+ private async _waitForStack ( ) : Promise < void > {
852+ if ( this . _pendingStackPromise != null ) {
853+ await this . _pendingStackPromise ;
854+ }
855+ }
856+
857+ private _requestStackUpdate ( ) : Promise < void > {
858+ if ( this . _pendingStackPromise != null ) {
859+ this . _followUpStackRequested = true ;
860+ return this . _pendingStackPromise ;
861+ }
862+
863+ this . _pendingStackPromise = createResolvablePromise ( ) ;
864+
865+ const requestStackHelper = ( ) : void => {
866+ this . _mvm . feval ( 'dbstack' , 2 , [ ] ) . then ( ( maybeResult : MatlabData ) => {
867+ if ( isError ( maybeResult ) ) {
868+ console . error ( maybeResult . error ) ;
869+ return ;
870+ }
871+ const result = maybeResult . result ;
872+ this . _currentMATLABFrame = result [ 1 ] ;
873+
874+ if ( this . _followUpStackRequested ) {
875+ this . _followUpStackRequested = false ;
876+ requestStackHelper ( ) ;
877+ } else {
878+ this . _pendingStackPromise ?. resolve ( ) ;
879+ this . _pendingStackPromise = undefined ;
880+ }
881+ } , ( err : MatlabData ) => {
882+ console . error ( err ) ;
883+ } ) ;
884+ }
885+
886+ requestStackHelper ( ) ;
887+
888+ return this . _pendingStackPromise ;
889+ }
890+
773891 private async _getCanonicalPath ( path : string ) : Promise < string > {
774892 let cachePromise : ResolvablePromise < string > | undefined = this . _canonicalizedPathCache . get ( path ) ;
775893
0 commit comments