Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts
5236 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { getDomNodePagePosition } from '../../../../base/browser/dom.js';
7
import { toAction } from '../../../../base/common/actions.js';
8
import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
9
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
10
import { EditorAction, IActionOptions, registerEditorAction } from '../../../../editor/browser/editorExtensions.js';
11
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
12
import { Position } from '../../../../editor/common/core/position.js';
13
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
14
import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
15
import { MessageController } from '../../../../editor/contrib/message/browser/messageController.js';
16
import * as nls from '../../../../nls.js';
17
import { ILocalizedString } from '../../../../platform/action/common/action.js';
18
import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
19
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
20
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
21
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
22
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
23
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
24
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
25
import { PanelFocusContext } from '../../../common/contextkeys.js';
26
import { ChatContextKeys } from '../../chat/common/actions/chatContextKeys.js';
27
import { openBreakpointSource } from './breakpointsView.js';
28
import { DisassemblyView, IDisassembledInstructionEntry } from './disassemblyView.js';
29
import { Repl } from './repl.js';
30
import { BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_DISASSEMBLY_VIEW_FOCUS, CONTEXT_EXCEPTION_WIDGET_VISIBLE, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_IN_DEBUG_MODE, CONTEXT_LANGUAGE_SUPPORTS_DISASSEMBLE_REQUEST, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IDebugConfiguration, IDebugEditorContribution, IDebugService, REPL_VIEW_ID, WATCH_VIEW_ID } from '../common/debug.js';
31
import { getEvaluatableExpressionAtPosition } from '../common/debugUtils.js';
32
import { DisassemblyViewInput } from '../common/disassemblyViewInput.js';
33
import { IEditorService } from '../../../services/editor/common/editorService.js';
34
import { IViewsService } from '../../../services/views/common/viewsService.js';
35
import { TOGGLE_BREAKPOINT_ID } from '../../../../workbench/contrib/debug/browser/debugCommands.js';
36
37
class ToggleBreakpointAction extends Action2 {
38
constructor() {
39
super({
40
id: TOGGLE_BREAKPOINT_ID,
41
title: {
42
...nls.localize2('toggleBreakpointAction', "Toggle Breakpoint"),
43
mnemonicTitle: nls.localize({ key: 'miToggleBreakpoint', comment: ['&& denotes a mnemonic'] }, "Toggle &&Breakpoint"),
44
},
45
category: nls.localize2('debugCategory', "Debug"),
46
f1: true,
47
precondition: CONTEXT_DEBUGGERS_AVAILABLE,
48
keybinding: {
49
when: ContextKeyExpr.or(EditorContextKeys.editorTextFocus, CONTEXT_DISASSEMBLY_VIEW_FOCUS),
50
primary: KeyCode.F9,
51
weight: KeybindingWeight.EditorContrib
52
},
53
menu: [{
54
id: MenuId.MenubarDebugMenu,
55
when: CONTEXT_DEBUGGERS_AVAILABLE,
56
group: '4_new_breakpoint',
57
order: 1
58
}]
59
});
60
}
61
62
async run(accessor: ServicesAccessor, entry?: IDisassembledInstructionEntry): Promise<void> {
63
const editorService = accessor.get(IEditorService);
64
const debugService = accessor.get(IDebugService);
65
66
const activePane = editorService.activeEditorPane;
67
if (activePane instanceof DisassemblyView) {
68
const location = entry ? activePane.getAddressAndOffset(entry) : activePane.focusedAddressAndOffset;
69
if (location) {
70
const bps = debugService.getModel().getInstructionBreakpoints();
71
const toRemove = bps.find(bp => bp.address === location.address);
72
if (toRemove) {
73
debugService.removeInstructionBreakpoints(toRemove.instructionReference, toRemove.offset);
74
} else {
75
debugService.addInstructionBreakpoint({ instructionReference: location.reference, offset: location.offset, address: location.address, canPersist: false });
76
}
77
}
78
return;
79
}
80
81
const codeEditorService = accessor.get(ICodeEditorService);
82
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
83
if (editor?.hasModel()) {
84
const modelUri = editor.getModel().uri;
85
const canSet = debugService.canSetBreakpointsIn(editor.getModel());
86
// Does not account for multi line selections, Set to remove multiple cursor on the same line
87
const lineNumbers = [...new Set(editor.getSelections().map(s => s.getPosition().lineNumber))];
88
89
await Promise.all(lineNumbers.map(async line => {
90
const bps = debugService.getModel().getBreakpoints({ lineNumber: line, uri: modelUri });
91
if (bps.length) {
92
await Promise.all(bps.map(bp => debugService.removeBreakpoints(bp.getId())));
93
} else if (canSet) {
94
await debugService.addBreakpoints(modelUri, [{ lineNumber: line }]);
95
}
96
}));
97
}
98
}
99
}
100
101
class ConditionalBreakpointAction extends EditorAction {
102
constructor() {
103
super({
104
id: 'editor.debug.action.conditionalBreakpoint',
105
label: nls.localize2('conditionalBreakpointEditorAction', "Debug: Add Conditional Breakpoint..."),
106
precondition: CONTEXT_DEBUGGERS_AVAILABLE,
107
menuOpts: {
108
menuId: MenuId.MenubarNewBreakpointMenu,
109
title: nls.localize({ key: 'miConditionalBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Conditional Breakpoint..."),
110
group: '1_breakpoints',
111
order: 1,
112
when: CONTEXT_DEBUGGERS_AVAILABLE
113
}
114
});
115
}
116
117
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
118
const debugService = accessor.get(IDebugService);
119
120
const position = editor.getPosition();
121
if (position && editor.hasModel() && debugService.canSetBreakpointsIn(editor.getModel())) {
122
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)?.showBreakpointWidget(position.lineNumber, undefined, BreakpointWidgetContext.CONDITION);
123
}
124
}
125
}
126
127
class LogPointAction extends EditorAction {
128
129
constructor() {
130
super({
131
id: 'editor.debug.action.addLogPoint',
132
label: nls.localize2('logPointEditorAction', "Debug: Add Logpoint..."),
133
precondition: CONTEXT_DEBUGGERS_AVAILABLE,
134
menuOpts: [
135
{
136
menuId: MenuId.MenubarNewBreakpointMenu,
137
title: nls.localize({ key: 'miLogPoint', comment: ['&& denotes a mnemonic'] }, "&&Logpoint..."),
138
group: '1_breakpoints',
139
order: 4,
140
when: CONTEXT_DEBUGGERS_AVAILABLE,
141
}
142
]
143
});
144
}
145
146
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
147
const debugService = accessor.get(IDebugService);
148
149
const position = editor.getPosition();
150
if (position && editor.hasModel() && debugService.canSetBreakpointsIn(editor.getModel())) {
151
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)?.showBreakpointWidget(position.lineNumber, position.column, BreakpointWidgetContext.LOG_MESSAGE);
152
}
153
}
154
}
155
156
class TriggerByBreakpointAction extends EditorAction {
157
158
constructor() {
159
super({
160
id: 'editor.debug.action.triggerByBreakpoint',
161
label: nls.localize('triggerByBreakpointEditorAction', "Debug: Add Triggered Breakpoint..."),
162
precondition: CONTEXT_DEBUGGERS_AVAILABLE,
163
alias: 'Debug: Triggered Breakpoint...',
164
menuOpts: [
165
{
166
menuId: MenuId.MenubarNewBreakpointMenu,
167
title: nls.localize({ key: 'miTriggerByBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Triggered Breakpoint..."),
168
group: '1_breakpoints',
169
order: 4,
170
when: CONTEXT_DEBUGGERS_AVAILABLE,
171
}
172
]
173
});
174
}
175
176
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
177
const debugService = accessor.get(IDebugService);
178
179
const position = editor.getPosition();
180
if (position && editor.hasModel() && debugService.canSetBreakpointsIn(editor.getModel())) {
181
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)?.showBreakpointWidget(position.lineNumber, position.column, BreakpointWidgetContext.TRIGGER_POINT);
182
}
183
}
184
}
185
186
class EditBreakpointAction extends EditorAction {
187
constructor() {
188
super({
189
id: 'editor.debug.action.editBreakpoint',
190
label: nls.localize('EditBreakpointEditorAction', "Debug: Edit Breakpoint"),
191
alias: 'Debug: Edit Existing Breakpoint',
192
precondition: CONTEXT_DEBUGGERS_AVAILABLE,
193
menuOpts: {
194
menuId: MenuId.MenubarNewBreakpointMenu,
195
title: nls.localize({ key: 'miEditBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Edit Breakpoint"),
196
group: '1_breakpoints',
197
order: 1,
198
when: CONTEXT_DEBUGGERS_AVAILABLE
199
}
200
});
201
}
202
203
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
204
const debugService = accessor.get(IDebugService);
205
206
const position = editor.getPosition();
207
const debugModel = debugService.getModel();
208
if (!(editor.hasModel() && position)) {
209
return;
210
}
211
212
const lineBreakpoints = debugModel.getBreakpoints({ lineNumber: position.lineNumber });
213
if (lineBreakpoints.length === 0) {
214
return;
215
}
216
217
const breakpointDistances = lineBreakpoints.map(b => {
218
if (!b.column) {
219
return position.column;
220
}
221
222
return Math.abs(b.column - position.column);
223
});
224
const closestBreakpointIndex = breakpointDistances.indexOf(Math.min(...breakpointDistances));
225
const closestBreakpoint = lineBreakpoints[closestBreakpointIndex];
226
227
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)?.showBreakpointWidget(closestBreakpoint.lineNumber, closestBreakpoint.column);
228
}
229
}
230
231
class OpenDisassemblyViewAction extends Action2 {
232
233
public static readonly ID = 'debug.action.openDisassemblyView';
234
235
constructor() {
236
super({
237
id: OpenDisassemblyViewAction.ID,
238
title: {
239
...nls.localize2('openDisassemblyView', "Open Disassembly View"),
240
mnemonicTitle: nls.localize({ key: 'miDisassemblyView', comment: ['&& denotes a mnemonic'] }, "&&DisassemblyView"),
241
},
242
precondition: CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE,
243
menu: [
244
{
245
id: MenuId.EditorContext,
246
group: 'debug',
247
order: 5,
248
when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, PanelFocusContext.toNegated(), CONTEXT_DEBUG_STATE.isEqualTo('stopped'), EditorContextKeys.editorTextFocus, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_LANGUAGE_SUPPORTS_DISASSEMBLE_REQUEST)
249
},
250
{
251
id: MenuId.DebugCallStackContext,
252
group: 'z_commands',
253
order: 50,
254
when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED)
255
},
256
{
257
id: MenuId.CommandPalette,
258
when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED)
259
}
260
]
261
});
262
}
263
264
run(accessor: ServicesAccessor): void {
265
const editorService = accessor.get(IEditorService);
266
editorService.openEditor(DisassemblyViewInput.instance, { pinned: true, revealIfOpened: true });
267
}
268
}
269
270
class ToggleDisassemblyViewSourceCodeAction extends Action2 {
271
272
public static readonly ID = 'debug.action.toggleDisassemblyViewSourceCode';
273
public static readonly configID: string = 'debug.disassemblyView.showSourceCode';
274
275
constructor() {
276
super({
277
id: ToggleDisassemblyViewSourceCodeAction.ID,
278
title: {
279
...nls.localize2('toggleDisassemblyViewSourceCode', "Toggle Source Code in Disassembly View"),
280
mnemonicTitle: nls.localize({ key: 'mitogglesource', comment: ['&& denotes a mnemonic'] }, "&&ToggleSource"),
281
},
282
metadata: {
283
description: nls.localize2('toggleDisassemblyViewSourceCodeDescription', 'Shows or hides source code in disassembly')
284
},
285
f1: true,
286
});
287
}
288
289
run(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {
290
const configService = accessor.get(IConfigurationService);
291
if (configService) {
292
const value = configService.getValue<IDebugConfiguration>('debug').disassemblyView.showSourceCode;
293
configService.updateValue(ToggleDisassemblyViewSourceCodeAction.configID, !value);
294
}
295
}
296
}
297
298
export class RunToCursorAction extends EditorAction {
299
300
public static readonly ID = 'editor.debug.action.runToCursor';
301
public static readonly LABEL: ILocalizedString = nls.localize2('runToCursor', "Run to Cursor");
302
303
constructor() {
304
super({
305
id: RunToCursorAction.ID,
306
label: RunToCursorAction.LABEL.value,
307
alias: 'Debug: Run to Cursor',
308
precondition: ContextKeyExpr.and(
309
CONTEXT_DEBUGGERS_AVAILABLE,
310
PanelFocusContext.toNegated(),
311
ContextKeyExpr.or(EditorContextKeys.editorTextFocus, CONTEXT_DISASSEMBLY_VIEW_FOCUS),
312
ChatContextKeys.inChatSession.negate()
313
),
314
contextMenuOpts: {
315
group: 'debug',
316
order: 2,
317
when: CONTEXT_IN_DEBUG_MODE
318
}
319
});
320
}
321
322
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
323
const position = editor.getPosition();
324
if (!(editor.hasModel() && position)) {
325
return;
326
}
327
const uri = editor.getModel().uri;
328
329
const debugService = accessor.get(IDebugService);
330
const viewModel = debugService.getViewModel();
331
const uriIdentityService = accessor.get(IUriIdentityService);
332
333
let column: number | undefined = undefined;
334
const focusedStackFrame = viewModel.focusedStackFrame;
335
if (focusedStackFrame && uriIdentityService.extUri.isEqual(focusedStackFrame.source.uri, uri) && focusedStackFrame.range.startLineNumber === position.lineNumber) {
336
// If the cursor is on a line different than the one the debugger is currently paused on, then send the breakpoint on the line without a column
337
// otherwise set it at the precise column #102199
338
column = position.column;
339
}
340
await debugService.runTo(uri, position.lineNumber, column);
341
}
342
}
343
344
export class SelectionToReplAction extends EditorAction {
345
346
public static readonly ID = 'editor.debug.action.selectionToRepl';
347
public static readonly LABEL: ILocalizedString = nls.localize2('evaluateInDebugConsole', "Evaluate in Debug Console");
348
349
constructor() {
350
super({
351
id: SelectionToReplAction.ID,
352
label: SelectionToReplAction.LABEL.value,
353
alias: 'Debug: Evaluate in Console',
354
precondition: ContextKeyExpr.and(
355
CONTEXT_IN_DEBUG_MODE,
356
EditorContextKeys.editorTextFocus,
357
ChatContextKeys.inChatSession.negate()),
358
contextMenuOpts: {
359
group: 'debug',
360
order: 0
361
}
362
});
363
}
364
365
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
366
const debugService = accessor.get(IDebugService);
367
const viewsService = accessor.get(IViewsService);
368
const viewModel = debugService.getViewModel();
369
const session = viewModel.focusedSession;
370
if (!editor.hasModel() || !session) {
371
return;
372
}
373
374
const selection = editor.getSelection();
375
let text: string;
376
if (selection.isEmpty()) {
377
text = editor.getModel().getLineContent(selection.selectionStartLineNumber).trim();
378
} else {
379
text = editor.getModel().getValueInRange(selection);
380
}
381
382
const replView = await viewsService.openView(REPL_VIEW_ID, false) as Repl | undefined;
383
replView?.sendReplInput(text);
384
}
385
}
386
387
export class SelectionToWatchExpressionsAction extends EditorAction {
388
389
public static readonly ID = 'editor.debug.action.selectionToWatch';
390
public static readonly LABEL: ILocalizedString = nls.localize2('addToWatch', "Add to Watch");
391
392
constructor() {
393
super({
394
id: SelectionToWatchExpressionsAction.ID,
395
label: SelectionToWatchExpressionsAction.LABEL.value,
396
alias: 'Debug: Add to Watch',
397
precondition: ContextKeyExpr.and(
398
CONTEXT_IN_DEBUG_MODE,
399
EditorContextKeys.editorTextFocus,
400
ChatContextKeys.inChatSession.negate()),
401
contextMenuOpts: {
402
group: 'debug',
403
order: 1
404
}
405
});
406
}
407
408
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
409
const debugService = accessor.get(IDebugService);
410
const viewsService = accessor.get(IViewsService);
411
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
412
if (!editor.hasModel()) {
413
return;
414
}
415
416
let expression: string | undefined = undefined;
417
418
const model = editor.getModel();
419
const selection = editor.getSelection();
420
421
if (!selection.isEmpty()) {
422
expression = model.getValueInRange(selection);
423
} else {
424
const position = editor.getPosition();
425
const evaluatableExpression = await getEvaluatableExpressionAtPosition(languageFeaturesService, model, position);
426
if (!evaluatableExpression) {
427
return;
428
}
429
expression = evaluatableExpression.matchingExpression;
430
}
431
432
if (!expression) {
433
return;
434
}
435
436
await viewsService.openView(WATCH_VIEW_ID);
437
debugService.addWatchExpression(expression);
438
}
439
}
440
441
class ShowDebugHoverAction extends EditorAction {
442
443
constructor() {
444
super({
445
id: 'editor.debug.action.showDebugHover',
446
label: nls.localize2('showDebugHover', "Debug: Show Hover"),
447
precondition: CONTEXT_IN_DEBUG_MODE,
448
kbOpts: {
449
kbExpr: EditorContextKeys.editorTextFocus,
450
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyI),
451
weight: KeybindingWeight.EditorContrib
452
}
453
});
454
}
455
456
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
457
const position = editor.getPosition();
458
if (!position || !editor.hasModel()) {
459
return;
460
}
461
462
return editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID)?.showHover(position, true);
463
}
464
}
465
466
const NO_TARGETS_MESSAGE = nls.localize('editor.debug.action.stepIntoTargets.notAvailable', "Step targets are not available here");
467
468
class StepIntoTargetsAction extends EditorAction {
469
470
public static readonly ID = 'editor.debug.action.stepIntoTargets';
471
public static readonly LABEL = nls.localize({ key: 'stepIntoTargets', comment: ['Step Into Targets lets the user step into an exact function he or she is interested in.'] }, "Step Into Target");
472
473
constructor() {
474
super({
475
id: StepIntoTargetsAction.ID,
476
label: StepIntoTargetsAction.LABEL,
477
alias: 'Debug: Step Into Target',
478
precondition: ContextKeyExpr.and(CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), EditorContextKeys.editorTextFocus),
479
contextMenuOpts: {
480
group: 'debug',
481
order: 1.5
482
}
483
});
484
}
485
486
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
487
const debugService = accessor.get(IDebugService);
488
const contextMenuService = accessor.get(IContextMenuService);
489
const uriIdentityService = accessor.get(IUriIdentityService);
490
const session = debugService.getViewModel().focusedSession;
491
const frame = debugService.getViewModel().focusedStackFrame;
492
const selection = editor.getSelection();
493
494
const targetPosition = selection?.getPosition() || (frame && { lineNumber: frame.range.startLineNumber, column: frame.range.startColumn });
495
496
if (!session || !frame || !editor.hasModel() || !uriIdentityService.extUri.isEqual(editor.getModel().uri, frame.source.uri)) {
497
if (targetPosition) {
498
MessageController.get(editor)?.showMessage(NO_TARGETS_MESSAGE, targetPosition);
499
}
500
return;
501
}
502
503
504
const targets = await session.stepInTargets(frame.frameId);
505
if (!targets?.length) {
506
MessageController.get(editor)?.showMessage(NO_TARGETS_MESSAGE, targetPosition!);
507
return;
508
}
509
510
// If there is a selection, try to find the best target with a position to step into.
511
if (selection) {
512
const positionalTargets: { start: Position; end?: Position; target: DebugProtocol.StepInTarget }[] = [];
513
for (const target of targets) {
514
if (target.line) {
515
positionalTargets.push({
516
start: new Position(target.line, target.column || 1),
517
end: target.endLine ? new Position(target.endLine, target.endColumn || 1) : undefined,
518
target
519
});
520
}
521
}
522
523
positionalTargets.sort((a, b) => b.start.lineNumber - a.start.lineNumber || b.start.column - a.start.column);
524
525
const needle = selection.getPosition();
526
527
// Try to find a target with a start and end that is around the cursor
528
// position. Or, if none, whatever is before the cursor.
529
const best = positionalTargets.find(t => t.end && needle.isBefore(t.end) && t.start.isBeforeOrEqual(needle)) || positionalTargets.find(t => t.end === undefined && t.start.isBeforeOrEqual(needle));
530
if (best) {
531
session.stepIn(frame.thread.threadId, best.target.id);
532
return;
533
}
534
}
535
536
// Otherwise, show a context menu and have the user pick a target
537
editor.revealLineInCenterIfOutsideViewport(frame.range.startLineNumber);
538
const cursorCoords = editor.getScrolledVisiblePosition(targetPosition!);
539
const editorCoords = getDomNodePagePosition(editor.getDomNode());
540
const x = editorCoords.left + cursorCoords.left;
541
const y = editorCoords.top + cursorCoords.top + cursorCoords.height;
542
543
contextMenuService.showContextMenu({
544
getAnchor: () => ({ x, y }),
545
getActions: () => {
546
return targets.map(t => toAction({ id: `stepIntoTarget:${t.id}`, label: t.label, enabled: true, run: () => session.stepIn(frame.thread.threadId, t.id) }));
547
}
548
});
549
}
550
}
551
552
class GoToBreakpointAction extends EditorAction {
553
constructor(private isNext: boolean, opts: IActionOptions) {
554
super(opts);
555
}
556
557
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<any> {
558
const debugService = accessor.get(IDebugService);
559
const editorService = accessor.get(IEditorService);
560
const uriIdentityService = accessor.get(IUriIdentityService);
561
562
if (editor.hasModel()) {
563
const currentUri = editor.getModel().uri;
564
const currentLine = editor.getPosition().lineNumber;
565
//Breakpoints returned from `getBreakpoints` are already sorted.
566
const allEnabledBreakpoints = debugService.getModel().getBreakpoints({ enabledOnly: true });
567
568
//Try to find breakpoint in current file
569
let moveBreakpoint =
570
this.isNext
571
? allEnabledBreakpoints.filter(bp => uriIdentityService.extUri.isEqual(bp.uri, currentUri) && bp.lineNumber > currentLine).shift()
572
: allEnabledBreakpoints.filter(bp => uriIdentityService.extUri.isEqual(bp.uri, currentUri) && bp.lineNumber < currentLine).pop();
573
574
//Try to find breakpoints in following files
575
if (!moveBreakpoint) {
576
moveBreakpoint =
577
this.isNext
578
? allEnabledBreakpoints.filter(bp => bp.uri.toString() > currentUri.toString()).shift()
579
: allEnabledBreakpoints.filter(bp => bp.uri.toString() < currentUri.toString()).pop();
580
}
581
582
//Move to first or last possible breakpoint
583
if (!moveBreakpoint && allEnabledBreakpoints.length) {
584
moveBreakpoint = this.isNext ? allEnabledBreakpoints[0] : allEnabledBreakpoints[allEnabledBreakpoints.length - 1];
585
}
586
587
if (moveBreakpoint) {
588
return openBreakpointSource(moveBreakpoint, false, true, false, debugService, editorService);
589
}
590
}
591
}
592
}
593
594
class GoToNextBreakpointAction extends GoToBreakpointAction {
595
constructor() {
596
super(true, {
597
id: 'editor.debug.action.goToNextBreakpoint',
598
label: nls.localize2('goToNextBreakpoint', "Debug: Go to Next Breakpoint"),
599
precondition: CONTEXT_DEBUGGERS_AVAILABLE
600
});
601
}
602
}
603
604
class GoToPreviousBreakpointAction extends GoToBreakpointAction {
605
constructor() {
606
super(false, {
607
id: 'editor.debug.action.goToPreviousBreakpoint',
608
label: nls.localize2('goToPreviousBreakpoint', "Debug: Go to Previous Breakpoint"),
609
precondition: CONTEXT_DEBUGGERS_AVAILABLE
610
});
611
}
612
}
613
614
class CloseExceptionWidgetAction extends EditorAction {
615
616
constructor() {
617
super({
618
id: 'editor.debug.action.closeExceptionWidget',
619
label: nls.localize2('closeExceptionWidget', "Close Exception Widget"),
620
precondition: CONTEXT_EXCEPTION_WIDGET_VISIBLE,
621
kbOpts: {
622
primary: KeyCode.Escape,
623
weight: KeybindingWeight.EditorContrib
624
}
625
});
626
}
627
628
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
629
const contribution = editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID);
630
contribution?.closeExceptionWidget();
631
}
632
}
633
634
registerAction2(OpenDisassemblyViewAction);
635
registerAction2(ToggleDisassemblyViewSourceCodeAction);
636
registerAction2(ToggleBreakpointAction);
637
registerEditorAction(ConditionalBreakpointAction);
638
registerEditorAction(LogPointAction);
639
registerEditorAction(TriggerByBreakpointAction);
640
registerEditorAction(EditBreakpointAction);
641
registerEditorAction(RunToCursorAction);
642
registerEditorAction(StepIntoTargetsAction);
643
registerEditorAction(SelectionToReplAction);
644
registerEditorAction(SelectionToWatchExpressionsAction);
645
registerEditorAction(ShowDebugHoverAction);
646
registerEditorAction(GoToNextBreakpointAction);
647
registerEditorAction(GoToPreviousBreakpointAction);
648
registerEditorAction(CloseExceptionWidgetAction);
649
650