Skip to content

Commit ed4e8e4

Browse files
committed
debt - let menu listen to (new) menu registry change events instead of listing to the extension host being ready. that simplifies this a lot and help with show menu sooner
1 parent e556d24 commit ed4e8e4

7 files changed

Lines changed: 75 additions & 75 deletions

File tree

src/vs/editor/standalone/browser/simpleServices.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import { TextEdit, WorkspaceEdit, isResourceTextEdit } from 'vs/editor/common/mo
2525
import { IModelService } from 'vs/editor/common/services/modelService';
2626
import { ITextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
2727
import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
28-
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
29-
import { Menu } from 'vs/platform/actions/common/menu';
3028
import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands';
3129
import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration';
3230
import { Configuration, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
@@ -479,21 +477,6 @@ export class SimpleResourcePropertiesService implements ITextResourcePropertiesS
479477
}
480478
}
481479

482-
export class SimpleMenuService implements IMenuService {
483-
484-
_serviceBrand: any;
485-
486-
private readonly _commandService: ICommandService;
487-
488-
constructor(commandService: ICommandService) {
489-
this._commandService = commandService;
490-
}
491-
492-
public createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
493-
return new Menu(id, Promise.resolve(true), this._commandService, contextKeyService);
494-
}
495-
}
496-
497480
export class StandaloneTelemetryService implements ITelemetryService {
498481
_serviceBrand: void;
499482

src/vs/editor/standalone/browser/standaloneServices.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
1313
import { IModelService } from 'vs/editor/common/services/modelService';
1414
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
1515
import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
16-
import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleMenuService, SimpleNotificationService, SimpleProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService } from 'vs/editor/standalone/browser/simpleServices';
16+
import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService } from 'vs/editor/standalone/browser/simpleServices';
1717
import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl';
1818
import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl';
1919
import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';
@@ -41,6 +41,7 @@ import { IStorageService, NullStorageService } from 'vs/platform/storage/common/
4141
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
4242
import { IThemeService } from 'vs/platform/theme/common/themeService';
4343
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
44+
import { MenuService } from 'vs/platform/actions/common/menuService';
4445

4546
export interface IEditorOverrideServices {
4647
[index: string]: any;
@@ -189,7 +190,7 @@ export class DynamicStandaloneServices extends Disposable {
189190

190191
ensure(IContextMenuService, () => this._register(new ContextMenuService(domElement, telemetryService, notificationService, contextViewService, keybindingService, themeService)));
191192

192-
ensure(IMenuService, () => new SimpleMenuService(commandService));
193+
ensure(IMenuService, () => new MenuService(commandService));
193194

194195
ensure(IBulkEditService, () => new SimpleBulkEditService(StaticServices.modelService.get(IModelService)));
195196
}

src/vs/platform/actions/common/actions.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'
1010
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1111
import { ICommandService } from 'vs/platform/commands/common/commands';
1212
import { IDisposable } from 'vs/base/common/lifecycle';
13-
import { Event } from 'vs/base/common/event';
13+
import { Event, Emitter } from 'vs/base/common/event';
1414
import { URI, UriComponents } from 'vs/base/common/uri';
1515

1616
export interface ILocalizedString {
@@ -128,6 +128,7 @@ export interface IMenuRegistry {
128128
getCommands(): ICommandsMap;
129129
appendMenuItem(menu: MenuId, item: IMenuItem | ISubmenuItem): IDisposable;
130130
getMenuItems(loc: MenuId): (IMenuItem | ISubmenuItem)[];
131+
onDidChangeMenu: Event<MenuId>;
131132
}
132133

133134
export interface ICommandsMap {
@@ -136,9 +137,11 @@ export interface ICommandsMap {
136137

137138
export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {
138139

139-
private _commands: { [id: string]: ICommandAction } = Object.create(null);
140+
private readonly _commands: { [id: string]: ICommandAction } = Object.create(null);
141+
private readonly _menuItems: { [loc: string]: (IMenuItem | ISubmenuItem)[] } = Object.create(null);
142+
private readonly _onDidChangeMenu = new Emitter<MenuId>();
140143

141-
private _menuItems: { [loc: string]: (IMenuItem | ISubmenuItem)[] } = Object.create(null);
144+
readonly onDidChangeMenu: Event<MenuId> = this._onDidChangeMenu.event;
142145

143146
addCommand(command: ICommandAction): boolean {
144147
const old = this._commands[command.id];
@@ -158,18 +161,20 @@ export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {
158161
return result;
159162
}
160163

161-
appendMenuItem({ id }: MenuId, item: IMenuItem | ISubmenuItem): IDisposable {
162-
let array = this._menuItems[id];
164+
appendMenuItem(id: MenuId, item: IMenuItem | ISubmenuItem): IDisposable {
165+
let array = this._menuItems[id.id];
163166
if (!array) {
164-
this._menuItems[id] = array = [item];
167+
this._menuItems[id.id] = array = [item];
165168
} else {
166169
array.push(item);
167170
}
171+
this._onDidChangeMenu.fire(id);
168172
return {
169-
dispose() {
173+
dispose: () => {
170174
const idx = array.indexOf(item);
171175
if (idx >= 0) {
172176
array.splice(idx, 1);
177+
this._onDidChangeMenu.fire(id);
173178
}
174179
}
175180
};

src/vs/platform/actions/common/menu.ts

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Event, Emitter } from 'vs/base/common/event';
6+
import { Event, Emitter, filterEvent, debounceEvent } from 'vs/base/common/event';
77
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
88
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
99
import { MenuId, MenuRegistry, MenuItemAction, IMenu, IMenuItem, IMenuActionOptions, ISubmenuItem, SubmenuItemAction, isIMenuItem } from 'vs/platform/actions/common/actions';
@@ -13,59 +13,74 @@ type MenuItemGroup = [string, (IMenuItem | ISubmenuItem)[]];
1313

1414
export class Menu implements IMenu {
1515

16-
private _menuGroups: MenuItemGroup[] = [];
17-
private _disposables: IDisposable[] = [];
18-
private _onDidChange = new Emitter<IMenu>();
16+
private readonly _onDidChange = new Emitter<IMenu>();
17+
private readonly _disposables: IDisposable[] = [];
18+
19+
private _menuGroups: MenuItemGroup[];
20+
private _contextKeys: Set<string>;
1921

2022
constructor(
21-
id: MenuId,
22-
startupSignal: Thenable<boolean>,
23+
private readonly _id: MenuId,
2324
@ICommandService private readonly _commandService: ICommandService,
2425
@IContextKeyService private readonly _contextKeyService: IContextKeyService
2526
) {
26-
startupSignal.then(_ => {
27-
const menuItems = MenuRegistry.getMenuItems(id);
28-
const keysFilter = new Set<string>();
29-
30-
let group: MenuItemGroup | undefined;
31-
menuItems.sort(Menu._compareMenuItems);
32-
33-
for (let item of menuItems) {
34-
// group by groupId
35-
const groupName = item.group;
36-
if (!group || group[0] !== groupName) {
37-
group = [groupName || '', []];
38-
this._menuGroups.push(group);
39-
}
40-
group![1].push(item);
27+
this._build();
28+
29+
// rebuild this menu whenever the menu registry reports an
30+
// event for this MenuId
31+
debounceEvent(
32+
filterEvent(MenuRegistry.onDidChangeMenu, menuId => menuId === this._id),
33+
() => { },
34+
100
35+
)(this._build, this, this._disposables);
36+
37+
// when context keys change we need to change if the menu also
38+
// has changed
39+
this._contextKeyService.onDidChangeContext(event => {
40+
if (event.affectsSome(this._contextKeys)) {
41+
this._onDidChange.fire();
42+
}
43+
}, this, this._disposables);
44+
}
4145

42-
// keep keys for eventing
43-
Menu._fillInKbExprKeys(item.when, keysFilter);
46+
private _build(): void {
4447

45-
// keep precondition keys for event if applicable
46-
if (isIMenuItem(item) && item.command.precondition) {
47-
Menu._fillInKbExprKeys(item.command.precondition, keysFilter);
48-
}
48+
// reset
49+
this._menuGroups = [];
50+
this._contextKeys = new Set();
4951

50-
// keep toggled keys for event if applicable
51-
if (isIMenuItem(item) && item.command.toggled) {
52-
Menu._fillInKbExprKeys(item.command.toggled, keysFilter);
53-
}
52+
const menuItems = MenuRegistry.getMenuItems(this._id);
53+
54+
let group: MenuItemGroup | undefined;
55+
menuItems.sort(Menu._compareMenuItems);
56+
57+
for (let item of menuItems) {
58+
// group by groupId
59+
const groupName = item.group;
60+
if (!group || group[0] !== groupName) {
61+
group = [groupName || '', []];
62+
this._menuGroups.push(group);
5463
}
64+
group![1].push(item);
5565

56-
// subscribe to context changes
57-
this._disposables.push(this._contextKeyService.onDidChangeContext(event => {
58-
if (event.affectsSome(keysFilter)) {
59-
this._onDidChange.fire();
60-
}
61-
}));
66+
// keep keys for eventing
67+
Menu._fillInKbExprKeys(item.when, this._contextKeys);
68+
69+
// keep precondition keys for event if applicable
70+
if (isIMenuItem(item) && item.command.precondition) {
71+
Menu._fillInKbExprKeys(item.command.precondition, this._contextKeys);
72+
}
6273

63-
this._onDidChange.fire(this);
64-
});
74+
// keep toggled keys for event if applicable
75+
if (isIMenuItem(item) && item.command.toggled) {
76+
Menu._fillInKbExprKeys(item.command.toggled, this._contextKeys);
77+
}
78+
}
79+
this._onDidChange.fire(this);
6580
}
6681

6782
dispose() {
68-
this._disposables = dispose(this._disposables);
83+
dispose(this._disposables);
6984
this._onDidChange.dispose();
7085
}
7186

src/vs/workbench/services/actions/common/menuService.ts renamed to src/vs/platform/actions/common/menuService.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@
66
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
77
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
88
import { Menu } from 'vs/platform/actions/common/menu';
9-
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
109
import { ICommandService } from 'vs/platform/commands/common/commands';
1110

1211
export class MenuService implements IMenuService {
1312

1413
_serviceBrand: any;
1514

1615
constructor(
17-
@IExtensionService private readonly _extensionService: IExtensionService,
1816
@ICommandService private readonly _commandService: ICommandService
1917
) {
2018
//
2119
}
2220

2321
createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
24-
return new Menu(id, this._extensionService.whenInstalledExtensionsRegistered(), this._commandService, contextKeyService);
22+
return new Menu(id, this._commandService, contextKeyService);
2523
}
2624
}

src/vs/workbench/services/actions/test/common/menuService.test.ts renamed to src/vs/platform/actions/test/common/menuService.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5+
56
import * as assert from 'assert';
67
import { MenuRegistry, MenuId, isIMenuItem } from 'vs/platform/actions/common/actions';
7-
import { MenuService } from 'vs/workbench/services/actions/common/menuService';
8+
import { MenuService } from 'vs/platform/actions/common/menuService';
89
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
910
import { NullCommandService } from 'vs/platform/commands/common/commands';
1011
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
11-
import { TestExtensionService } from 'vs/workbench/test/workbenchTestServices';
1212

1313
// --- service instances
1414

15-
const extensionService = new TestExtensionService();
16-
1715
const contextKeyService = new class extends MockContextKeyService {
1816
contextMatchesRules() {
1917
return true;
@@ -29,7 +27,7 @@ suite('MenuService', function () {
2927
let testMenuId: MenuId;
3028

3129
setup(function () {
32-
menuService = new MenuService(extensionService, NullCommandService);
30+
menuService = new MenuService(NullCommandService);
3331
testMenuId = new MenuId();
3432
disposables = [];
3533
});

src/vs/workbench/electron-browser/workbench.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecyc
7878
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration, IPath, MenuBarVisibility } from 'vs/platform/windows/common/windows';
7979
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
8080
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
81-
import { MenuService } from 'vs/workbench/services/actions/common/menuService';
81+
import { MenuService } from 'vs/platform/actions/common/menuService';
8282
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
8383
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
8484
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';

0 commit comments

Comments
 (0)