Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/browser/parts/panel/panelActions.ts
5318 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 './media/panelpart.css';
7
import { localize, localize2 } from '../../../../nls.js';
8
import { KeyMod, KeyCode } from '../../../../base/common/keyCodes.js';
9
import { MenuId, MenuRegistry, registerAction2, Action2, IAction2Options } from '../../../../platform/actions/common/actions.js';
10
import { Categories } from '../../../../platform/action/common/actionCommonCategories.js';
11
import { isHorizontal, IWorkbenchLayoutService, PanelAlignment, Parts, Position, positionToString } from '../../../services/layout/browser/layoutService.js';
12
import { IsAuxiliaryWindowContext, PanelAlignmentContext, PanelMaximizedContext, PanelPositionContext, PanelVisibleContext } from '../../../common/contextkeys.js';
13
import { ContextKeyExpr, ContextKeyExpression } from '../../../../platform/contextkey/common/contextkey.js';
14
import { Codicon } from '../../../../base/common/codicons.js';
15
import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js';
16
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
17
import { ViewContainerLocation, IViewDescriptorService } from '../../../common/views.js';
18
import { IViewsService } from '../../../services/views/common/viewsService.js';
19
import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.js';
20
import { INotificationService } from '../../../../platform/notification/common/notification.js';
21
import { ICommandActionTitle } from '../../../../platform/action/common/action.js';
22
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
23
import { SwitchCompositeViewAction } from '../compositeBarActions.js';
24
25
const maximizeIcon = registerIcon('panel-maximize', Codicon.screenFull, localize('maximizeIcon', 'Icon to maximize a panel.'));
26
const restoreIcon = registerIcon('panel-restore', Codicon.screenNormal, localize('restoreIcon', 'Icon to restore a panel.'));
27
const closeIcon = registerIcon('panel-close', Codicon.close, localize('closeIcon', 'Icon to close a panel.'));
28
const panelIcon = registerIcon('panel-layout-icon', Codicon.layoutPanel, localize('togglePanelOffIcon', 'Icon to toggle the panel off when it is on.'));
29
const panelOffIcon = registerIcon('panel-layout-icon-off', Codicon.layoutPanelOff, localize('togglePanelOnIcon', 'Icon to toggle the panel on when it is off.'));
30
31
export class TogglePanelAction extends Action2 {
32
33
static readonly ID = 'workbench.action.togglePanel';
34
static readonly LABEL = localize2('togglePanelVisibility', "Toggle Panel Visibility");
35
36
constructor() {
37
super({
38
id: TogglePanelAction.ID,
39
title: TogglePanelAction.LABEL,
40
toggled: {
41
condition: PanelVisibleContext,
42
title: localize('closePanel', 'Hide Panel'),
43
icon: closeIcon,
44
mnemonicTitle: localize({ key: 'miTogglePanelMnemonic', comment: ['&& denotes a mnemonic'] }, "&&Panel"),
45
},
46
icon: closeIcon,
47
f1: true,
48
category: Categories.View,
49
metadata: {
50
description: localize('openAndClosePanel', 'Open/Show and Close/Hide Panel'),
51
},
52
keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyJ, weight: KeybindingWeight.WorkbenchContrib },
53
menu: [
54
{
55
id: MenuId.MenubarAppearanceMenu,
56
group: '2_workbench_layout',
57
order: 5
58
}, {
59
id: MenuId.LayoutControlMenuSubmenu,
60
group: '0_workbench_layout',
61
order: 4
62
}
63
]
64
});
65
}
66
67
override async run(accessor: ServicesAccessor): Promise<void> {
68
const layoutService = accessor.get(IWorkbenchLayoutService);
69
layoutService.setPartHidden(layoutService.isVisible(Parts.PANEL_PART), Parts.PANEL_PART);
70
}
71
}
72
73
registerAction2(TogglePanelAction);
74
75
MenuRegistry.appendMenuItem(MenuId.PanelTitle, {
76
command: {
77
id: TogglePanelAction.ID,
78
title: localize('closePanel', 'Hide Panel'),
79
icon: closeIcon
80
},
81
group: 'navigation',
82
order: 2
83
});
84
85
registerAction2(class extends Action2 {
86
constructor() {
87
super({
88
id: 'workbench.action.closePanel',
89
title: localize2('closePanel', 'Hide Panel'),
90
category: Categories.View,
91
precondition: PanelVisibleContext,
92
f1: true,
93
});
94
}
95
run(accessor: ServicesAccessor) {
96
accessor.get(IWorkbenchLayoutService).setPartHidden(true, Parts.PANEL_PART);
97
}
98
});
99
100
registerAction2(class extends Action2 {
101
102
static readonly ID = 'workbench.action.focusPanel';
103
static readonly LABEL = localize('focusPanel', "Focus into Panel");
104
105
constructor() {
106
super({
107
id: 'workbench.action.focusPanel',
108
title: localize2('focusPanel', "Focus into Panel"),
109
category: Categories.View,
110
f1: true,
111
});
112
}
113
114
override async run(accessor: ServicesAccessor): Promise<void> {
115
const layoutService = accessor.get(IWorkbenchLayoutService);
116
const paneCompositeService = accessor.get(IPaneCompositePartService);
117
118
// Show panel
119
if (!layoutService.isVisible(Parts.PANEL_PART)) {
120
layoutService.setPartHidden(false, Parts.PANEL_PART);
121
}
122
123
// Focus into active panel
124
const panel = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);
125
panel?.focus();
126
}
127
});
128
129
const PositionPanelActionId = {
130
LEFT: 'workbench.action.positionPanelLeft',
131
RIGHT: 'workbench.action.positionPanelRight',
132
BOTTOM: 'workbench.action.positionPanelBottom',
133
TOP: 'workbench.action.positionPanelTop'
134
};
135
136
const AlignPanelActionId = {
137
LEFT: 'workbench.action.alignPanelLeft',
138
RIGHT: 'workbench.action.alignPanelRight',
139
CENTER: 'workbench.action.alignPanelCenter',
140
JUSTIFY: 'workbench.action.alignPanelJustify',
141
};
142
143
interface PanelActionConfig<T> {
144
id: string;
145
when: ContextKeyExpression;
146
title: ICommandActionTitle;
147
shortLabel: string;
148
value: T;
149
}
150
151
function createPanelActionConfig<T>(id: string, title: ICommandActionTitle, shortLabel: string, value: T, when: ContextKeyExpression): PanelActionConfig<T> {
152
return {
153
id,
154
title,
155
shortLabel,
156
value,
157
when,
158
};
159
}
160
161
function createPositionPanelActionConfig(id: string, title: ICommandActionTitle, shortLabel: string, position: Position): PanelActionConfig<Position> {
162
return createPanelActionConfig<Position>(id, title, shortLabel, position, PanelPositionContext.notEqualsTo(positionToString(position)));
163
}
164
165
function createAlignmentPanelActionConfig(id: string, title: ICommandActionTitle, shortLabel: string, alignment: PanelAlignment): PanelActionConfig<PanelAlignment> {
166
return createPanelActionConfig<PanelAlignment>(id, title, shortLabel, alignment, PanelAlignmentContext.notEqualsTo(alignment));
167
}
168
169
const PositionPanelActionConfigs: PanelActionConfig<Position>[] = [
170
createPositionPanelActionConfig(PositionPanelActionId.TOP, localize2('positionPanelTop', "Move Panel To Top"), localize('positionPanelTopShort', "Top"), Position.TOP),
171
createPositionPanelActionConfig(PositionPanelActionId.LEFT, localize2('positionPanelLeft', "Move Panel Left"), localize('positionPanelLeftShort', "Left"), Position.LEFT),
172
createPositionPanelActionConfig(PositionPanelActionId.RIGHT, localize2('positionPanelRight', "Move Panel Right"), localize('positionPanelRightShort', "Right"), Position.RIGHT),
173
createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, localize2('positionPanelBottom', "Move Panel To Bottom"), localize('positionPanelBottomShort', "Bottom"), Position.BOTTOM),
174
];
175
176
177
const AlignPanelActionConfigs: PanelActionConfig<PanelAlignment>[] = [
178
createAlignmentPanelActionConfig(AlignPanelActionId.LEFT, localize2('alignPanelLeft', "Set Panel Alignment to Left"), localize('alignPanelLeftShort', "Left"), 'left'),
179
createAlignmentPanelActionConfig(AlignPanelActionId.RIGHT, localize2('alignPanelRight', "Set Panel Alignment to Right"), localize('alignPanelRightShort', "Right"), 'right'),
180
createAlignmentPanelActionConfig(AlignPanelActionId.CENTER, localize2('alignPanelCenter', "Set Panel Alignment to Center"), localize('alignPanelCenterShort', "Center"), 'center'),
181
createAlignmentPanelActionConfig(AlignPanelActionId.JUSTIFY, localize2('alignPanelJustify', "Set Panel Alignment to Justify"), localize('alignPanelJustifyShort', "Justify"), 'justify'),
182
];
183
184
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
185
submenu: MenuId.PanelPositionMenu,
186
title: localize('positionPanel', "Panel Position"),
187
group: '3_workbench_layout_move',
188
order: 4
189
});
190
191
PositionPanelActionConfigs.forEach((positionPanelAction, index) => {
192
const { id, title, shortLabel, value, when } = positionPanelAction;
193
194
registerAction2(class extends Action2 {
195
constructor() {
196
super({
197
id,
198
title,
199
category: Categories.View,
200
f1: true
201
});
202
}
203
run(accessor: ServicesAccessor): void {
204
const layoutService = accessor.get(IWorkbenchLayoutService);
205
layoutService.setPanelPosition(value === undefined ? Position.BOTTOM : value);
206
}
207
});
208
209
MenuRegistry.appendMenuItem(MenuId.PanelPositionMenu, {
210
command: {
211
id,
212
title: shortLabel,
213
toggled: when.negate()
214
},
215
order: 5 + index
216
});
217
});
218
219
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
220
submenu: MenuId.PanelAlignmentMenu,
221
title: localize('alignPanel', "Align Panel"),
222
group: '3_workbench_layout_move',
223
order: 5
224
});
225
226
AlignPanelActionConfigs.forEach(alignPanelAction => {
227
const { id, title, shortLabel, value, when } = alignPanelAction;
228
registerAction2(class extends Action2 {
229
constructor() {
230
super({
231
id,
232
title,
233
category: Categories.View,
234
toggled: when.negate(),
235
f1: true
236
});
237
}
238
run(accessor: ServicesAccessor): void {
239
const layoutService = accessor.get(IWorkbenchLayoutService);
240
layoutService.setPanelAlignment(value === undefined ? 'center' : value);
241
}
242
});
243
244
MenuRegistry.appendMenuItem(MenuId.PanelAlignmentMenu, {
245
command: {
246
id,
247
title: shortLabel,
248
toggled: when.negate()
249
},
250
order: 5
251
});
252
});
253
254
registerAction2(class extends SwitchCompositeViewAction {
255
constructor() {
256
super({
257
id: 'workbench.action.previousPanelView',
258
title: localize2('previousPanelView', "Previous Panel View"),
259
category: Categories.View,
260
f1: true
261
}, ViewContainerLocation.Panel, -1);
262
}
263
});
264
265
registerAction2(class extends SwitchCompositeViewAction {
266
constructor() {
267
super({
268
id: 'workbench.action.nextPanelView',
269
title: localize2('nextPanelView', "Next Panel View"),
270
category: Categories.View,
271
f1: true
272
}, ViewContainerLocation.Panel, 1);
273
}
274
});
275
276
const panelMaximizationSupportedWhen = ContextKeyExpr.or(PanelAlignmentContext.isEqualTo('center'), ContextKeyExpr.and(PanelPositionContext.notEqualsTo('bottom'), PanelPositionContext.notEqualsTo('top')));
277
const ToggleMaximizedPanelActionId = 'workbench.action.toggleMaximizedPanel';
278
279
registerAction2(class extends Action2 {
280
constructor() {
281
super({
282
id: ToggleMaximizedPanelActionId,
283
title: localize2('toggleMaximizedPanel', 'Toggle Maximized Panel'),
284
tooltip: localize('maximizePanel', "Maximize Panel Size"),
285
category: Categories.View,
286
f1: true,
287
icon: maximizeIcon,
288
precondition: panelMaximizationSupportedWhen, // the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment
289
});
290
}
291
run(accessor: ServicesAccessor) {
292
const layoutService = accessor.get(IWorkbenchLayoutService);
293
const notificationService = accessor.get(INotificationService);
294
if (layoutService.getPanelAlignment() !== 'center' && isHorizontal(layoutService.getPanelPosition())) {
295
notificationService.warn(localize('panelMaxNotSupported', "Maximizing the panel is only supported when it is center aligned."));
296
return;
297
}
298
299
if (!layoutService.isVisible(Parts.PANEL_PART)) {
300
layoutService.setPartHidden(false, Parts.PANEL_PART);
301
// If the panel is not already maximized, maximize it
302
if (!layoutService.isPanelMaximized()) {
303
layoutService.toggleMaximizedPanel();
304
}
305
}
306
else {
307
layoutService.toggleMaximizedPanel();
308
}
309
}
310
});
311
312
MenuRegistry.appendMenuItem(MenuId.PanelTitle, {
313
command: {
314
id: ToggleMaximizedPanelActionId,
315
title: localize('maximizePanel', "Maximize Panel Size"),
316
icon: maximizeIcon
317
},
318
group: 'navigation',
319
order: 1,
320
when: ContextKeyExpr.and(panelMaximizationSupportedWhen, PanelMaximizedContext.negate())
321
});
322
323
MenuRegistry.appendMenuItem(MenuId.PanelTitle, {
324
command: {
325
id: ToggleMaximizedPanelActionId,
326
title: localize('minimizePanel', "Restore Panel Size"),
327
icon: restoreIcon
328
},
329
group: 'navigation',
330
order: 1,
331
when: ContextKeyExpr.and(panelMaximizationSupportedWhen, PanelMaximizedContext)
332
});
333
334
MenuRegistry.appendMenuItems([
335
{
336
id: MenuId.LayoutControlMenu,
337
item: {
338
group: '2_pane_toggles',
339
command: {
340
id: TogglePanelAction.ID,
341
title: localize('togglePanel', "Toggle Panel"),
342
icon: panelOffIcon,
343
toggled: { condition: PanelVisibleContext, icon: panelIcon }
344
},
345
when:
346
ContextKeyExpr.and(
347
IsAuxiliaryWindowContext.negate(),
348
ContextKeyExpr.or(
349
ContextKeyExpr.equals('config.workbench.layoutControl.type', 'toggles'),
350
ContextKeyExpr.equals('config.workbench.layoutControl.type', 'both')
351
)
352
),
353
order: 1
354
}
355
}
356
]);
357
358
class MoveViewsBetweenPanelsAction extends Action2 {
359
constructor(private readonly source: ViewContainerLocation, private readonly destination: ViewContainerLocation, desc: Readonly<IAction2Options>) {
360
super(desc);
361
}
362
363
run(accessor: ServicesAccessor, ...args: unknown[]): void {
364
const viewDescriptorService = accessor.get(IViewDescriptorService);
365
const layoutService = accessor.get(IWorkbenchLayoutService);
366
const viewsService = accessor.get(IViewsService);
367
368
const srcContainers = viewDescriptorService.getViewContainersByLocation(this.source);
369
const destContainers = viewDescriptorService.getViewContainersByLocation(this.destination);
370
371
if (srcContainers.length) {
372
const activeViewContainer = viewsService.getVisibleViewContainer(this.source);
373
374
srcContainers.forEach(viewContainer => viewDescriptorService.moveViewContainerToLocation(viewContainer, this.destination, undefined, this.desc.id));
375
layoutService.setPartHidden(false, this.destination === ViewContainerLocation.Panel ? Parts.PANEL_PART : Parts.AUXILIARYBAR_PART);
376
377
if (activeViewContainer && destContainers.length === 0) {
378
viewsService.openViewContainer(activeViewContainer.id, true);
379
}
380
}
381
}
382
}
383
384
// --- Move Panel Views To Secondary Side Bar
385
386
class MovePanelToSidePanelAction extends MoveViewsBetweenPanelsAction {
387
static readonly ID = 'workbench.action.movePanelToSidePanel';
388
constructor() {
389
super(ViewContainerLocation.Panel, ViewContainerLocation.AuxiliaryBar, {
390
id: MovePanelToSidePanelAction.ID,
391
title: localize2('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"),
392
category: Categories.View,
393
f1: false
394
});
395
}
396
}
397
398
export class MovePanelToSecondarySideBarAction extends MoveViewsBetweenPanelsAction {
399
static readonly ID = 'workbench.action.movePanelToSecondarySideBar';
400
constructor() {
401
super(ViewContainerLocation.Panel, ViewContainerLocation.AuxiliaryBar, {
402
id: MovePanelToSecondarySideBarAction.ID,
403
title: localize2('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"),
404
category: Categories.View,
405
f1: true
406
});
407
}
408
}
409
410
registerAction2(MovePanelToSidePanelAction);
411
registerAction2(MovePanelToSecondarySideBarAction);
412
413
// --- Move Secondary Side Bar Views To Panel
414
415
class MoveSidePanelToPanelAction extends MoveViewsBetweenPanelsAction {
416
static readonly ID = 'workbench.action.moveSidePanelToPanel';
417
418
constructor() {
419
super(ViewContainerLocation.AuxiliaryBar, ViewContainerLocation.Panel, {
420
id: MoveSidePanelToPanelAction.ID,
421
title: localize2('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"),
422
category: Categories.View,
423
f1: false
424
});
425
}
426
}
427
428
export class MoveSecondarySideBarToPanelAction extends MoveViewsBetweenPanelsAction {
429
static readonly ID = 'workbench.action.moveSecondarySideBarToPanel';
430
431
constructor() {
432
super(ViewContainerLocation.AuxiliaryBar, ViewContainerLocation.Panel, {
433
id: MoveSecondarySideBarToPanelAction.ID,
434
title: localize2('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"),
435
category: Categories.View,
436
f1: true
437
});
438
}
439
}
440
registerAction2(MoveSidePanelToPanelAction);
441
registerAction2(MoveSecondarySideBarToPanelAction);
442
443