commands.ts 3.1 KB
Newer Older
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import {TPromise} from 'vs/base/common/winjs.base';
import {TypeConstraint, validateConstraints} from 'vs/base/common/types';
9
import {ServicesAccessor, createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
10

11
export const ICommandService = createDecorator<ICommandService>('commandService');
12 13

export interface ICommandService {
14
	serviceId: ServiceIdentifier<any>;
15 16
	executeCommand<T>(commandId: string, ...args: any[]): TPromise<T>;
	executeCommand(commandId: string, ...args: any[]): TPromise<any>;
17
	isKnownCommand(commandId: string): boolean;
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
}

export interface ICommandsMap {
	[id: string]: ICommand;
}

export interface ICommandHandler {
	(accessor: ServicesAccessor, ...args: any[]): void;
}

export interface ICommand {
	handler: ICommandHandler;
	description?: ICommandHandlerDescription;
}

export interface ICommandHandlerDescription {
	description: string;
	args: { name: string; description?: string; constraint?: TypeConstraint; }[];
	returns?: string;
}

export interface ICommandRegistry {
	registerCommand(id: string, command: ICommandHandler): void;
	registerCommand(id: string, command: ICommand): void;
	getCommand(id: string): ICommand;
	getCommands(): ICommandsMap;
}

function isCommand(thing: any): thing is ICommand {
	return typeof thing === 'object'
		&& typeof (<ICommand>thing).handler === 'function'
		&& (!(<ICommand>thing).description || typeof (<ICommand>thing).description === 'object');
}

export const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry {

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

	registerCommand(id: string, commandOrDesc: ICommandHandler | ICommand): void {
		// if (this._commands[id] !== void 0) {
		// 	throw new Error(`command already exists: '${id}'`);
		// }
		if (!commandOrDesc) {
			throw new Error(`invalid command`);
		}

		if (!isCommand(commandOrDesc)) {
			// simple handler
			this._commands[id] = { handler: commandOrDesc };

		} else {
			const {handler, description} = commandOrDesc;
			if (description) {
				// add argument validation if rich command metadata is provided
				const constraints: TypeConstraint[] = [];
				for (let arg of description.args) {
					constraints.push(arg.constraint);
				}
				this._commands[id] = {
					description,
					handler(accessor, ...args: any[]) {
						validateConstraints(args, constraints);
						return handler(accessor, ...args);
					}
				};
			} else {
				// add as simple handler
				this._commands[id] = { handler };
			}
		}
	}

	getCommand(id: string): ICommand {
		return this._commands[id];
	}

	getCommands(): ICommandsMap {
		return this._commands;
	}
};
98 99 100 101 102

export const NullCommandService: ICommandService = {
	serviceId: undefined,
	executeCommand() {
		return TPromise.as(undefined);
103 104 105
	},
	isKnownCommand() {
		return false;
106 107
	}
};