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' ;
77import { IDisposable , dispose } from 'vs/base/common/lifecycle' ;
88import { ContextKeyExpr , IContextKeyService } from 'vs/platform/contextkey/common/contextkey' ;
99import { 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
1414export 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
0 commit comments