@@ -60,19 +60,23 @@ const isError = function <T> (value: T | MVMError): boolean {
60
60
61
61
export default class MatlabDebugAdaptor {
62
62
static _nextId = 1 ;
63
- private _debugServices : DebugServices ;
64
- private _mvm : IMVM ;
63
+ private readonly _debugServices : DebugServices ;
64
+ private readonly _mvm : IMVM ;
65
65
66
66
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 ;
67
71
68
72
private _pendingSetBreakpointPromise ?: ResolvablePromise < void > ;
69
- private _pendingVariablesPromise ?: ResolvablePromise < void > ;
73
+ private _pendingTemporaryStackChangePromise ?: ResolvablePromise < void > ;
70
74
71
75
private _breakpointChangeListeners : Array < ( type : BreakpointChangeType , bp : BreakpointInfo ) => void > = [ ] ;
72
76
73
77
private _matlabBreakpoints : BreakpointInfo [ ] = [ ] ;
74
78
75
- private _canonicalizedPathCache : Map < string , ResolvablePromise < string > > = new Map ( ) ;
79
+ private readonly _canonicalizedPathCache : Map < string , ResolvablePromise < string > > = new Map ( ) ;
76
80
77
81
private _isCurrentlyStopped : boolean = false ;
78
82
protected _isCurrentlyDebugging : boolean = false ;
@@ -84,7 +88,7 @@ export default class MatlabDebugAdaptor {
84
88
this . _debugServices = debugServices ;
85
89
86
90
this . _pendingSetBreakpointPromise = undefined ;
87
- this . _pendingVariablesPromise = undefined ;
91
+ this . _pendingTemporaryStackChangePromise = undefined ;
88
92
89
93
this . _mvm . on ( IMVM . Events . stateChange , ( state : MatlabState ) => {
90
94
if ( state === MatlabState . DISCONNECTED ) {
@@ -203,11 +207,15 @@ export default class MatlabDebugAdaptor {
203
207
this . _pendingSetBreakpointPromise = createResolvablePromise ( ) ;
204
208
}
205
209
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 ( ) ;
209
218
}
210
- this . _pendingVariablesPromise = createResolvablePromise ( ) ;
211
219
}
212
220
213
221
private _clearPendingBreakpointsRequest ( ) : void {
@@ -216,9 +224,9 @@ export default class MatlabDebugAdaptor {
216
224
oldPromise ?. resolve ( ) ;
217
225
}
218
226
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 ;
222
230
oldPromise ?. resolve ( ) ;
223
231
}
224
232
@@ -280,8 +288,32 @@ export default class MatlabDebugAdaptor {
280
288
this . _handleDebuggingStateChange ( ) ;
281
289
}
282
290
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
+
283
309
this . sendEvent ( new debug . StoppedEvent ( 'breakpoint' , 0 ) ) ;
284
310
} ) ;
311
+
312
+ this . _debugServices . on ( DebugServices . Events . DBWorkspaceChanged , ( ) => {
313
+ if ( ! this . _ignoreWorkspaceUpdates ) {
314
+ void this . _requestStackUpdate ( ) ;
315
+ }
316
+ } ) ;
285
317
}
286
318
287
319
protected _handleDebuggingStateChange ( ) : void {
@@ -527,7 +559,6 @@ export default class MatlabDebugAdaptor {
527
559
const size = stack . mwsize [ 0 ] ;
528
560
const newStack = [ ] ;
529
561
for ( let i = 0 ; i < size ; i ++ ) {
530
-
531
562
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 ) )
532
563
}
533
564
return newStack ;
@@ -630,7 +661,6 @@ export default class MatlabDebugAdaptor {
630
661
}
631
662
632
663
async evaluateRequest ( response : DebugProtocol . EvaluateResponse , args : DebugProtocol . EvaluateArguments , request ?: DebugProtocol . Request ) : Promise < void > {
633
-
634
664
let stackChanger ;
635
665
try {
636
666
stackChanger = await this . _moveToFrame ( args . frameId ) ;
@@ -653,7 +683,7 @@ export default class MatlabDebugAdaptor {
653
683
maybeResult = await this . _mvm . feval < MatlabData > ( 'evalc' , 1 , [ "try, datatipinfo('" + args . expression + "'), catch, disp('Error evaluating expression'); end" ] ) ;
654
684
}
655
685
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 ) ] ) ;
657
687
658
688
if ( stackChanger !== null ) {
659
689
try {
@@ -679,8 +709,8 @@ export default class MatlabDebugAdaptor {
679
709
this . sendResponse ( response ) ;
680
710
return ;
681
711
}
682
- response . body = {
683
- result : result ,
712
+ response . body = {
713
+ result,
684
714
variablesReference : 0
685
715
} ;
686
716
response . body . type = 'string' ;
@@ -700,20 +730,24 @@ export default class MatlabDebugAdaptor {
700
730
protected customRequest ( command : string , response : DebugProtocol . Response , args : any , request ?: DebugProtocol . Request ) : void {
701
731
if ( command === 'cacheFilePath' ) {
702
732
this . _getCanonicalPath ( args . fileName ) . then ( ( ) => { } , ( ) => { } ) ;
733
+ } else if ( command === 'StackChange' ) {
734
+ void this . _requestStackChange ( args . frame ) ;
703
735
}
704
736
this . sendResponse ( response ) ;
705
737
}
706
738
707
739
private _cleanup ( ) : void {
708
740
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
+
717
751
this . _breakpointChangeListeners = [ ] ;
718
752
}
719
753
@@ -730,12 +764,18 @@ export default class MatlabDebugAdaptor {
730
764
}
731
765
732
766
try {
733
- await this . _waitForPendingVariablesRequest ( ) ;
767
+ await this . _waitForPendingStackChanges ( ) ;
734
768
} catch ( e ) {
735
769
return null ;
736
770
}
737
771
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 ;
739
779
if ( dbAmount !== 0 ) {
740
780
try {
741
781
if ( dbAmount > 0 ) {
@@ -744,14 +784,20 @@ export default class MatlabDebugAdaptor {
744
784
await this . _mvm . feval < undefined > ( 'dbdown' , 0 , [ - dbAmount ] ) ;
745
785
}
746
786
} catch ( e ) {
747
- this . _clearPendingVariablesRequest ( ) ;
787
+ this . _clearPendingStackChanges ( ) ;
748
788
throw e ;
749
789
}
750
790
}
751
791
752
792
return {
753
793
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 ;
755
801
if ( dbAmount !== 0 ) {
756
802
try {
757
803
if ( dbAmount > 0 ) {
@@ -760,16 +806,88 @@ export default class MatlabDebugAdaptor {
760
806
await this . _mvm . feval < undefined > ( 'dbup' , 0 , [ - dbAmount ] ) ;
761
807
}
762
808
} catch ( e ) {
763
- this . _clearPendingVariablesRequest ( ) ;
809
+ this . _clearPendingStackChanges ( ) ;
764
810
return ;
765
811
}
766
812
}
767
813
768
- this . _clearPendingVariablesRequest ( ) ;
814
+ this . _clearPendingStackChanges ( ) ;
769
815
}
770
816
} ;
771
817
}
772
818
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
+
773
891
private async _getCanonicalPath ( path : string ) : Promise < string > {
774
892
let cachePromise : ResolvablePromise < string > | undefined = this . _canonicalizedPathCache . get ( path ) ;
775
893
0 commit comments