in patched-vscode/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts [255:402]
private registerListeners(): void {
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
if (!this.debugService.getAdapterManager().hasEnabledDebuggers()) {
return;
}
const model = this.editor.getModel();
if (!e.target.position
|| !model
|| e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN
|| e.target.detail.isAfterLines
|| !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)
// don't return early if there's a breakpoint
&& !e.target.element?.className.includes('breakpoint')
) {
return;
}
const canSetBreakpoints = this.debugService.canSetBreakpointsIn(model);
const lineNumber = e.target.position.lineNumber;
const uri = model.uri;
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
// handled by editor gutter context menu
return;
} else {
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
if (breakpoints.length) {
const isShiftPressed = e.event.shiftKey;
const enabled = breakpoints.some(bp => bp.enabled);
if (isShiftPressed) {
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!enabled, bp));
} else if (!env.isLinux && breakpoints.some(bp => !!bp.condition || !!bp.logMessage || !!bp.hitCondition || !!bp.triggeredBy)) {
// Show the dialog if there is a potential condition to be accidently lost.
// Do not show dialog on linux due to electron issue freezing the mouse #50026
const logPoint = breakpoints.every(bp => !!bp.logMessage);
const breakpointType = logPoint ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
const disabledBreakpointDialogMessage = nls.localize(
'breakpointHasConditionDisabled',
"This {0} has a {1} that will get lost on remove. Consider enabling the {0} instead.",
breakpointType.toLowerCase(),
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
);
const enabledBreakpointDialogMessage = nls.localize(
'breakpointHasConditionEnabled',
"This {0} has a {1} that will get lost on remove. Consider disabling the {0} instead.",
breakpointType.toLowerCase(),
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
);
await this.dialogService.prompt({
type: severity.Info,
message: enabled ? enabledBreakpointDialogMessage : disabledBreakpointDialogMessage,
buttons: [
{
label: nls.localize({ key: 'removeLogPoint', comment: ['&& denotes a mnemonic'] }, "&&Remove {0}", breakpointType),
run: () => breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()))
},
{
label: nls.localize('disableLogPoint', "{0} {1}", enabled ? nls.localize({ key: 'disable', comment: ['&& denotes a mnemonic'] }, "&&Disable") : nls.localize({ key: 'enable', comment: ['&& denotes a mnemonic'] }, "&&Enable"), breakpointType),
run: () => breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!enabled, bp))
}
],
cancelButton: true
});
} else {
if (!enabled) {
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!enabled, bp));
} else {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
}
} else if (canSetBreakpoints) {
if (e.event.middleButton) {
const action = this.configurationService.getValue<IDebugConfiguration>('debug').gutterMiddleClickAction;
if (action !== 'none') {
let context: BreakpointWidgetContext;
switch (action) {
case 'logpoint':
context = BreakpointWidgetContext.LOG_MESSAGE;
break;
case 'conditionalBreakpoint':
context = BreakpointWidgetContext.CONDITION;
break;
case 'triggeredBreakpoint':
context = BreakpointWidgetContext.TRIGGER_POINT;
}
this.showBreakpointWidget(lineNumber, undefined, context);
}
} else {
this.debugService.addBreakpoints(uri, [{ lineNumber }]);
}
}
}
}));
if (!(BrowserFeatures.pointerEvents && isSafari)) {
/**
* We disable the hover feature for Safari on iOS as
* 1. Browser hover events are handled specially by the system (it treats first click as hover if there is `:hover` css registered). Below hover behavior will confuse users with inconsistent expeirence.
* 2. When users click on line numbers, the breakpoint hint displays immediately, however it doesn't create the breakpoint unless users click on the left gutter. On a touch screen, it's hard to click on that small area.
*/
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
if (!this.debugService.getAdapterManager().hasEnabledDebuggers()) {
return;
}
let showBreakpointHintAtLineNumber = -1;
const model = this.editor.getModel();
if (model && e.target.position && (e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN || e.target.type === MouseTargetType.GUTTER_LINE_NUMBERS) && this.debugService.canSetBreakpointsIn(model) &&
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
const data = e.target.detail;
if (!data.isAfterLines) {
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
}
}
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
}));
this.toDispose.push(this.editor.onMouseLeave(() => {
this.ensureBreakpointHintDecoration(-1);
}));
}
this.toDispose.push(this.editor.onDidChangeModel(async () => {
this.closeBreakpointWidget();
await this.setDecorations();
}));
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => {
if (!this.ignoreBreakpointsChangeEvent && !this.setDecorationsScheduler.isScheduled()) {
this.setDecorationsScheduler.schedule();
}
}));
this.toDispose.push(this.debugService.onDidChangeState(() => {
// We need to update breakpoint decorations when state changes since the top stack frame and breakpoint decoration might change
if (!this.setDecorationsScheduler.isScheduled()) {
this.setDecorationsScheduler.schedule();
}
}));
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged()));
this.toDispose.push(this.configurationService.onDidChangeConfiguration(async (e) => {
if (e.affectsConfiguration('debug.showBreakpointsInOverviewRuler') || e.affectsConfiguration('debug.showInlineBreakpointCandidates')) {
await this.setDecorations();
}
}));
}