debugCommands.ts 20.4 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import * as nls from 'vs/nls';
7 8
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { List } from 'vs/base/browser/ui/list/listWidget';
9
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
10
import { IListService } from 'vs/platform/list/browser/listService';
11
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
I
isidor 已提交
12
import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, CONTEXT_BREAKPOINT_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, REPL_ID, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
13
import { Expression, Variable, Breakpoint, FunctionBreakpoint, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
14
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
I
isidor 已提交
15
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
B
Benjamin Pasero 已提交
16
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
I
isidor 已提交
17
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
18
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
I
isidor 已提交
19 20
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
21
import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView';
22
import { INotificationService } from 'vs/platform/notification/common/notification';
23
import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';
I
isidor 已提交
24
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
25
import { PanelFocusContext } from 'vs/workbench/common/panel';
26 27
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { onUnexpectedError } from 'vs/base/common/errors';
28 29 30 31
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { startDebugging } from 'vs/workbench/contrib/debug/common/debugUtils';
I
isidor 已提交
32
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
I
isidor 已提交
33
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
I
isidor 已提交
34
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
35

36 37
export const ADD_CONFIGURATION_ID = 'debug.addConfiguration';
export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint';
38 39 40 41 42 43 44 45 46 47 48 49 50
export const COPY_STACK_TRACE_ID = 'debug.copyStackTrace';
export const REVERSE_CONTINUE_ID = 'workbench.action.debug.reverseContinue';
export const STEP_BACK_ID = 'workbench.action.debug.stepBack';
export const RESTART_SESSION_ID = 'workbench.action.debug.restart';
export const TERMINATE_THREAD_ID = 'workbench.action.debug.terminateThread';
export const STEP_OVER_ID = 'workbench.action.debug.stepOver';
export const STEP_INTO_ID = 'workbench.action.debug.stepInto';
export const STEP_OUT_ID = 'workbench.action.debug.stepOut';
export const PAUSE_ID = 'workbench.action.debug.pause';
export const DISCONNECT_ID = 'workbench.action.debug.disconnect';
export const STOP_ID = 'workbench.action.debug.stop';
export const RESTART_FRAME_ID = 'workbench.action.debug.restartFrame';
export const CONTINUE_ID = 'workbench.action.debug.continue';
I
isidor 已提交
51
export const FOCUS_REPL_ID = 'workbench.debug.action.focusRepl';
I
isidor 已提交
52
export const JUMP_TO_CURSOR_ID = 'debug.jumpToCursor';
53 54 55 56 57

function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined, run: (thread: IThread) => Promise<void>, ): void {
	const debugService = accessor.get(IDebugService);
	if (!(thread instanceof Thread)) {
		thread = debugService.getViewModel().focusedThread;
58 59 60 61 62
		if (!thread) {
			const focusedSession = debugService.getViewModel().focusedSession;
			const threads = focusedSession ? focusedSession.getAllThreads() : undefined;
			thread = threads && threads.length ? threads[0] : undefined;
		}
63 64 65 66 67 68
	}

	if (thread) {
		run(thread).then(undefined, onUnexpectedError);
	}
}
69

70 71
export function registerCommands(): void {

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	CommandsRegistry.registerCommand({
		id: COPY_STACK_TRACE_ID,
		handler: (accessor: ServicesAccessor, _: string, frame: IStackFrame) => {
			const textResourcePropertiesService = accessor.get(ITextResourcePropertiesService);
			const clipboardService = accessor.get(IClipboardService);
			const eol = textResourcePropertiesService.getEOL(frame.source.uri);
			clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol));
		}
	});

	CommandsRegistry.registerCommand({
		id: REVERSE_CONTINUE_ID,
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.reverseContinue());
		}
	});

	CommandsRegistry.registerCommand({
		id: STEP_BACK_ID,
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.stepBack());
		}
	});

	CommandsRegistry.registerCommand({
		id: TERMINATE_THREAD_ID,
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.terminate());
		}
	});

I
isidor 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	CommandsRegistry.registerCommand({
		id: JUMP_TO_CURSOR_ID,
		handler: async (accessor: ServicesAccessor) => {
			const debugService = accessor.get(IDebugService);
			const stackFrame = debugService.getViewModel().focusedStackFrame;
			const editorService = accessor.get(IEditorService);
			const activeEditor = editorService.activeEditor;
			const notificationService = accessor.get(INotificationService);
			const quickInputService = accessor.get(IQuickInputService);

			if (stackFrame && isCodeEditor(activeEditor)) {
				const position = activeEditor.getPosition();
				const resource = activeEditor.getResource();
				if (position && resource) {
					const source = stackFrame.thread.session.getSourceForUri(resource);
					if (source) {
						const response = await stackFrame.thread.session.gotoTargets(source, position.lineNumber, position.column);
						const targets = response.body.targets;
						if (targets.length) {
							let id = targets[0].id;
							if (targets.length > 1) {
								const picks = targets.map(t => ({ label: t.label, _id: t.id }));
								const pick = await quickInputService.pick(picks, { placeHolder: nls.localize('chooseLocation', "Choose the specific location") });
								if (!pick) {
									return;
								}

								id = pick._id;
							}

							return await stackFrame.thread.session.goto(stackFrame.thread.threadId, id);
						}
					}
				}
			}

			return notificationService.warn(nls.localize('noExecutableCode', "No executable code is associated at the current cursor position."));
		}
	});

	MenuRegistry.appendMenuItem(MenuId.EditorContext, {
		command: {
			id: JUMP_TO_CURSOR_ID,
			title: nls.localize('jumpToCursor', "Jump to Cursor"),
			category: { value: nls.localize('debug', "Debug"), original: 'Debug' }
		},
		when: ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED, EditorContextKeys.editorTextFocus),
		group: 'debug',
		order: 3
	});

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: RESTART_SESSION_ID,
		weight: KeybindingWeight.WorkbenchContrib,
		primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.F5,
		when: CONTEXT_IN_DEBUG_MODE,
		handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => {
			const debugService = accessor.get(IDebugService);
			if (!session || !session.getId) {
				session = debugService.getViewModel().focusedSession;
			}

			if (!session) {
				const historyService = accessor.get(IHistoryService);
				startDebugging(debugService, historyService, false);
			} else {
				session.removeReplExpressions();
				debugService.restartSession(session).then(undefined, onUnexpectedError);
			}
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: STEP_OVER_ID,
		weight: KeybindingWeight.WorkbenchContrib,
		primary: KeyCode.F10,
		when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.next());
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: STEP_INTO_ID,
I
isidor 已提交
187
		weight: KeybindingWeight.WorkbenchContrib + 10, // Have a stronger weight to have priority over full screen when debugging
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
		primary: KeyCode.F11,
		when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.stepIn());
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: STEP_OUT_ID,
		weight: KeybindingWeight.WorkbenchContrib,
		primary: KeyMod.Shift | KeyCode.F11,
		when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.stepOut());
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: PAUSE_ID,
		weight: KeybindingWeight.WorkbenchContrib,
		primary: KeyCode.F6,
		when: CONTEXT_DEBUG_STATE.isEqualTo('running'),
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
I
isidor 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223
			const debugService = accessor.get(IDebugService);
			if (!(thread instanceof Thread)) {
				thread = debugService.getViewModel().focusedThread;
				if (!thread) {
					const session = debugService.getViewModel().focusedSession;
					const threads = session && session.getAllThreads();
					thread = threads && threads.length ? threads[0] : undefined;
				}
			}

			if (thread) {
				thread.pause().then(undefined, onUnexpectedError);
			}
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
		}
	});

	CommandsRegistry.registerCommand({
		id: DISCONNECT_ID,
		handler: (accessor: ServicesAccessor) => {
			const debugService = accessor.get(IDebugService);
			const session = debugService.getViewModel().focusedSession;
			debugService.stopSession(session).then(undefined, onUnexpectedError);
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: STOP_ID,
		weight: KeybindingWeight.WorkbenchContrib,
		primary: KeyMod.Shift | KeyCode.F5,
		when: CONTEXT_IN_DEBUG_MODE,
		handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => {
			const debugService = accessor.get(IDebugService);
			if (!session || !session.getId) {
				session = debugService.getViewModel().focusedSession;
I
isidor 已提交
245
				const configurationService = accessor.get(IConfigurationService);
I
isidor 已提交
246
				const showSubSessions = configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
I
isidor 已提交
247
				// Stop should be sent to the root parent session
I
isidor 已提交
248
				while (!showSubSessions && session && session.parentSession) {
I
isidor 已提交
249 250
					session = session.parentSession;
				}
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
			}

			debugService.stopSession(session).then(undefined, onUnexpectedError);
		}
	});

	CommandsRegistry.registerCommand({
		id: RESTART_FRAME_ID,
		handler: (accessor: ServicesAccessor, _: string, frame: IStackFrame | undefined) => {
			const debugService = accessor.get(IDebugService);
			if (!frame) {
				frame = debugService.getViewModel().focusedStackFrame;
			}

			return frame!.restart();
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: CONTINUE_ID,
		weight: KeybindingWeight.WorkbenchContrib,
		primary: KeyCode.F5,
		when: CONTEXT_IN_DEBUG_MODE,
		handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => {
			getThreadAndRun(accessor, thread, thread => thread.continue());
		}
	});

I
isidor 已提交
279 280 281 282 283 284 285 286
	CommandsRegistry.registerCommand({
		id: FOCUS_REPL_ID,
		handler: (accessor) => {
			const panelService = accessor.get(IPanelService);
			panelService.openPanel(REPL_ID, true);
		}
	});

287 288 289
	CommandsRegistry.registerCommand({
		id: 'debug.startFromConfig',
		handler: (accessor, config: IConfig) => {
290
			const debugService = accessor.get(IDebugService);
291
			debugService.startDebugging(undefined, config).then(undefined, onUnexpectedError);
292 293 294
		}
	});

295 296
	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'debug.toggleBreakpoint',
297
		weight: KeybindingWeight.WorkbenchContrib + 5,
I
isidor 已提交
298
		when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_FOCUSED, InputFocusedContext.toNegated()),
299 300 301 302
		primary: KeyCode.Space,
		handler: (accessor) => {
			const listService = accessor.get(IListService);
			const debugService = accessor.get(IDebugService);
303 304 305 306
			const list = listService.lastFocusedList;
			if (list instanceof List) {
				const focused = <IEnablement[]>list.getFocusedElements();
				if (focused && focused.length) {
307
					debugService.enableOrDisableBreakpoints(!focused[0].enabled, focused[0]);
308
				}
309 310 311 312
			}
		}
	});

313
	KeybindingsRegistry.registerCommandAndKeybindingRule({
314
		id: 'debug.enableOrDisableBreakpoint',
315
		weight: KeybindingWeight.WorkbenchContrib,
316
		primary: undefined,
317 318 319
		when: EditorContextKeys.editorTextFocus,
		handler: (accessor) => {
			const debugService = accessor.get(IDebugService);
320
			const editorService = accessor.get(IEditorService);
321 322 323
			const widget = editorService.activeTextEditorWidget;
			if (isCodeEditor(widget)) {
				const model = widget.getModel();
I
isidor 已提交
324
				if (model) {
325
					const position = widget.getPosition();
I
isidor 已提交
326 327 328 329 330
					if (position) {
						const bps = debugService.getModel().getBreakpoints({ uri: model.uri, lineNumber: position.lineNumber });
						if (bps.length) {
							debugService.enableOrDisableBreakpoints(!bps[0].enabled, bps[0]);
						}
I
isidor 已提交
331
					}
332 333 334 335 336
				}
			}
		}
	});

337 338
	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'debug.renameWatchExpression',
339
		weight: KeybindingWeight.WorkbenchContrib + 5,
340 341 342 343 344 345
		when: CONTEXT_WATCH_EXPRESSIONS_FOCUSED,
		primary: KeyCode.F2,
		mac: { primary: KeyCode.Enter },
		handler: (accessor) => {
			const listService = accessor.get(IListService);
			const debugService = accessor.get(IDebugService);
J
Joao Moreno 已提交
346
			const focused = listService.lastFocusedList;
347

I
isidor 已提交
348 349 350 351
			if (focused) {
				const elements = focused.getFocus();
				if (Array.isArray(elements) && elements[0] instanceof Expression) {
					debugService.getViewModel().setSelectedExpression(elements[0]);
352 353 354 355 356 357 358
				}
			}
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'debug.setVariable',
359
		weight: KeybindingWeight.WorkbenchContrib + 5,
360 361 362 363 364 365
		when: CONTEXT_VARIABLES_FOCUSED,
		primary: KeyCode.F2,
		mac: { primary: KeyCode.Enter },
		handler: (accessor) => {
			const listService = accessor.get(IListService);
			const debugService = accessor.get(IDebugService);
J
Joao Moreno 已提交
366
			const focused = listService.lastFocusedList;
367

I
isidor 已提交
368 369 370 371
			if (focused) {
				const elements = focused.getFocus();
				if (Array.isArray(elements) && elements[0] instanceof Variable) {
					debugService.getViewModel().setSelectedExpression(elements[0]);
372 373 374 375 376 377 378
				}
			}
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'debug.removeWatchExpression',
379
		weight: KeybindingWeight.WorkbenchContrib,
380
		when: ContextKeyExpr.and(CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_EXPRESSION_SELECTED.toNegated()),
381 382 383 384 385
		primary: KeyCode.Delete,
		mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },
		handler: (accessor) => {
			const listService = accessor.get(IListService);
			const debugService = accessor.get(IDebugService);
J
Joao Moreno 已提交
386
			const focused = listService.lastFocusedList;
387

I
isidor 已提交
388 389 390 391
			if (focused) {
				const elements = focused.getFocus();
				if (Array.isArray(elements) && elements[0] instanceof Expression) {
					debugService.removeWatchExpressions(elements[0].getId());
392 393 394 395 396 397 398
				}
			}
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'debug.removeBreakpoint',
399
		weight: KeybindingWeight.WorkbenchContrib,
400
		when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_BREAKPOINT_SELECTED.toNegated()),
401 402 403 404 405
		primary: KeyCode.Delete,
		mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },
		handler: (accessor) => {
			const listService = accessor.get(IListService);
			const debugService = accessor.get(IDebugService);
406
			const list = listService.lastFocusedList;
407

408 409 410
			if (list instanceof List) {
				const focused = list.getFocusedElements();
				const element = focused.length ? focused[0] : undefined;
411
				if (element instanceof Breakpoint) {
412
					debugService.removeBreakpoints(element.getId());
413
				} else if (element instanceof FunctionBreakpoint) {
414
					debugService.removeFunctionBreakpoints(element.getId());
415 416 417 418
				}
			}
		}
	});
I
isidor 已提交
419 420

	KeybindingsRegistry.registerCommandAndKeybindingRule({
I
isidor 已提交
421
		id: 'debug.installAdditionalDebuggers',
422
		weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
423
		when: undefined,
I
isidor 已提交
424 425 426 427 428 429
		primary: undefined,
		handler: (accessor) => {
			const viewletService = accessor.get(IViewletService);
			return viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true)
				.then(viewlet => viewlet as IExtensionsViewlet)
				.then(viewlet => {
430
					viewlet.search('tag:debuggers @sort:installs');
I
isidor 已提交
431 432 433 434
					viewlet.focus();
				});
		}
	});
I
isidor 已提交
435 436

	KeybindingsRegistry.registerCommandAndKeybindingRule({
437
		id: ADD_CONFIGURATION_ID,
438
		weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
439 440
		when: undefined,
		primary: undefined,
I
isidor 已提交
441
		handler: (accessor, launchUri: string) => {
I
isidor 已提交
442
			const manager = accessor.get(IDebugService).getConfigurationManager();
443
			if (accessor.get(IWorkspaceContextService).getWorkbenchState() === WorkbenchState.EMPTY) {
444
				accessor.get(INotificationService).info(nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration."));
445
				return undefined;
446
			}
447
			const launch = manager.getLaunches().filter(l => l.uri.toString() === launchUri).pop() || manager.selectedConfiguration.launch;
448

I
isidor 已提交
449
			return launch!.openConfigFile(false, false).then(({ editor, created }) => {
450
				if (editor && !created) {
I
isidor 已提交
451
					const codeEditor = <ICodeEditor>editor.getControl();
I
isidor 已提交
452 453 454 455 456 457 458 459 460
					if (codeEditor) {
						return codeEditor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).addLaunchConfiguration();
					}
				}

				return undefined;
			});
		}
	});
I
isidor 已提交
461

I
isidor 已提交
462
	const inlineBreakpointHandler = (accessor: ServicesAccessor) => {
463
		const debugService = accessor.get(IDebugService);
464
		const editorService = accessor.get(IEditorService);
465 466 467
		const widget = editorService.activeTextEditorWidget;
		if (isCodeEditor(widget)) {
			const position = widget.getPosition();
I
isidor 已提交
468 469 470 471
			if (position && widget.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(widget.getModel())) {
				const modelUri = widget.getModel().uri;
				const breakpointAlreadySet = debugService.getModel().getBreakpoints({ lineNumber: position.lineNumber, uri: modelUri })
					.some(bp => (bp.sessionAgnosticData.column === position.column || (!bp.column && position.column <= 1)));
I
isidor 已提交
472

I
isidor 已提交
473 474 475
				if (!breakpointAlreadySet) {
					debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column > 1 ? position.column : undefined }], 'debugCommands.inlineBreakpointCommand');
				}
476 477 478
			}
		}
	};
I
isidor 已提交
479

480
	KeybindingsRegistry.registerCommandAndKeybindingRule({
481
		weight: KeybindingWeight.WorkbenchContrib,
482
		primary: KeyMod.Shift | KeyCode.F9,
483
		when: EditorContextKeys.editorTextFocus,
484
		id: TOGGLE_INLINE_BREAKPOINT_ID,
485 486
		handler: inlineBreakpointHandler
	});
I
isidor 已提交
487 488 489

	MenuRegistry.appendMenuItem(MenuId.EditorContext, {
		command: {
490
			id: TOGGLE_INLINE_BREAKPOINT_ID,
491 492
			title: nls.localize('addInlineBreakpoint', "Add Inline Breakpoint"),
			category: { value: nls.localize('debug', "Debug"), original: 'Debug' }
I
isidor 已提交
493
		},
I
isidor 已提交
494
		when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, PanelFocusContext.toNegated(), EditorContextKeys.editorTextFocus),
I
isidor 已提交
495 496 497
		group: 'debug',
		order: 1
	});
498 499 500

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'debug.openBreakpointToSide',
501
		weight: KeybindingWeight.WorkbenchContrib,
502 503 504 505 506 507 508 509 510
		when: CONTEXT_BREAKPOINTS_FOCUSED,
		primary: KeyMod.CtrlCmd | KeyCode.Enter,
		secondary: [KeyMod.Alt | KeyCode.Enter],
		handler: (accessor) => {
			const listService = accessor.get(IListService);
			const list = listService.lastFocusedList;
			if (list instanceof List) {
				const focus = list.getFocusedElements();
				if (focus.length && focus[0] instanceof Breakpoint) {
511
					return openBreakpointSource(focus[0], true, false, accessor.get(IDebugService), accessor.get(IEditorService));
512 513 514
				}
			}

515
			return undefined;
516 517
		}
	});
518
}