Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts
5253 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 { isActiveDocument, reset } from '../../../../base/browser/dom.js';
7
import { BaseActionViewItem, IBaseActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js';
8
import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
9
import { IHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate.js';
10
import { renderIcon } from '../../../../base/browser/ui/iconLabel/iconLabels.js';
11
import { IAction, SubmenuAction } from '../../../../base/common/actions.js';
12
import { Codicon } from '../../../../base/common/codicons.js';
13
import { Emitter, Event } from '../../../../base/common/event.js';
14
import { DisposableStore } from '../../../../base/common/lifecycle.js';
15
import { localize } from '../../../../nls.js';
16
import { createActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
17
import { HiddenItemStrategy, MenuWorkbenchToolBar, WorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js';
18
import { MenuId, MenuRegistry, SubmenuItemAction } from '../../../../platform/actions/common/actions.js';
19
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
20
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
21
import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js';
22
import { WindowTitle } from './windowTitle.js';
23
import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js';
24
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
25
26
export class CommandCenterControl {
27
28
private readonly _disposables = new DisposableStore();
29
30
private readonly _onDidChangeVisibility = this._disposables.add(new Emitter<void>());
31
readonly onDidChangeVisibility: Event<void> = this._onDidChangeVisibility.event;
32
33
readonly element: HTMLElement = document.createElement('div');
34
35
constructor(
36
windowTitle: WindowTitle,
37
hoverDelegate: IHoverDelegate,
38
@IInstantiationService instantiationService: IInstantiationService,
39
@IQuickInputService quickInputService: IQuickInputService,
40
) {
41
this.element.classList.add('command-center');
42
43
const titleToolbar = instantiationService.createInstance(MenuWorkbenchToolBar, this.element, MenuId.CommandCenter, {
44
contextMenu: MenuId.TitleBarContext,
45
hiddenItemStrategy: HiddenItemStrategy.NoHide,
46
toolbarOptions: {
47
primaryGroup: () => true,
48
},
49
telemetrySource: 'commandCenter',
50
actionViewItemProvider: (action, options) => {
51
if (action instanceof SubmenuItemAction && action.item.submenu === MenuId.CommandCenterCenter) {
52
return instantiationService.createInstance(CommandCenterCenterViewItem, action, windowTitle, { ...options, hoverDelegate });
53
} else {
54
return createActionViewItem(instantiationService, action, { ...options, hoverDelegate });
55
}
56
}
57
});
58
59
this._disposables.add(Event.filter(quickInputService.onShow, () => isActiveDocument(this.element), this._disposables)(this._setVisibility.bind(this, false)));
60
this._disposables.add(quickInputService.onHide(this._setVisibility.bind(this, true)));
61
this._disposables.add(titleToolbar);
62
}
63
64
private _setVisibility(show: boolean): void {
65
this.element.classList.toggle('hide', !show);
66
this._onDidChangeVisibility.fire();
67
}
68
69
dispose(): void {
70
this._disposables.dispose();
71
}
72
}
73
74
75
class CommandCenterCenterViewItem extends BaseActionViewItem {
76
77
private static readonly _quickOpenCommandId = 'workbench.action.quickOpenWithModes';
78
79
private readonly _hoverDelegate: IHoverDelegate;
80
81
constructor(
82
private readonly _submenu: SubmenuItemAction,
83
private readonly _windowTitle: WindowTitle,
84
options: IBaseActionViewItemOptions,
85
@IHoverService private readonly _hoverService: IHoverService,
86
@IKeybindingService private _keybindingService: IKeybindingService,
87
@IInstantiationService private _instaService: IInstantiationService,
88
@IEditorGroupsService private _editorGroupService: IEditorGroupsService,
89
) {
90
super(undefined, _submenu.actions.find(action => action.id === 'workbench.action.quickOpenWithModes') ?? _submenu.actions[0], options);
91
this._hoverDelegate = options.hoverDelegate ?? getDefaultHoverDelegate('mouse');
92
}
93
94
override render(container: HTMLElement): void {
95
super.render(container);
96
container.classList.add('command-center-center');
97
container.classList.toggle('multiple', (this._submenu.actions.length > 1));
98
99
const hover = this._store.add(this._hoverService.setupManagedHover(this._hoverDelegate, container, this.getTooltip()));
100
101
// update label & tooltip when window title changes
102
this._store.add(this._windowTitle.onDidChange(() => {
103
hover.update(this.getTooltip());
104
}));
105
106
const groups: (readonly IAction[])[] = [];
107
for (const action of this._submenu.actions) {
108
if (action instanceof SubmenuAction) {
109
groups.push(action.actions);
110
} else {
111
groups.push([action]);
112
}
113
}
114
115
116
for (let i = 0; i < groups.length; i++) {
117
const group = groups[i];
118
119
// nested toolbar
120
const toolbar = this._instaService.createInstance(WorkbenchToolBar, container, {
121
hiddenItemStrategy: HiddenItemStrategy.NoHide,
122
telemetrySource: 'commandCenterCenter',
123
actionViewItemProvider: (action, options) => {
124
options = {
125
...options,
126
hoverDelegate: this._hoverDelegate,
127
};
128
129
if (action.id !== CommandCenterCenterViewItem._quickOpenCommandId) {
130
return createActionViewItem(this._instaService, action, options);
131
}
132
133
const that = this;
134
135
return this._instaService.createInstance(class CommandCenterQuickPickItem extends BaseActionViewItem {
136
137
constructor() {
138
super(undefined, action, options);
139
}
140
141
override render(container: HTMLElement): void {
142
super.render(container);
143
container.classList.toggle('command-center-quick-pick');
144
container.role = 'button';
145
container.setAttribute('aria-description', this.getTooltip());
146
const action = this.action;
147
148
// icon (search)
149
const searchIcon = document.createElement('span');
150
searchIcon.ariaHidden = 'true';
151
searchIcon.className = action.class ?? '';
152
searchIcon.classList.add('search-icon');
153
154
// label: just workspace name and optional decorations
155
const label = this._getLabel();
156
const labelElement = document.createElement('span');
157
labelElement.classList.add('search-label');
158
labelElement.textContent = label;
159
reset(container, searchIcon, labelElement);
160
161
const hover = this._store.add(that._hoverService.setupManagedHover(that._hoverDelegate, container, this.getTooltip()));
162
163
// update label & tooltip when window title changes
164
this._store.add(that._windowTitle.onDidChange(() => {
165
hover.update(this.getTooltip());
166
labelElement.textContent = this._getLabel();
167
}));
168
169
// update label & tooltip when tabs visibility changes
170
this._store.add(that._editorGroupService.onDidChangeEditorPartOptions(({ newPartOptions, oldPartOptions }) => {
171
if (newPartOptions.showTabs !== oldPartOptions.showTabs) {
172
hover.update(this.getTooltip());
173
labelElement.textContent = this._getLabel();
174
}
175
}));
176
}
177
178
protected override getTooltip() {
179
return that.getTooltip();
180
}
181
182
private _getLabel(): string {
183
const { prefix, suffix } = that._windowTitle.getTitleDecorations();
184
let label = that._windowTitle.workspaceName;
185
if (that._windowTitle.isCustomTitleFormat()) {
186
label = that._windowTitle.getWindowTitle();
187
} else if (that._editorGroupService.partOptions.showTabs === 'none') {
188
label = that._windowTitle.fileName ?? label;
189
}
190
if (!label) {
191
label = localize('label.dfl', "Search");
192
}
193
if (prefix) {
194
label = localize('label1', "{0} {1}", prefix, label);
195
}
196
if (suffix) {
197
label = localize('label2', "{0} {1}", label, suffix);
198
}
199
200
return label.replaceAll(/\r\n|\r|\n/g, '\u23CE');
201
}
202
});
203
}
204
});
205
toolbar.setActions(group);
206
this._store.add(toolbar);
207
208
209
// spacer
210
if (i < groups.length - 1) {
211
const icon = renderIcon(Codicon.circleSmallFilled);
212
icon.style.padding = '0 8px';
213
icon.style.height = '100%';
214
icon.style.opacity = '0.5';
215
container.appendChild(icon);
216
}
217
}
218
}
219
220
protected override getTooltip() {
221
222
// tooltip: full windowTitle
223
const kb = this._keybindingService.lookupKeybinding(this.action.id)?.getLabel();
224
const title = kb
225
? localize('title', "Search {0} ({1}) \u2014 {2}", this._windowTitle.workspaceName, kb, this._windowTitle.value)
226
: localize('title2', "Search {0} \u2014 {1}", this._windowTitle.workspaceName, this._windowTitle.value);
227
228
return title;
229
}
230
}
231
232
MenuRegistry.appendMenuItem(MenuId.CommandCenter, {
233
submenu: MenuId.CommandCenterCenter,
234
title: localize('title3', "Command Center"),
235
icon: Codicon.shield,
236
order: 101,
237
});
238
239