Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/debug/browser/debugToolBar.ts
3296 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 * as dom from '../../../../base/browser/dom.js';
7
import { StandardMouseEvent } from '../../../../base/browser/mouseEvent.js';
8
import { PixelRatio } from '../../../../base/browser/pixelRatio.js';
9
import { ActionBar, ActionsOrientation, IActionViewItem } from '../../../../base/browser/ui/actionbar/actionbar.js';
10
import { IBaseActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js';
11
import { CodeWindow, mainWindow } from '../../../../base/browser/window.js';
12
import { Action, IAction, IRunEvent, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from '../../../../base/common/actions.js';
13
import * as arrays from '../../../../base/common/arrays.js';
14
import { RunOnceScheduler } from '../../../../base/common/async.js';
15
import { Codicon } from '../../../../base/common/codicons.js';
16
import * as errors from '../../../../base/common/errors.js';
17
import { DisposableStore, markAsSingleton, MutableDisposable } from '../../../../base/common/lifecycle.js';
18
import { Platform, platform } from '../../../../base/common/platform.js';
19
import { ThemeIcon } from '../../../../base/common/themables.js';
20
import { URI } from '../../../../base/common/uri.js';
21
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
22
import { localize } from '../../../../nls.js';
23
import { ICommandAction, ICommandActionTitle } from '../../../../platform/action/common/action.js';
24
import { DropdownWithPrimaryActionViewItem, IDropdownWithPrimaryActionViewItemOptions } from '../../../../platform/actions/browser/dropdownWithPrimaryActionViewItem.js';
25
import { createActionViewItem, getFlatActionBarActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
26
import { IMenu, IMenuService, MenuId, MenuItemAction, MenuRegistry } from '../../../../platform/actions/common/actions.js';
27
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
28
import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
29
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
30
import { INotificationService } from '../../../../platform/notification/common/notification.js';
31
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
32
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
33
import { widgetBorder, widgetShadow } from '../../../../platform/theme/common/colorRegistry.js';
34
import { IThemeService, Themable } from '../../../../platform/theme/common/themeService.js';
35
import { getTitleBarStyle, TitlebarStyle } from '../../../../platform/window/common/window.js';
36
import { IWorkbenchContribution } from '../../../common/contributions.js';
37
import { EditorTabsMode, IWorkbenchLayoutService, LayoutSettings, Parts } from '../../../services/layout/browser/layoutService.js';
38
import { CONTEXT_DEBUG_STATE, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_IN_DEBUG_MODE, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, IDebugConfiguration, IDebugService, State, VIEWLET_ID } from '../common/debug.js';
39
import { FocusSessionActionViewItem } from './debugActionViewItems.js';
40
import { debugToolBarBackground, debugToolBarBorder } from './debugColors.js';
41
import { CONTINUE_ID, CONTINUE_LABEL, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, DISCONNECT_ID, DISCONNECT_LABEL, FOCUS_SESSION_ID, FOCUS_SESSION_LABEL, PAUSE_ID, PAUSE_LABEL, RESTART_LABEL, RESTART_SESSION_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, STEP_INTO_ID, STEP_INTO_LABEL, STEP_OUT_ID, STEP_OUT_LABEL, STEP_OVER_ID, STEP_OVER_LABEL, STOP_ID, STOP_LABEL } from './debugCommands.js';
42
import * as icons from './debugIcons.js';
43
import './media/debugToolBar.css';
44
45
const DEBUG_TOOLBAR_POSITION_KEY = 'debug.actionswidgetposition';
46
const DEBUG_TOOLBAR_Y_KEY = 'debug.actionswidgety';
47
48
export class DebugToolBar extends Themable implements IWorkbenchContribution {
49
50
private $el: HTMLElement;
51
private dragArea: HTMLElement;
52
private actionBar: ActionBar;
53
private activeActions: IAction[];
54
private updateScheduler: RunOnceScheduler;
55
private debugToolBarMenu: IMenu;
56
57
private isVisible = false;
58
private isBuilt = false;
59
60
private readonly stopActionViewItemDisposables = this._register(new DisposableStore());
61
/** coordinate of the debug toolbar per aux window */
62
private readonly auxWindowCoordinates = new WeakMap<CodeWindow, { x: number; y: number | undefined }>();
63
64
private readonly trackPixelRatioListener = this._register(new MutableDisposable());
65
66
constructor(
67
@INotificationService private readonly notificationService: INotificationService,
68
@ITelemetryService private readonly telemetryService: ITelemetryService,
69
@IDebugService private readonly debugService: IDebugService,
70
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
71
@IStorageService private readonly storageService: IStorageService,
72
@IConfigurationService private readonly configurationService: IConfigurationService,
73
@IThemeService themeService: IThemeService,
74
@IInstantiationService private readonly instantiationService: IInstantiationService,
75
@IMenuService menuService: IMenuService,
76
@IContextKeyService contextKeyService: IContextKeyService,
77
) {
78
super(themeService);
79
80
this.$el = dom.$('div.debug-toolbar');
81
82
// Note: changes to this setting require a restart, so no need to listen to it.
83
const controlsOnTitlebar = getTitleBarStyle(this.configurationService) === TitlebarStyle.CUSTOM;
84
85
// Do not allow the widget to overflow or underflow window controls.
86
// Use CSS calculations to avoid having to force layout with `.clientWidth`
87
const controlsOnLeft = controlsOnTitlebar && platform === Platform.Mac;
88
const controlsOnRight = controlsOnTitlebar && (platform === Platform.Windows || platform === Platform.Linux);
89
this.$el.style.transform = `translate(
90
min(
91
max(${controlsOnLeft ? '60px' : '0px'}, calc(-50% + (100vw * var(--x-position)))),
92
calc(100vw - 100% - ${controlsOnRight ? '100px' : '0px'})
93
),
94
var(--y-position)
95
)`;
96
97
this.dragArea = dom.append(this.$el, dom.$('div.drag-area' + ThemeIcon.asCSSSelector(icons.debugGripper)));
98
99
const actionBarContainer = dom.append(this.$el, dom.$('div.action-bar-container'));
100
this.debugToolBarMenu = menuService.createMenu(MenuId.DebugToolBar, contextKeyService);
101
this._register(this.debugToolBarMenu);
102
103
this.activeActions = [];
104
this.actionBar = this._register(new ActionBar(actionBarContainer, {
105
orientation: ActionsOrientation.HORIZONTAL,
106
actionViewItemProvider: (action: IAction, options: IBaseActionViewItemOptions) => {
107
if (action.id === FOCUS_SESSION_ID) {
108
return this.instantiationService.createInstance(FocusSessionActionViewItem, action, undefined);
109
} else if (action.id === STOP_ID || action.id === DISCONNECT_ID) {
110
this.stopActionViewItemDisposables.clear();
111
const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, this.stopActionViewItemDisposables, accessor, { hoverDelegate: options.hoverDelegate }));
112
if (item) {
113
return item;
114
}
115
}
116
117
return createActionViewItem(this.instantiationService, action, options);
118
}
119
}));
120
121
this.updateScheduler = this._register(new RunOnceScheduler(() => {
122
const state = this.debugService.state;
123
const toolBarLocation = this.configurationService.getValue<IDebugConfiguration>('debug').toolBarLocation;
124
if (
125
state === State.Inactive ||
126
toolBarLocation !== 'floating' ||
127
this.debugService.getModel().getSessions().every(s => s.suppressDebugToolbar) ||
128
(state === State.Initializing && this.debugService.initializingOptions?.suppressDebugToolbar)
129
) {
130
return this.hide();
131
}
132
133
const actions = getFlatActionBarActions(this.debugToolBarMenu.getActions({ shouldForwardArgs: true }));
134
if (!arrays.equals(actions, this.activeActions, (first, second) => first.id === second.id && first.enabled === second.enabled)) {
135
this.actionBar.clear();
136
this.actionBar.push(actions, { icon: true, label: false });
137
this.activeActions = actions;
138
}
139
140
this.show();
141
}, 20));
142
143
this.updateStyles();
144
this.registerListeners();
145
this.hide();
146
}
147
148
private registerListeners(): void {
149
this._register(this.debugService.onDidChangeState(() => this.updateScheduler.schedule()));
150
this._register(this.configurationService.onDidChangeConfiguration(e => {
151
if (e.affectsConfiguration('debug.toolBarLocation')) {
152
this.updateScheduler.schedule();
153
}
154
if (e.affectsConfiguration(LayoutSettings.EDITOR_TABS_MODE) || e.affectsConfiguration(LayoutSettings.COMMAND_CENTER)) {
155
this._yRange = undefined;
156
this.setCoordinates();
157
}
158
}));
159
this._register(this.debugToolBarMenu.onDidChange(() => this.updateScheduler.schedule()));
160
this._register(this.actionBar.actionRunner.onDidRun((e: IRunEvent) => {
161
// check for error
162
if (e.error && !errors.isCancellationError(e.error)) {
163
this.notificationService.warn(e.error);
164
}
165
166
// log in telemetry
167
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: e.action.id, from: 'debugActionsWidget' });
168
}));
169
170
this._register(dom.addDisposableGenericMouseUpListener(this.dragArea, (event: MouseEvent) => {
171
const mouseClickEvent = new StandardMouseEvent(dom.getWindow(this.dragArea), event);
172
if (mouseClickEvent.detail === 2) {
173
// double click on debug bar centers it again #8250
174
this.setCoordinates(0.5, this.yDefault);
175
this.storePosition();
176
}
177
}));
178
179
this._register(dom.addDisposableGenericMouseDownListener(this.dragArea, (e: MouseEvent) => {
180
this.dragArea.classList.add('dragged');
181
const activeWindow = dom.getWindow(this.layoutService.activeContainer);
182
const originEvent = new StandardMouseEvent(activeWindow, e);
183
184
const originX = this.computeCurrentXPercent();
185
const originY = this.getCurrentYPosition();
186
187
const mouseMoveListener = dom.addDisposableGenericMouseMoveListener(activeWindow, (e: MouseEvent) => {
188
const mouseMoveEvent = new StandardMouseEvent(activeWindow, e);
189
// Prevent default to stop editor selecting text #8524
190
mouseMoveEvent.preventDefault();
191
this.setCoordinates(
192
originX + (mouseMoveEvent.posx - originEvent.posx) / activeWindow.innerWidth,
193
originY + mouseMoveEvent.posy - originEvent.posy,
194
);
195
});
196
197
const mouseUpListener = dom.addDisposableGenericMouseUpListener(activeWindow, (e: MouseEvent) => {
198
this.storePosition();
199
this.dragArea.classList.remove('dragged');
200
201
mouseMoveListener.dispose();
202
mouseUpListener.dispose();
203
});
204
}));
205
206
this._register(this.layoutService.onDidChangePartVisibility(() => this.setCoordinates()));
207
208
this._register(this.layoutService.onDidChangeActiveContainer(async () => {
209
this._yRange = undefined;
210
211
// note: we intentionally don't keep the activeContainer before the
212
// `await` clause to avoid any races due to quickly switching windows.
213
await this.layoutService.whenContainerStylesLoaded(dom.getWindow(this.layoutService.activeContainer));
214
if (this.isBuilt) {
215
this.doShowInActiveContainer();
216
this.setCoordinates();
217
}
218
}));
219
}
220
221
/**
222
* Computes the x percent position at which the toolbar is currently displayed.
223
*/
224
private computeCurrentXPercent(): number {
225
const { left, width } = this.$el.getBoundingClientRect();
226
return (left + width / 2) / dom.getWindow(this.$el).innerWidth;
227
}
228
229
/**
230
* Gets the x position set in the style of the toolbar. This may not be its
231
* actual position on screen depending on toolbar locations.
232
*/
233
private getCurrentXPercent(): number {
234
return Number(this.$el.style.getPropertyValue('--x-position'));
235
}
236
237
/** Gets the y position set in the style of the toolbar */
238
private getCurrentYPosition(): number {
239
return parseInt(this.$el.style.getPropertyValue('--y-position'));
240
}
241
242
private storePosition(): void {
243
const activeWindow = dom.getWindow(this.layoutService.activeContainer);
244
const isMainWindow = this.layoutService.activeContainer === this.layoutService.mainContainer;
245
246
const x = this.getCurrentXPercent();
247
const y = this.getCurrentYPosition();
248
if (isMainWindow) {
249
this.storageService.store(DEBUG_TOOLBAR_POSITION_KEY, x, StorageScope.PROFILE, StorageTarget.MACHINE);
250
this.storageService.store(DEBUG_TOOLBAR_Y_KEY, y, StorageScope.PROFILE, StorageTarget.MACHINE);
251
} else {
252
this.auxWindowCoordinates.set(activeWindow, { x, y });
253
}
254
}
255
256
override updateStyles(): void {
257
super.updateStyles();
258
259
if (this.$el) {
260
this.$el.style.backgroundColor = this.getColor(debugToolBarBackground) || '';
261
262
const widgetShadowColor = this.getColor(widgetShadow);
263
this.$el.style.boxShadow = widgetShadowColor ? `0 0 8px 2px ${widgetShadowColor}` : '';
264
265
const contrastBorderColor = this.getColor(widgetBorder);
266
const borderColor = this.getColor(debugToolBarBorder);
267
268
if (contrastBorderColor) {
269
this.$el.style.border = `1px solid ${contrastBorderColor}`;
270
} else {
271
this.$el.style.border = borderColor ? `solid ${borderColor}` : 'none';
272
this.$el.style.border = '1px 0';
273
}
274
}
275
}
276
277
/** Gets the stored X position of the middle of the toolbar based on the current window width */
278
private getStoredXPosition() {
279
const currentWindow = dom.getWindow(this.layoutService.activeContainer);
280
const isMainWindow = currentWindow === mainWindow;
281
const storedPercentage = isMainWindow
282
? Number(this.storageService.get(DEBUG_TOOLBAR_POSITION_KEY, StorageScope.PROFILE))
283
: this.auxWindowCoordinates.get(currentWindow)?.x;
284
return storedPercentage !== undefined && !isNaN(storedPercentage) ? storedPercentage : 0.5;
285
}
286
287
private getStoredYPosition() {
288
const currentWindow = dom.getWindow(this.layoutService.activeContainer);
289
const isMainWindow = currentWindow === mainWindow;
290
const storedY = isMainWindow
291
? this.storageService.getNumber(DEBUG_TOOLBAR_Y_KEY, StorageScope.PROFILE)
292
: this.auxWindowCoordinates.get(currentWindow)?.y;
293
return storedY ?? this.yDefault;
294
}
295
296
private setCoordinates(x?: number, y?: number): void {
297
if (!this.isVisible) {
298
return;
299
}
300
301
x ??= this.getStoredXPosition();
302
y ??= this.getStoredYPosition();
303
304
const [yMin, yMax] = this.yRange;
305
y = Math.max(yMin, Math.min(y, yMax));
306
this.$el.style.setProperty('--x-position', `${x}`);
307
this.$el.style.setProperty('--y-position', `${y}px`);
308
}
309
310
private get yDefault() {
311
return this.layoutService.mainContainerOffset.top;
312
}
313
314
private _yRange: [number, number] | undefined;
315
private get yRange(): [number, number] {
316
if (!this._yRange) {
317
const isTitleBarVisible = this.layoutService.isVisible(Parts.TITLEBAR_PART, dom.getWindow(this.layoutService.activeContainer));
318
const yMin = isTitleBarVisible ? 0 : this.layoutService.mainContainerOffset.top;
319
let yMax = 0;
320
321
if (isTitleBarVisible) {
322
if (this.configurationService.getValue(LayoutSettings.COMMAND_CENTER) === true) {
323
yMax += 35;
324
} else {
325
yMax += 28;
326
}
327
}
328
329
if (this.configurationService.getValue(LayoutSettings.EDITOR_TABS_MODE) !== EditorTabsMode.NONE) {
330
yMax += 35;
331
}
332
this._yRange = [yMin, yMax];
333
}
334
return this._yRange;
335
}
336
337
private show(): void {
338
if (this.isVisible) {
339
this.setCoordinates();
340
return;
341
}
342
if (!this.isBuilt) {
343
this.isBuilt = true;
344
this.doShowInActiveContainer();
345
}
346
347
this.isVisible = true;
348
dom.show(this.$el);
349
this.setCoordinates();
350
}
351
352
private doShowInActiveContainer(): void {
353
this.layoutService.activeContainer.appendChild(this.$el);
354
this.trackPixelRatioListener.value = PixelRatio.getInstance(dom.getWindow(this.$el)).onDidChange(
355
() => this.setCoordinates()
356
);
357
}
358
359
private hide(): void {
360
this.isVisible = false;
361
dom.hide(this.$el);
362
}
363
364
override dispose(): void {
365
super.dispose();
366
367
this.$el?.remove();
368
}
369
}
370
371
export function createDisconnectMenuItemAction(action: MenuItemAction, disposables: DisposableStore, accessor: ServicesAccessor, options: IDropdownWithPrimaryActionViewItemOptions): IActionViewItem | undefined {
372
const menuService = accessor.get(IMenuService);
373
const contextKeyService = accessor.get(IContextKeyService);
374
const instantiationService = accessor.get(IInstantiationService);
375
376
const menu = menuService.getMenuActions(MenuId.DebugToolBarStop, contextKeyService, { shouldForwardArgs: true });
377
const secondary = getFlatActionBarActions(menu);
378
379
if (!secondary.length) {
380
return undefined;
381
}
382
383
const dropdownAction = disposables.add(new Action('notebook.moreRunActions', localize('notebook.moreRunActionsLabel', "More..."), 'codicon-chevron-down', true));
384
const item = instantiationService.createInstance(DropdownWithPrimaryActionViewItem,
385
action as MenuItemAction,
386
dropdownAction,
387
secondary,
388
'debug-stop-actions',
389
options);
390
return item;
391
}
392
393
// Debug toolbar
394
395
const debugViewTitleItems = new DisposableStore();
396
const registerDebugToolBarItem = (id: string, title: string | ICommandActionTitle, order: number, icon?: { light?: URI; dark?: URI } | ThemeIcon, when?: ContextKeyExpression, precondition?: ContextKeyExpression, alt?: ICommandAction) => {
397
MenuRegistry.appendMenuItem(MenuId.DebugToolBar, {
398
group: 'navigation',
399
when,
400
order,
401
command: {
402
id,
403
title,
404
icon,
405
precondition
406
},
407
alt
408
});
409
410
// Register actions in debug viewlet when toolbar is docked
411
debugViewTitleItems.add(MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, {
412
group: 'navigation',
413
when: ContextKeyExpr.and(when, ContextKeyExpr.equals('viewContainer', VIEWLET_ID), CONTEXT_DEBUG_STATE.notEqualsTo('inactive'), ContextKeyExpr.equals('config.debug.toolBarLocation', 'docked')),
414
order,
415
command: {
416
id,
417
title,
418
icon,
419
precondition
420
}
421
}));
422
};
423
424
markAsSingleton(MenuRegistry.onDidChangeMenu(e => {
425
// In case the debug toolbar is docked we need to make sure that the docked toolbar has the up to date commands registered #115945
426
if (e.has(MenuId.DebugToolBar)) {
427
debugViewTitleItems.clear();
428
const items = MenuRegistry.getMenuItems(MenuId.DebugToolBar);
429
for (const i of items) {
430
debugViewTitleItems.add(MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, {
431
...i,
432
when: ContextKeyExpr.and(i.when, ContextKeyExpr.equals('viewContainer', VIEWLET_ID), CONTEXT_DEBUG_STATE.notEqualsTo('inactive'), ContextKeyExpr.equals('config.debug.toolBarLocation', 'docked'))
433
}));
434
}
435
}
436
}));
437
438
439
const CONTEXT_TOOLBAR_COMMAND_CENTER = ContextKeyExpr.equals('config.debug.toolBarLocation', 'commandCenter');
440
441
MenuRegistry.appendMenuItem(MenuId.CommandCenterCenter, {
442
submenu: MenuId.DebugToolBar,
443
title: 'Debug',
444
icon: Codicon.debug,
445
order: 1,
446
when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_TOOLBAR_COMMAND_CENTER)
447
});
448
449
registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, 10, icons.debugContinue, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
450
registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, 10, icons.debugPause, CONTEXT_DEBUG_STATE.notEqualsTo('stopped'), ContextKeyExpr.and(CONTEXT_DEBUG_STATE.isEqualTo('running'), CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG.toNegated()));
451
registerDebugToolBarItem(STOP_ID, STOP_LABEL, 70, icons.debugStop, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated(), undefined, { id: DISCONNECT_ID, title: DISCONNECT_LABEL, icon: icons.debugDisconnect, precondition: ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated(), CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED), });
452
registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, 70, icons.debugDisconnect, CONTEXT_FOCUSED_SESSION_IS_ATTACH, undefined, { id: STOP_ID, title: STOP_LABEL, icon: icons.debugStop, precondition: ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED), });
453
registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, 20, icons.debugStepOver, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
454
registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, 30, icons.debugStepInto, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
455
registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, 40, icons.debugStepOut, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
456
registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, 60, icons.debugRestart);
457
registerDebugToolBarItem(STEP_BACK_ID, localize('stepBackDebug', "Step Back"), 50, icons.debugStepBack, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
458
registerDebugToolBarItem(REVERSE_CONTINUE_ID, localize('reverseContinue', "Reverse"), 55, icons.debugReverseContinue, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
459
registerDebugToolBarItem(FOCUS_SESSION_ID, FOCUS_SESSION_LABEL, 100, Codicon.listTree, ContextKeyExpr.and(CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_TOOLBAR_COMMAND_CENTER.negate()));
460
461
MenuRegistry.appendMenuItem(MenuId.DebugToolBarStop, {
462
group: 'navigation',
463
when: ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated(), CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED),
464
order: 0,
465
command: {
466
id: DISCONNECT_ID,
467
title: DISCONNECT_LABEL,
468
icon: icons.debugDisconnect
469
}
470
});
471
472
MenuRegistry.appendMenuItem(MenuId.DebugToolBarStop, {
473
group: 'navigation',
474
when: ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED),
475
order: 0,
476
command: {
477
id: STOP_ID,
478
title: STOP_LABEL,
479
icon: icons.debugStop
480
}
481
});
482
483
MenuRegistry.appendMenuItem(MenuId.DebugToolBarStop, {
484
group: 'navigation',
485
when: ContextKeyExpr.or(
486
ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated(), CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED),
487
ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED),
488
),
489
order: 0,
490
command: {
491
id: DISCONNECT_AND_SUSPEND_ID,
492
title: DISCONNECT_AND_SUSPEND_LABEL,
493
icon: icons.debugDisconnect
494
}
495
});
496
497