@@ -72,7 +72,7 @@ export function getExpandedBodySize(model: IDebugModel, sessionId: string | unde
72
72
type BreakpointItem = IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IExceptionBreakpoint | IInstructionBreakpoint ;
73
73
74
74
interface InputBoxData {
75
- breakpoint : IFunctionBreakpoint | IExceptionBreakpoint ;
75
+ breakpoint : IFunctionBreakpoint | IExceptionBreakpoint | IDataBreakpoint ;
76
76
type : 'condition' | 'hitCount' | 'name' ;
77
77
}
78
78
@@ -136,8 +136,9 @@ export class BreakpointsView extends ViewPane {
136
136
new ExceptionBreakpointsRenderer ( this . menu , this . breakpointSupportsCondition , this . breakpointItemType , this . debugService ) ,
137
137
new ExceptionBreakpointInputRenderer ( this , this . debugService , this . contextViewService ) ,
138
138
this . instantiationService . createInstance ( FunctionBreakpointsRenderer , this . menu , this . breakpointSupportsCondition , this . breakpointItemType ) ,
139
- this . instantiationService . createInstance ( DataBreakpointsRenderer ) ,
140
139
new FunctionBreakpointInputRenderer ( this , this . debugService , this . contextViewService , this . labelService ) ,
140
+ this . instantiationService . createInstance ( DataBreakpointsRenderer , this . menu , this . breakpointSupportsCondition , this . breakpointItemType ) ,
141
+ new DataBreakpointInputRenderer ( this , this . debugService , this . contextViewService , this . labelService ) ,
141
142
this . instantiationService . createInstance ( InstructionBreakpointsRenderer ) ,
142
143
] , {
143
144
identityProvider : { getId : ( element : IEnablement ) => element . getId ( ) } ,
@@ -403,6 +404,11 @@ class BreakpointsDelegate implements IListVirtualDelegate<BreakpointItem> {
403
404
return ExceptionBreakpointsRenderer . ID ;
404
405
}
405
406
if ( element instanceof DataBreakpoint ) {
407
+ const inputBoxBreakpoint = this . view . inputBoxData ?. breakpoint ;
408
+ if ( inputBoxBreakpoint && inputBoxBreakpoint . getId ( ) === element . getId ( ) ) {
409
+ return DataBreakpointInputRenderer . ID ;
410
+ }
411
+
406
412
return DataBreakpointsRenderer . ID ;
407
413
}
408
414
if ( element instanceof InstructionBreakpoint ) {
@@ -441,6 +447,7 @@ interface IFunctionBreakpointTemplateData extends IBaseBreakpointWithIconTemplat
441
447
442
448
interface IDataBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
443
449
accessType : HTMLElement ;
450
+ condition : HTMLElement ;
444
451
}
445
452
446
453
interface IInstructionBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
@@ -457,6 +464,16 @@ interface IFunctionBreakpointInputTemplateData {
457
464
updating ?: boolean ;
458
465
}
459
466
467
+ interface IDataBreakpointInputTemplateData {
468
+ inputBox : InputBox ;
469
+ checkbox : HTMLInputElement ;
470
+ icon : HTMLElement ;
471
+ breakpoint : IDataBreakpoint ;
472
+ toDispose : IDisposable [ ] ;
473
+ type : 'hitCount' | 'condition' | 'name' ;
474
+ updating ?: boolean ;
475
+ }
476
+
460
477
interface IExceptionBreakpointInputTemplateData {
461
478
inputBox : InputBox ;
462
479
checkbox : HTMLInputElement ;
@@ -657,7 +674,7 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
657
674
data . checkbox . checked = functionBreakpoint . enabled ;
658
675
data . breakpoint . title = message ? message : '' ;
659
676
if ( functionBreakpoint . condition && functionBreakpoint . hitCondition ) {
660
- data . condition . textContent = localize ( 'expressionAndHitCount' , "Expression : {0} | Hit Count: {1}" , functionBreakpoint . condition , functionBreakpoint . hitCondition ) ;
677
+ data . condition . textContent = localize ( 'expressionAndHitCount' , "Condition : {0} | Hit Count: {1}" , functionBreakpoint . condition , functionBreakpoint . hitCondition ) ;
661
678
} else {
662
679
data . condition . textContent = functionBreakpoint . condition || functionBreakpoint . hitCondition || '' ;
663
680
}
@@ -686,6 +703,9 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
686
703
class DataBreakpointsRenderer implements IListRenderer < DataBreakpoint , IDataBreakpointTemplateData > {
687
704
688
705
constructor (
706
+ private menu : IMenu ,
707
+ private breakpointSupportsCondition : IContextKey < boolean > ,
708
+ private breakpointItemType : IContextKey < string | undefined > ,
689
709
@IDebugService private readonly debugService : IDebugService ,
690
710
@ILabelService private readonly labelService : ILabelService
691
711
) {
@@ -714,6 +734,10 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
714
734
715
735
data . name = dom . append ( data . breakpoint , $ ( 'span.name' ) ) ;
716
736
data . accessType = dom . append ( data . breakpoint , $ ( 'span.access-type' ) ) ;
737
+ data . condition = dom . append ( data . breakpoint , $ ( 'span.condition' ) ) ;
738
+
739
+ data . actionBar = new ActionBar ( data . breakpoint ) ;
740
+ data . toDispose . push ( data . actionBar ) ;
717
741
718
742
return data ;
719
743
}
@@ -727,7 +751,7 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
727
751
data . checkbox . checked = dataBreakpoint . enabled ;
728
752
data . breakpoint . title = message ? message : '' ;
729
753
730
- // Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
754
+ // Mark data breakpoints as disabled if deactivated or if debug type does not support them
731
755
const session = this . debugService . getViewModel ( ) . focusedSession ;
732
756
data . breakpoint . classList . toggle ( 'disabled' , ( session && ! session . capabilities . supportsDataBreakpoints ) || ! this . debugService . getModel ( ) . areBreakpointsActivated ( ) ) ;
733
757
if ( session && ! session . capabilities . supportsDataBreakpoints ) {
@@ -739,6 +763,19 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
739
763
} else {
740
764
data . accessType . textContent = '' ;
741
765
}
766
+ if ( dataBreakpoint . condition && dataBreakpoint . hitCondition ) {
767
+ data . condition . textContent = localize ( 'expressionAndHitCount' , "Condition: {0} | Hit Count: {1}" , dataBreakpoint . condition , dataBreakpoint . hitCondition ) ;
768
+ } else {
769
+ data . condition . textContent = dataBreakpoint . condition || dataBreakpoint . hitCondition || '' ;
770
+ }
771
+
772
+ const primary : IAction [ ] = [ ] ;
773
+ this . breakpointSupportsCondition . set ( ! session || ! ! session . capabilities . supportsConditionalBreakpoints ) ;
774
+ this . breakpointItemType . set ( 'dataBreakpoint' ) ;
775
+ createAndFillInActionBarActions ( this . menu , { arg : dataBreakpoint , shouldForwardArgs : true } , { primary, secondary : [ ] } , 'inline' ) ;
776
+ data . actionBar . clear ( ) ;
777
+ data . actionBar . push ( primary , { icon : true , label : false } ) ;
778
+ breakpointIdToActionBarDomeNode . set ( dataBreakpoint . getId ( ) , data . actionBar . domNode ) ;
742
779
}
743
780
744
781
disposeTemplate ( templateData : IBaseBreakpointWithIconTemplateData ) : void {
@@ -922,6 +959,113 @@ class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoi
922
959
}
923
960
}
924
961
962
+ class DataBreakpointInputRenderer implements IListRenderer < IDataBreakpoint , IDataBreakpointInputTemplateData > {
963
+
964
+ constructor (
965
+ private view : BreakpointsView ,
966
+ private debugService : IDebugService ,
967
+ private contextViewService : IContextViewService ,
968
+ private labelService : ILabelService
969
+ ) { }
970
+
971
+ static readonly ID = 'databreakpointinput' ;
972
+
973
+ get templateId ( ) {
974
+ return DataBreakpointInputRenderer . ID ;
975
+ }
976
+
977
+ renderTemplate ( container : HTMLElement ) : IDataBreakpointInputTemplateData {
978
+ const template : IDataBreakpointInputTemplateData = Object . create ( null ) ;
979
+ const toDispose : IDisposable [ ] = [ ] ;
980
+
981
+ const breakpoint = dom . append ( container , $ ( '.breakpoint' ) ) ;
982
+ template . icon = $ ( '.icon' ) ;
983
+ template . checkbox = createCheckbox ( toDispose ) ;
984
+
985
+ dom . append ( breakpoint , template . icon ) ;
986
+ dom . append ( breakpoint , template . checkbox ) ;
987
+ this . view . breakpointInputFocused . set ( true ) ;
988
+ const inputBoxContainer = dom . append ( breakpoint , $ ( '.inputBoxContainer' ) ) ;
989
+
990
+
991
+ const inputBox = new InputBox ( inputBoxContainer , this . contextViewService , { inputBoxStyles : defaultInputBoxStyles } ) ;
992
+
993
+ const wrapUp = ( success : boolean ) => {
994
+ template . updating = true ;
995
+ try {
996
+ this . view . breakpointInputFocused . set ( false ) ;
997
+ const id = template . breakpoint . getId ( ) ;
998
+
999
+ if ( success ) {
1000
+ if ( template . type === 'condition' ) {
1001
+ this . debugService . updateDataBreakpoint ( id , { condition : inputBox . value } ) ;
1002
+ }
1003
+ if ( template . type === 'hitCount' ) {
1004
+ this . debugService . updateDataBreakpoint ( id , { hitCondition : inputBox . value } ) ;
1005
+ }
1006
+ } else {
1007
+ this . view . renderInputBox ( undefined ) ;
1008
+ }
1009
+ } finally {
1010
+ template . updating = false ;
1011
+ }
1012
+ } ;
1013
+
1014
+ toDispose . push ( dom . addStandardDisposableListener ( inputBox . inputElement , 'keydown' , ( e : IKeyboardEvent ) => {
1015
+ const isEscape = e . equals ( KeyCode . Escape ) ;
1016
+ const isEnter = e . equals ( KeyCode . Enter ) ;
1017
+ if ( isEscape || isEnter ) {
1018
+ e . preventDefault ( ) ;
1019
+ e . stopPropagation ( ) ;
1020
+ wrapUp ( isEnter ) ;
1021
+ }
1022
+ } ) ) ;
1023
+ toDispose . push ( dom . addDisposableListener ( inputBox . inputElement , 'blur' , ( ) => {
1024
+ if ( ! template . updating ) {
1025
+ wrapUp ( ! ! inputBox . value ) ;
1026
+ }
1027
+ } ) ) ;
1028
+
1029
+ template . inputBox = inputBox ;
1030
+ template . toDispose = toDispose ;
1031
+ return template ;
1032
+ }
1033
+
1034
+ renderElement ( dataBreakpoint : DataBreakpoint , _index : number , data : IDataBreakpointInputTemplateData ) : void {
1035
+ data . breakpoint = dataBreakpoint ;
1036
+ data . type = this . view . inputBoxData ?. type || 'condition' ; // If there is no type set take the 'condition' as the default
1037
+ const { icon, message } = getBreakpointMessageAndIcon ( this . debugService . state , this . debugService . getModel ( ) . areBreakpointsActivated ( ) , dataBreakpoint , this . labelService ) ;
1038
+
1039
+ data . icon . className = ThemeIcon . asClassName ( icon ) ;
1040
+ data . icon . title = message ? message : '' ;
1041
+ data . checkbox . checked = dataBreakpoint . enabled ;
1042
+ data . checkbox . disabled = true ;
1043
+ data . inputBox . value = '' ;
1044
+ let placeholder = '' ;
1045
+ let ariaLabel = '' ;
1046
+ if ( data . type === 'condition' ) {
1047
+ data . inputBox . value = dataBreakpoint . condition || '' ;
1048
+ placeholder = localize ( 'dataBreakpointExpressionPlaceholder' , "Break when expression evaluates to true" ) ;
1049
+ ariaLabel = localize ( 'dataBreakPointExpresionAriaLabel' , "Type expression. Data breakpoint will break when expression evaluates to true" ) ;
1050
+ } else if ( data . type === 'hitCount' ) {
1051
+ data . inputBox . value = dataBreakpoint . hitCondition || '' ;
1052
+ placeholder = localize ( 'dataBreakpointHitCountPlaceholder' , "Break when hit count is met" ) ;
1053
+ ariaLabel = localize ( 'dataBreakPointHitCountAriaLabel' , "Type hit count. Data breakpoint will break when hit count is met." ) ;
1054
+ }
1055
+ data . inputBox . setAriaLabel ( ariaLabel ) ;
1056
+ data . inputBox . setPlaceHolder ( placeholder ) ;
1057
+
1058
+ setTimeout ( ( ) => {
1059
+ data . inputBox . focus ( ) ;
1060
+ data . inputBox . select ( ) ;
1061
+ } , 0 ) ;
1062
+ }
1063
+
1064
+ disposeTemplate ( templateData : IDataBreakpointInputTemplateData ) : void {
1065
+ dispose ( templateData . toDispose ) ;
1066
+ }
1067
+ }
1068
+
925
1069
class ExceptionBreakpointInputRenderer implements IListRenderer < IExceptionBreakpoint , IExceptionBreakpointInputTemplateData > {
926
1070
927
1071
constructor (
@@ -1109,7 +1253,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
1109
1253
const messages : string [ ] = [ ] ;
1110
1254
messages . push ( breakpoint . message || localize ( 'functionBreakpoint' , "Function Breakpoint" ) ) ;
1111
1255
if ( breakpoint . condition ) {
1112
- messages . push ( localize ( 'expression' , "Expression condition : {0}" , breakpoint . condition ) ) ;
1256
+ messages . push ( localize ( 'expression' , "Condition : {0}" , breakpoint . condition ) ) ;
1113
1257
}
1114
1258
if ( breakpoint . hitCondition ) {
1115
1259
messages . push ( localize ( 'hitCount' , "Hit Count: {0}" , breakpoint . hitCondition ) ) ;
@@ -1161,7 +1305,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
1161
1305
messages . push ( localize ( 'logMessage' , "Log Message: {0}" , breakpoint . logMessage ) ) ;
1162
1306
}
1163
1307
if ( breakpoint . condition ) {
1164
- messages . push ( localize ( 'expression' , "Expression condition : {0}" , breakpoint . condition ) ) ;
1308
+ messages . push ( localize ( 'expression' , "Condition : {0}" , breakpoint . condition ) ) ;
1165
1309
}
1166
1310
if ( breakpoint . hitCondition ) {
1167
1311
messages . push ( localize ( 'hitCount' , "Hit Count: {0}" , breakpoint . hitCondition ) ) ;
@@ -1410,7 +1554,7 @@ registerAction2(class extends ViewAction<BreakpointsView> {
1410
1554
} ) ;
1411
1555
}
1412
1556
1413
- async runInView ( accessor : ServicesAccessor , view : BreakpointsView , breakpoint : ExceptionBreakpoint | Breakpoint | FunctionBreakpoint ) : Promise < void > {
1557
+ async runInView ( accessor : ServicesAccessor , view : BreakpointsView , breakpoint : ExceptionBreakpoint | Breakpoint | FunctionBreakpoint | DataBreakpoint ) : Promise < void > {
1414
1558
const debugService = accessor . get ( IDebugService ) ;
1415
1559
const editorService = accessor . get ( IEditorService ) ;
1416
1560
if ( breakpoint instanceof Breakpoint ) {
@@ -1472,7 +1616,7 @@ registerAction2(class extends ViewAction<BreakpointsView> {
1472
1616
id : MenuId . DebugBreakpointsContext ,
1473
1617
group : 'navigation' ,
1474
1618
order : 20 ,
1475
- when : CONTEXT_BREAKPOINT_ITEM_TYPE . isEqualTo ( 'functionBreakpoint' )
1619
+ when : ContextKeyExpr . or ( CONTEXT_BREAKPOINT_ITEM_TYPE . isEqualTo ( 'functionBreakpoint' ) , CONTEXT_BREAKPOINT_ITEM_TYPE . isEqualTo ( 'dataBreakpoint' ) )
1476
1620
} ]
1477
1621
} ) ;
1478
1622
}
0 commit comments