@@ -80,6 +80,27 @@ export class ArrayExpander implements Expandable {
80
80
}
81
81
}
82
82
83
+ /**
84
+ * This class represents an internal line/column breakpoint.
85
+ */
86
+ export class InternalBreakpoint {
87
+
88
+ /** The requested breakpoint line location in the JavaScript file. */
89
+ line : number ;
90
+ /** The requested breakpoint column location in the JavaScript file. */
91
+ column : number ;
92
+
93
+ /** do not try to set this breakpoint (because source locations could not successfully be mapped to destination locations) */
94
+ ignore : boolean ;
95
+
96
+ /** true if this breakpoint could be set and node.js returned an 'actual location' for it. */
97
+ verified : boolean ;
98
+ /** The actual line location of this breakpoint in client coordinates. Contains the original client line if breakpoint could not be verified. */
99
+ actualLine : number ;
100
+ /** the actual column location of this breakpoint in client coordinates. Contains the original client column if breakpoint could not be verified. */
101
+ actualColumn : number ;
102
+ }
103
+
83
104
/**
84
105
* This interface should always match the schema found in the node-debug extension manifest.
85
106
*/
@@ -760,11 +781,16 @@ export class NodeDebugSession extends DebugSession {
760
781
const clientLines = args . lines ;
761
782
762
783
// convert line numbers from client
763
- const lines = new Array < number > ( clientLines . length ) ;
764
- const columns = new Array < number > ( clientLines . length ) ;
784
+ const lbs = new Array < InternalBreakpoint > ( clientLines . length ) ;
765
785
for ( let i = 0 ; i < clientLines . length ; i ++ ) {
766
- lines [ i ] = this . convertClientLineToDebugger ( clientLines [ i ] ) ;
767
- columns [ i ] = 0 ;
786
+ lbs [ i ] = {
787
+ actualLine : clientLines [ i ] ,
788
+ actualColumn : this . convertDebuggerColumnToClient ( 1 ) , // hardcoded for now
789
+ line : this . convertClientLineToDebugger ( clientLines [ i ] ) ,
790
+ column : 0 , // hardcoded for now
791
+ verified : false ,
792
+ ignore : false
793
+ } ;
768
794
}
769
795
770
796
let scriptId = - 1 ;
@@ -783,13 +809,16 @@ export class NodeDebugSession extends DebugSession {
783
809
if ( p ) {
784
810
sourcemap = true ;
785
811
// source map line numbers
786
- for ( let i = 0 ; i < lines . length ; i ++ ) {
812
+ for ( let i = 0 ; i < lbs . length ; i ++ ) {
787
813
let pp = path ;
788
- const mr = this . _sourceMaps . MapFromSource ( pp , lines [ i ] , columns [ i ] ) ;
814
+ const mr = this . _sourceMaps . MapFromSource ( pp , lbs [ i ] . line , lbs [ i ] . column ) ;
789
815
if ( mr ) {
790
816
pp = mr . path ;
791
- lines [ i ] = mr . line ;
792
- columns [ i ] = mr . column ;
817
+ lbs [ i ] . line = mr . line ;
818
+ lbs [ i ] . column = mr . column ;
819
+ } else {
820
+ // we couldn't map this breakpoint -> do not try to set it
821
+ lbs [ i ] . ignore = true ;
793
822
}
794
823
if ( pp !== p ) {
795
824
// console.error(`setBreakPointsRequest: sourceMap limitation ${pp}`);
@@ -798,26 +827,20 @@ export class NodeDebugSession extends DebugSession {
798
827
path = p ;
799
828
}
800
829
else if ( ! NodeDebugSession . isJavaScript ( path ) ) {
801
- // return these breakpoints as unverified
802
- const bpts = new Array < Breakpoint > ( ) ;
803
- for ( let l of clientLines ) {
804
- bpts . push ( new Breakpoint ( false , l ) ) ;
830
+ // ignore all breakpoints for this source
831
+ for ( let lb of lbs ) {
832
+ lb . ignore = true ;
805
833
}
806
- response . body = {
807
- breakpoints : bpts
808
- } ;
809
- this . sendResponse ( response ) ;
810
- return ;
811
834
}
812
- this . _clearAllBreakpoints ( response , path , - 1 , lines , columns , sourcemap , clientLines ) ;
835
+ this . _clearAllBreakpoints ( response , path , - 1 , lbs , sourcemap ) ;
813
836
return ;
814
837
}
815
838
816
839
if ( source . name ) {
817
840
this . findModule ( source . name , ( id : number ) => {
818
841
if ( id >= 0 ) {
819
842
scriptId = id ;
820
- this . _clearAllBreakpoints ( response , null , scriptId , lines , columns , sourcemap , clientLines ) ;
843
+ this . _clearAllBreakpoints ( response , null , scriptId , lbs , sourcemap ) ;
821
844
return ;
822
845
} else {
823
846
this . sendErrorResponse ( response , 2019 , "internal module {_module} not found" , { _module : source . name } ) ;
@@ -829,7 +852,7 @@ export class NodeDebugSession extends DebugSession {
829
852
830
853
if ( source . sourceReference > 0 ) {
831
854
scriptId = source . sourceReference - 1000 ;
832
- this . _clearAllBreakpoints ( response , null , scriptId , lines , columns , sourcemap , clientLines ) ;
855
+ this . _clearAllBreakpoints ( response , null , scriptId , lbs , sourcemap ) ;
833
856
return ;
834
857
}
835
858
@@ -839,7 +862,7 @@ export class NodeDebugSession extends DebugSession {
839
862
/*
840
863
* Phase 2 of setBreakpointsRequest: clear all breakpoints of a given file
841
864
*/
842
- private _clearAllBreakpoints ( response : DebugProtocol . SetBreakpointsResponse , path : string , scriptId : number , lines : number [ ] , columns : number [ ] , sourcemap : boolean , clientLines : number [ ] ) : void {
865
+ private _clearAllBreakpoints ( response : DebugProtocol . SetBreakpointsResponse , path : string , scriptId : number , lbs : InternalBreakpoint [ ] , sourcemap : boolean ) : void {
843
866
844
867
// clear all existing breakpoints for the given path or script ID
845
868
this . _node . command ( 'listbreakpoints' , null , ( nodeResponse : NodeV8Response ) => {
@@ -867,7 +890,7 @@ export class NodeDebugSession extends DebugSession {
867
890
}
868
891
869
892
this . _clearBreakpoints ( toClear , 0 , ( ) => {
870
- this . _finishSetBreakpoints ( response , path , scriptId , lines , columns , sourcemap , clientLines ) ;
893
+ this . _finishSetBreakpoints ( response , path , scriptId , lbs , sourcemap ) ;
871
894
} ) ;
872
895
873
896
} else {
@@ -906,11 +929,15 @@ export class NodeDebugSession extends DebugSession {
906
929
/*
907
930
* Finish the setBreakpointsRequest: set the breakpooints and send the verification response back to client
908
931
*/
909
- private _finishSetBreakpoints ( response : DebugProtocol . SetBreakpointsResponse , path : string , scriptId : number , lines : number [ ] , columns : number [ ] , sourcemap : boolean , clientLines : number [ ] ) : void {
932
+ private _finishSetBreakpoints ( response : DebugProtocol . SetBreakpointsResponse , path : string , scriptId : number , lbs : InternalBreakpoint [ ] , sourcemap : boolean ) : void {
910
933
911
- const breakpoints = new Array < Breakpoint > ( ) ;
934
+ this . _setBreakpoints ( 0 , path , scriptId , lbs , sourcemap , ( ) => {
935
+
936
+ const breakpoints = new Array < Breakpoint > ( ) ;
937
+ for ( let lb of lbs ) {
938
+ breakpoints . push ( new Breakpoint ( lb . verified , lb . actualLine /* ; lb.clientColumn */ ) ) ;
939
+ }
912
940
913
- this . _setBreakpoints ( breakpoints , 0 , path , scriptId , lines , columns , sourcemap , clientLines , ( ) => {
914
941
response . body = {
915
942
breakpoints : breakpoints
916
943
} ;
@@ -921,45 +948,47 @@ export class NodeDebugSession extends DebugSession {
921
948
/**
922
949
* Recursive function for setting node breakpoints.
923
950
*/
924
- private _setBreakpoints ( breakpoints : Array < Breakpoint > , ix : number , path : string , scriptId : number , lines : number [ ] , columns : number [ ] , sourcemap : boolean , clientLines : number [ ] , done : ( ) => void ) : void {
951
+ private _setBreakpoints ( ix : number , path : string , scriptId : number , lbs : InternalBreakpoint [ ] , sourcemap : boolean , done : ( ) => void ) : void {
925
952
926
- if ( lines . length == 0 ) { // nothing to do
953
+ if ( lbs . length == 0 ) { // nothing to do
927
954
done ( ) ;
928
955
return ;
929
956
}
930
957
931
- this . _robustSetBreakPoint ( scriptId , path , lines [ ix ] , columns [ ix ] , ( verified : boolean , actualLine , actualColumn ) => {
958
+ this . _robustSetBreakPoint ( scriptId , path , lbs [ ix ] , ( success : boolean , actualLine : number , actualColumn : number ) => {
932
959
933
- // prepare sending breakpoint locations back to client
934
- let sourceLine = clientLines [ ix ] ; // we start with the original lines from the client
960
+ if ( success ) {
961
+ // breakpoint successfully set and we've got an actual location
935
962
936
- if ( verified ) {
937
963
if ( sourcemap ) {
938
- if ( ! this . _lazy ) { // only if not in lazy mode we try to map actual Positions back
964
+ // this source uses a sourcemap so we have to map locations back
965
+
966
+ if ( ! this . _lazy ) { // only if not in lazy mode we try to map actual positions back
939
967
// map adjusted js breakpoints back to source language
940
968
if ( path && this . _sourceMaps ) {
941
- const p = path ;
942
- const mr = this . _sourceMaps . MapToSource ( p , actualLine , actualColumn ) ;
969
+ const mr = this . _sourceMaps . MapToSource ( path , actualLine , actualColumn ) ;
943
970
if ( mr ) {
944
971
actualLine = mr . line ;
945
972
actualColumn = mr . column ;
946
973
}
947
974
}
948
- sourceLine = this . convertDebuggerLineToClient ( actualLine ) ;
975
+ lbs [ ix ] . actualLine = this . convertDebuggerLineToClient ( actualLine ) ;
949
976
}
950
977
} else {
951
- sourceLine = this . convertDebuggerLineToClient ( actualLine ) ;
978
+ lbs [ ix ] . actualLine = this . convertDebuggerLineToClient ( actualLine ) ;
952
979
}
980
+
953
981
}
954
- breakpoints [ ix ] = new Breakpoint ( verified , sourceLine ) ;
982
+ lbs [ ix ] . verified = success ;
955
983
956
984
// nasty corner case: since we ignore the break-on-entry event we have to make sure that we
957
985
// stop in the entry point line if the user has an explicit breakpoint there.
958
986
// For this we check here whether a breakpoint is at the same location as the "break-on-entry" location.
959
987
// If yes, then we plan for hitting the breakpoint instead of "continue" over it!
988
+
960
989
if ( ! this . _stopOnEntry ) { // only relevant if we do not stop on entry
961
- const li = verified ? actualLine : lines [ ix ] ;
962
- const co = columns [ ix ] ; // verified ? actualColumn : columns[ix];
990
+ const li = success ? actualLine : lbs [ ix ] . line ;
991
+ const co = lbs [ ix ] . column ; // success ? actualColumn : columns[ix];
963
992
if ( this . _entryPath === path && this . _entryLine === li && this . _entryColumn === co ) {
964
993
// if yes, we do not have to "continue" but we have to generate a stopped event instead
965
994
this . _needContinue = false ;
@@ -968,10 +997,10 @@ export class NodeDebugSession extends DebugSession {
968
997
}
969
998
}
970
999
971
- if ( ix + 1 < lines . length ) {
1000
+ if ( ix + 1 < lbs . length ) {
972
1001
setImmediate ( ( ) => {
973
1002
// recurse
974
- this . _setBreakpoints ( breakpoints , ix + 1 , path , scriptId , lines , columns , sourcemap , clientLines , done ) ;
1003
+ this . _setBreakpoints ( ix + 1 , path , scriptId , lbs , sourcemap , done ) ;
975
1004
} ) ;
976
1005
} else {
977
1006
done ( ) ;
@@ -980,21 +1009,30 @@ export class NodeDebugSession extends DebugSession {
980
1009
}
981
1010
982
1011
/*
983
- * register a single breakpoint with node and retry if it fails due to drive letter casing (on Windows)
1012
+ * register a single breakpoint with node and retry if it fails due to drive letter casing (on Windows).
1013
+ * On success the actual line and column is returned.
984
1014
*/
985
- private _robustSetBreakPoint ( scriptId : number , path : string , l : number , c : number , done : ( success : boolean , actualLine ?: number , actualColumn ?: number ) => void ) : void {
986
- this . _setBreakpoint ( scriptId , path , l , c , ( verified : boolean , actualLine , actualColumn ) => {
987
- if ( verified ) {
1015
+ private _robustSetBreakPoint ( scriptId : number , path : string , lb : InternalBreakpoint , done : ( success : boolean , actualLine ?: number , actualColumn ?: number ) => void ) : void {
1016
+
1017
+ if ( lb . ignore ) {
1018
+ // ignore this breakpoint because it couldn't be source mapped successfully
1019
+ done ( false ) ;
1020
+ return ;
1021
+ }
1022
+
1023
+ this . _setBreakpoint ( scriptId , path , lb , ( success : boolean , actualLine : number , actualColumn : number ) => {
1024
+
1025
+ if ( success ) {
988
1026
done ( true , actualLine , actualColumn ) ;
989
1027
return ;
990
1028
}
991
1029
992
- // take care of a mismatch of drive letter caseing
1030
+ // failure -> guess: mismatch of drive letter caseing
993
1031
const root = PathUtils . getPathRoot ( path ) ;
994
1032
if ( root && root . length === 3 ) { // root contains a drive letter
995
1033
path = path . substring ( 0 , 1 ) . toUpperCase ( ) + path . substring ( 1 ) ;
996
- this . _setBreakpoint ( scriptId , path , l , c , ( verified : boolean , actualLine , actualColumn ) => {
997
- if ( verified ) {
1034
+ this . _setBreakpoint ( scriptId , path , lb , ( success : boolean , actualLine , actualColumn ) => {
1035
+ if ( success ) {
998
1036
done ( true , actualLine , actualColumn ) ;
999
1037
} else {
1000
1038
done ( false ) ;
@@ -1009,20 +1047,20 @@ export class NodeDebugSession extends DebugSession {
1009
1047
/*
1010
1048
* register a single breakpoint with node.
1011
1049
*/
1012
- private _setBreakpoint ( scriptId : number , path : string , l : number , c : number , cb : ( success : boolean , actualLine ?: number , actualColumn ?: number ) => void ) : void {
1050
+ private _setBreakpoint ( scriptId : number , path : string , lb : InternalBreakpoint , cb : ( success : boolean , actualLine ?: number , actualColumn ?: number ) => void ) : void {
1013
1051
1014
- if ( l === 0 ) {
1015
- c += NodeDebugSession . FIRST_LINE_OFFSET ;
1052
+ if ( lb . line === 0 ) {
1053
+ lb . column += NodeDebugSession . FIRST_LINE_OFFSET ;
1016
1054
}
1017
1055
1018
- let actualLine = l ;
1019
- let actualColumn = c ;
1056
+ let actualLine = lb . line ;
1057
+ let actualColumn = lb . column ;
1020
1058
1021
1059
let a : any ;
1022
1060
if ( scriptId > 0 ) {
1023
- a = { type : 'scriptId' , target : scriptId , line : l , column : c } ;
1061
+ a = { type : 'scriptId' , target : scriptId , line : lb . line , column : lb . column } ;
1024
1062
} else {
1025
- a = { type : 'script' , target : path , line : l , column : c } ;
1063
+ a = { type : 'script' , target : path , line : lb . line , column : lb . column } ;
1026
1064
}
1027
1065
1028
1066
this . _node . command ( 'setbreakpoint' , a , ( resp : NodeV8Response ) => {
@@ -1038,7 +1076,7 @@ export class NodeDebugSession extends DebugSession {
1038
1076
actualColumn = 0 ;
1039
1077
}
1040
1078
1041
- if ( actualLine !== l ) {
1079
+ if ( actualLine !== lb . line ) {
1042
1080
// console.error(`setbreakpoint: ${l} !== ${actualLine}`);
1043
1081
}
1044
1082
cb ( true , actualLine , actualColumn ) ;
0 commit comments