actions.ts 6.5 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

B
Benjamin Pasero 已提交
7 8 9 10
import { Action } from 'vs/base/common/actions';
import { TPromise } from 'vs/base/common/winjs.base';
import { SyncDescriptor0, createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IConstructorSignature2, createDecorator } from 'vs/platform/instantiation/common/instantiation';
A
Renames  
Alex Dima 已提交
11
import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
B
imports  
Benjamin Pasero 已提交
12 13 14
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDisposable } from 'vs/base/common/lifecycle';
15
import Event from 'vs/base/common/event';
16

17 18 19 20 21
export interface ILocalizedString {
	value: string;
	original: string;
}

22
export interface ICommandAction {
23
	id: string;
24 25
	title: string | ILocalizedString;
	category?: string | ILocalizedString;
26
	iconClass?: string;
27 28
}

29
export interface IMenuItem {
30 31
	command: ICommandAction;
	alt?: ICommandAction;
A
Alex Dima 已提交
32
	when?: ContextKeyExpr;
33
	group?: 'navigation' | string;
34
	order?: number;
35 36
}

J
Joao Moreno 已提交
37 38 39 40 41 42 43
export class MenuId {

	static readonly EditorTitle = new MenuId('1');
	static readonly EditorTitleContext = new MenuId('2');
	static readonly EditorContext = new MenuId('3');
	static readonly ExplorerContext = new MenuId('4');
	static readonly ProblemsPanelContext = new MenuId('5');
44 45 46 47 48
	static readonly DebugVariablesContext = new MenuId('6');
	static readonly DebugWatchContext = new MenuId('7');
	static readonly DebugCallStackContext = new MenuId('8');
	static readonly DebugBreakpointsContext = new MenuId('9');
	static readonly DebugConsoleContext = new MenuId('10');
J
Joao Moreno 已提交
49 50 51
	static readonly SCMTitle = new MenuId('11');
	static readonly SCMResourceGroupContext = new MenuId('12');
	static readonly SCMResourceContext = new MenuId('13');
J
Joao Moreno 已提交
52
	static readonly CommandPalette = new MenuId('14');
J
Joao Moreno 已提交
53 54 55 56 57 58 59 60

	constructor(private _id: string) {

	}

	get id(): string {
		return this._id;
	}
61 62
}

63 64 65 66 67
export interface IMenuActionOptions {
	arg?: any;
	shouldForwardArgs?: boolean;
}

68 69
export interface IMenu extends IDisposable {
	onDidChange: Event<IMenu>;
70
	getActions(options?: IMenuActionOptions): [string, MenuItemAction[]][];
71 72
}

73 74 75 76
export const IMenuService = createDecorator<IMenuService>('menuService');

export interface IMenuService {

77
	_serviceBrand: any;
78

79
	createMenu(id: MenuId, scopedKeybindingService: IContextKeyService): IMenu;
80 81
}

82 83 84
export interface IMenuRegistry {
	addCommand(userCommand: ICommandAction): boolean;
	getCommand(id: string): ICommandAction;
85
	appendMenuItem(menu: MenuId, item: IMenuItem): IDisposable;
86 87 88 89 90
	getMenuItems(loc: MenuId): IMenuItem[];
}

export const MenuRegistry: IMenuRegistry = new class {

91
	private _commands: { [id: string]: ICommandAction } = Object.create(null);
92

93
	private _menuItems: { [loc: string]: IMenuItem[] } = Object.create(null);
94 95

	addCommand(command: ICommandAction): boolean {
96 97
		const old = this._commands[command.id];
		this._commands[command.id] = command;
98 99 100 101
		return old !== void 0;
	}

	getCommand(id: string): ICommandAction {
102
		return this._commands[id];
103 104
	}

105
	appendMenuItem({ id }: MenuId, item: IMenuItem): IDisposable {
106
		let array = this._menuItems[id];
107
		if (!array) {
108
			this._menuItems[id] = array = [item];
109
		} else {
110
			array.push(item);
111
		}
112 113 114 115 116 117 118 119
		return {
			dispose() {
				const idx = array.indexOf(item);
				if (idx >= 0) {
					array.splice(idx, 1);
				}
			}
		};
120
	}
121

122
	getMenuItems({ id }: MenuId): IMenuItem[] {
123
		const result = this._menuItems[id] || [];
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

		if (id === MenuId.CommandPalette.id) {
			// CommandPalette is special because it shows
			// all commands by default
			this._appendImplicitItems(result);
		}
		return result;
	}

	private _appendImplicitItems(result: IMenuItem[]) {
		const set = new Set<string>();
		for (const { command, alt } of result) {
			set.add(command.id);
			if (alt) {
				set.add(alt.id);
			}
		}
141
		for (let id in this._commands) {
142
			if (!set.has(id)) {
143
				result.push({ command: this._commands[id] });
144 145
			}
		}
146 147 148
	}
};

149
export class ExecuteCommandAction extends Action {
150 151

	constructor(
152 153 154
		id: string,
		label: string,
		@ICommandService private _commandService: ICommandService) {
155

156
		super(id, label);
157 158
	}

159 160
	run(...args: any[]): TPromise<any> {
		return this._commandService.executeCommand(this.id, ...args);
161 162 163
	}
}

164
export class MenuItemAction extends ExecuteCommandAction {
165

166
	private _options: IMenuActionOptions;
167 168 169

	readonly item: ICommandAction;
	readonly alt: MenuItemAction;
170 171

	constructor(
172 173
		item: ICommandAction,
		alt: ICommandAction,
174
		options: IMenuActionOptions,
175 176
		@ICommandService commandService: ICommandService
	) {
177
		typeof item.title === 'string' ? super(item.id, item.title, commandService) : super(item.id, item.title.value, commandService);
178 179
		this._cssClass = item.iconClass;
		this._enabled = true;
180
		this._options = options;
E
Erich Gamma 已提交
181

182
		this.item = item;
183
		this.alt = alt ? new MenuItemAction(alt, undefined, this._options, commandService) : undefined;
184
	}
E
Erich Gamma 已提交
185

186
	run(...args: any[]): TPromise<any> {
187 188 189 190
		let runArgs = [];

		if (this._options.arg) {
			runArgs = [...runArgs, this._options.arg];
191
		}
192 193 194 195 196 197

		if (this._options.shouldForwardArgs) {
			runArgs = [...runArgs, ...args];
		}

		return super.run(...runArgs);
198
	}
E
Erich Gamma 已提交
199 200 201 202
}

export class SyncActionDescriptor {

B
imports  
Benjamin Pasero 已提交
203
	private _descriptor: SyncDescriptor0<Action>;
E
Erich Gamma 已提交
204 205 206 207

	private _id: string;
	private _label: string;
	private _keybindings: IKeybindings;
A
Alex Dima 已提交
208
	private _keybindingContext: ContextKeyExpr;
E
Erich Gamma 已提交
209 210
	private _keybindingWeight: number;

B
imports  
Benjamin Pasero 已提交
211
	constructor(ctor: IConstructorSignature2<string, string, Action>,
A
Alex Dima 已提交
212
		id: string, label: string, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number
E
Erich Gamma 已提交
213 214 215 216 217 218
	) {
		this._id = id;
		this._label = label;
		this._keybindings = keybindings;
		this._keybindingContext = keybindingContext;
		this._keybindingWeight = keybindingWeight;
B
imports  
Benjamin Pasero 已提交
219
		this._descriptor = createSyncDescriptor(ctor, this._id, this._label);
E
Erich Gamma 已提交
220 221
	}

B
imports  
Benjamin Pasero 已提交
222
	public get syncDescriptor(): SyncDescriptor0<Action> {
E
Erich Gamma 已提交
223 224 225
		return this._descriptor;
	}

B
Benjamin Pasero 已提交
226
	public get id(): string {
E
Erich Gamma 已提交
227 228 229
		return this._id;
	}

B
Benjamin Pasero 已提交
230
	public get label(): string {
E
Erich Gamma 已提交
231 232 233
		return this._label;
	}

B
Benjamin Pasero 已提交
234
	public get keybindings(): IKeybindings {
E
Erich Gamma 已提交
235 236 237
		return this._keybindings;
	}

A
Alex Dima 已提交
238
	public get keybindingContext(): ContextKeyExpr {
E
Erich Gamma 已提交
239 240 241 242 243 244
		return this._keybindingContext;
	}

	public get keybindingWeight(): number {
		return this._keybindingWeight;
	}
245
}