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