/*--------------------------------------------------------------------------------------------- * 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 { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { validateConstraint } from 'vs/base/common/types'; import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostEditors } from 'vs/workbench/api/node/extHostEditors'; import * as extHostTypes from 'vs/workbench/api/node/extHostTypes'; import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters'; import { cloneAndChange } from 'vs/base/common/objects'; import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape } from './extHost.protocol'; interface CommandHandler { callback: Function; thisArg: any; description: ICommandHandlerDescription; } export class ExtHostCommands extends ExtHostCommandsShape { private _commands: { [n: string]: CommandHandler } = Object.create(null); private _proxy: MainThreadCommandsShape; private _extHostEditors: ExtHostEditors; constructor( threadService: IThreadService, extHostEditors: ExtHostEditors ) { super(); this._extHostEditors = extHostEditors; this._proxy = threadService.get(MainContext.MainThreadCommands); } registerCommand(id: string, callback: (...args: any[]) => T | Thenable, thisArg?: any, description?: ICommandHandlerDescription): extHostTypes.Disposable { if (!id.trim().length) { throw new Error('invalid id'); } if (this._commands[id]) { throw new Error('command with id already exists'); } this._commands[id] = { callback, thisArg, description }; this._proxy.$registerCommand(id); return new extHostTypes.Disposable(() => { if (delete this._commands[id]) { this._proxy.$unregisterCommand(id); } }); } executeCommand(id: string, ...args: any[]): Thenable { if (this._commands[id]) { // we stay inside the extension host and support // to pass any kind of parameters around return this.$executeContributedCommand(id, ...args); } else { // automagically convert some argument types args = cloneAndChange(args, function (value) { if (value instanceof extHostTypes.Position) { return extHostTypeConverter.fromPosition(value); } if (value instanceof extHostTypes.Range) { return extHostTypeConverter.fromRange(value); } if (value instanceof extHostTypes.Location) { return extHostTypeConverter.location.from(value); } if (!Array.isArray(value)) { return value; } }); return this._proxy.$executeCommand(id, args); } } $executeContributedCommand(id: string, ...args: any[]): Thenable { let command = this._commands[id]; if (!command) { return TPromise.wrapError(`Contributed command '${id}' does not exist.`); } let {callback, thisArg, description} = command; if (description) { for (let i = 0; i < description.args.length; i++) { try { validateConstraint(args[i], description.args[i].constraint); } catch (err) { return TPromise.wrapError(`Running the contributed command:'${id}' failed. Illegal argument '${description.args[i].name}' - ${description.args[i].description}`); } } } try { let result = callback.apply(thisArg, args); return TPromise.as(result); } catch (err) { // console.log(err); // try { // console.log(toErrorMessage(err)); // } catch (err) { // // // } return TPromise.wrapError(`Running the contributed command:'${id}' failed.`); } } getCommands(filterUnderscoreCommands: boolean = false): Thenable { return this._proxy.$getCommands().then(result => { if (filterUnderscoreCommands) { result = result.filter(command => command[0] !== '_'); } return result; }); } $getContributedCommandHandlerDescriptions(): TPromise<{ [id: string]: string | ICommandHandlerDescription }> { const result: { [id: string]: string | ICommandHandlerDescription } = Object.create(null); for (let id in this._commands) { let {description} = this._commands[id]; if (description) { result[id] = description; } } return TPromise.as(result); } }