in src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts [175:289]
private registerListeners(): void {
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
const data = e.target.detail as IMarginData;
const model = this.editor.getModel();
if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
return;
}
const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(model);
const lineNumber = e.target.position.lineNumber;
const uri = model.uri;
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
if (!canSetBreakpoints) {
return;
}
const anchor = { x: e.event.posx, y: e.event.posy };
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber, uri });
const actions = this.getContextMenuActions(breakpoints, uri, lineNumber);
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => actions,
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined,
onHide: () => dispose(actions)
});
} else {
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
if (breakpoints.length) {
// 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
if (!env.isLinux && breakpoints.some(bp => !!bp.condition || !!bp.logMessage || !!bp.hitCondition)) {
const logPoint = breakpoints.every(bp => !!bp.logMessage);
const breakpointType = logPoint ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
const disable = breakpoints.some(bp => bp.enabled);
const enabling = 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 disabling = 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")
);
const { choice } = await this.dialogService.show(severity.Info, disable ? disabling : enabling, [
nls.localize('removeLogPoint', "Remove {0}", breakpointType),
nls.localize('disableLogPoint', "{0} {1}", disable ? nls.localize('disable', "Disable") : nls.localize('enable', "Enable"), breakpointType),
nls.localize('cancel', "Cancel")
], { cancelId: 2 });
if (choice === 0) {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
if (choice === 1) {
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp));
}
} else {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
} else if (canSetBreakpoints) {
this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorGutter`);
}
}
}));
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) => {
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.getConfigurationManager().canSetBreakpointsIn(model) &&
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
const data = e.target.detail as IMarginData;
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();
}
}));
}