Skip to content

Commit

Permalink
Added mappings from vscode commands to internal commands
Browse files Browse the repository at this point in the history
Signed-off-by: Josh Pinkney <joshpinkney@gmail.com>
  • Loading branch information
JPinkney committed Oct 28, 2019
1 parent 8f03fc0 commit 41df06c
Show file tree
Hide file tree
Showing 11 changed files with 528 additions and 69 deletions.
12 changes: 5 additions & 7 deletions packages/monaco/src/browser/monaco-command-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export interface MonacoEditorCommandHandler {
@injectable()
export class MonacoCommandRegistry {

/**
* @deprecated Do not register with monaco prefix
*/
public static MONACO_COMMAND_PREFIX = 'monaco.';

constructor(
Expand All @@ -36,19 +39,14 @@ export class MonacoCommandRegistry {
@inject(SelectionService) protected readonly selectionService: SelectionService
) { }

protected prefix(command: string): string {
return MonacoCommandRegistry.MONACO_COMMAND_PREFIX + command;
}

validate(command: string): string | undefined {
const monacoCommand = this.prefix(command);
return this.commands.commandIds.indexOf(monacoCommand) !== -1 ? monacoCommand : undefined;
return this.commands.commandIds.indexOf(command) !== -1 ? command : undefined;
}

registerCommand(command: Command, handler: MonacoEditorCommandHandler): void {
this.commands.registerCommand({
...command,
id: this.prefix(command.id)
id: command.id
}, this.newHandler(handler));
}

Expand Down
5 changes: 5 additions & 0 deletions packages/monaco/src/browser/monaco-command-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export class MonacoCommandService implements ICommandService {
this._onWillExecuteCommand.fire({ commandId });
return handler.execute(...args);
}
return this.executeMonacoCommand(commandId, ...args);
}

// tslint:disable-next-line:no-any
async executeMonacoCommand(commandId: any, ...args: any[]): Promise<any> {
if (this.delegate) {
return this.delegate.executeCommand(commandId, ...args);
}
Expand Down
8 changes: 7 additions & 1 deletion packages/monaco/src/browser/monaco-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { EditorCommands } from '@theia/editor/lib/browser';
import { MonacoEditor } from './monaco-editor';
import { MonacoCommandRegistry, MonacoEditorCommandHandler } from './monaco-command-registry';
import MenuRegistry = monaco.actions.MenuRegistry;
import { MonacoCommandService } from './monaco-command-service';

export type MonacoCommand = Command & { delegate?: string };
export namespace MonacoCommands {
Expand Down Expand Up @@ -271,7 +272,7 @@ export class MonacoEditorCommandHandlers implements CommandContribution {
}
protected newMonacoActionHandler(action: MonacoCommand): MonacoEditorCommandHandler {
const delegate = action.delegate;
return delegate ? this.newCommandHandler(delegate) : this.newActionHandler(action.id);
return delegate ? this.newDelegateHandler(delegate) : this.newActionHandler(action.id);
}

protected newKeyboardHandler(action: string): MonacoEditorCommandHandler {
Expand All @@ -290,5 +291,10 @@ export class MonacoEditorCommandHandlers implements CommandContribution {
isEnabled: editor => editor.isActionSupported(action)
};
}
protected newDelegateHandler(action: string): MonacoEditorCommandHandler {
return {
execute: (editor, ...args) => (editor.commandService as MonacoCommandService).executeMonacoCommand(action, ...args)
};
}

}
1 change: 1 addition & 0 deletions packages/plugin-ext/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
export * from './plugin-protocol';
export * from './plugin-api-rpc';
export * from './plugin-ext-api-contribution';
export * from './known-commands';
325 changes: 325 additions & 0 deletions packages/plugin-ext/src/common/known-commands.ts

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions packages/plugin-ext/src/common/objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// tslint:disable
// copied from https://github.com/microsoft/vscode/blob/1.37.0/src/vs/base/common/objects.ts
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { isUndefinedOrNull, isArray, isObject } from './types';

const _hasOwnProperty = Object.prototype.hasOwnProperty;

export function cloneAndChange(obj: any, changer: (orig: any) => any): any {
return _cloneAndChange(obj, changer, new Set());
}

function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set<any>): any {
if (isUndefinedOrNull(obj)) {
return obj;
}

const changed = changer(obj);
if (typeof changed !== 'undefined') {
return changed;
}

if (isArray(obj)) {
const r1: any[] = [];
for (const e of obj) {
r1.push(_cloneAndChange(e, changer, seen));
}
return r1;
}

if (isObject(obj)) {
if (seen.has(obj)) {
throw new Error('Cannot clone recursive data-structure');
}
seen.add(obj);
const r2 = {};
for (let i2 in obj) {
if (_hasOwnProperty.call(obj, i2)) {
(r2 as any)[i2] = _cloneAndChange(obj[i2], changer, seen);
}
}
seen.delete(obj);
return r2;
}

return obj;
}
41 changes: 41 additions & 0 deletions packages/plugin-ext/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
// copied from https://github.com/microsoft/vscode/blob/1.37.0/src/vs/base/common/types.ts
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

/**
* Returns `true` if the parameter has type "object" and not null, an array, a regexp, a date.
Expand Down Expand Up @@ -75,3 +80,39 @@ export function es5ClassCompat<T extends Function>(target: T): T {
return _ as unknown as T;
}
// tslint:enable:no-any
const _typeof = {
number: 'number',
string: 'string',
undefined: 'undefined',
object: 'object',
function: 'function'
};
// tslint:disable:no-any
/**
* @returns whether the provided parameter is a JavaScript Array or not.
*/
export function isArray(array: any): array is any[] {
if (Array.isArray) {
return Array.isArray(array);
}

if (array && typeof (array.length) === _typeof.number && array.constructor === Array) {
return true;
}

return false;
}

/**
* @returns whether the provided parameter is undefined.
*/
export function isUndefined(obj: any): obj is undefined {
return typeof (obj) === _typeof.undefined;
}

/**
* @returns whether the provided parameter is undefined or null.
*/
export function isUndefinedOrNull(obj: any): obj is undefined | null {
return isUndefined(obj) || obj === null;
}
7 changes: 5 additions & 2 deletions packages/plugin-ext/src/plugin/command-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import * as model from '../common/plugin-api-rpc-model';
import { CommandRegistryExt, PLUGIN_RPC_CONTEXT as Ext, CommandRegistryMain } from '../common/plugin-api-rpc';
import { RPCProtocol } from '../common/rpc-protocol';
import { Disposable } from './types-impl';
import { KnownCommands } from './type-converters';
import { DisposableCollection } from '@theia/core';
import { KnownCommands } from '../common/known-commands';

// tslint:disable-next-line:no-any
export type Handler = <T>(...args: any[]) => T | PromiseLike<T | undefined>;
Expand Down Expand Up @@ -102,9 +102,12 @@ export class CommandRegistryImpl implements CommandRegistryExt {
executeCommand<T>(id: string, ...args: any[]): PromiseLike<T | undefined> {
if (this.handlers.has(id)) {
return this.executeLocalCommand(id, ...args);
} else {
} else if (KnownCommands.mapped(id)) {
// Using the KnownCommand exclusions, convert the commands manually
return KnownCommands.map(id, args, (mappedId: string, mappedArgs: any[] | undefined) =>
this.proxy.$executeCommand(mappedId, ...mappedArgs));
} else {
return this.proxy.$executeCommand(id, args);
}
}
// tslint:enable:no-any
Expand Down
72 changes: 72 additions & 0 deletions packages/plugin-ext/src/plugin/known-commands.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/********************************************************************************
* Copyright (C) 2019 Red Hat, Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import * as assert from 'assert';
import { KnownCommands } from '../common/known-commands';
import URI from 'vscode-uri';
import { Position } from './types-impl';
import { fromPosition } from './type-converters';

describe('Known Command Conversions', () => {

it('Should convert position correctly', () => {

// given
const commandID = 'editor.action.rename';
const uri = URI.parse('file://my_theia_location');
const line = 61;
const character = 22;
const position = new Position(line, character); // vscode type position

assert.ok(KnownCommands.mapped(commandID));

// when
// tslint:disable-next-line:no-any
KnownCommands.map(commandID, [uri, position], (mappedID: string, mappedArgs: any[]) => {

// then
assert.strictEqual(commandID, mappedID);
assert.strictEqual(mappedArgs.length, 2);
assert.deepStrictEqual(uri, mappedArgs[0]);

const expectedMonacoPosition = fromPosition(position);
assert.deepStrictEqual(expectedMonacoPosition, mappedArgs[1]);
});

});

it('Does not convert non-monaco action commands', () => {

// given
const commandID = 'workbench.view.search';
const line = 61;
const character = 22;
const position = new Position(line, character); // vscode type position

assert.ok(KnownCommands.mapped(commandID));

// when
// tslint:disable-next-line:no-any
KnownCommands.map(commandID, [position], (mappedID: string, mappedArgs: any[]) => {
// then
assert.strictEqual(mappedID, 'search-in-workspace.open');
assert.strictEqual(mappedArgs.length, 1);
assert.deepStrictEqual(mappedArgs[0], position);
});

});

});
60 changes: 1 addition & 59 deletions packages/plugin-ext/src/plugin/type-converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import URI from 'vscode-uri';

const SIDE_GROUP = -2;
const ACTIVE_GROUP = -1;
import { SymbolInformation, Range as R, Position as P, SymbolKind as S, Location as L } from 'vscode-languageserver-types';
import { SymbolInformation, Range as R, Position as P, SymbolKind as S } from 'vscode-languageserver-types';
import { Item } from './quick-open';

export function toViewColumn(ep?: EditorPosition): theia.ViewColumn | undefined {
Expand Down Expand Up @@ -507,64 +507,6 @@ export namespace SignatureHelp {
}
}

export namespace KnownCommands {
// tslint:disable: no-any
const mappings: { [id: string]: [string, (args: any[] | undefined) => any[] | undefined] } = {};
mappings['editor.action.showReferences'] = ['textEditor.commands.showReferences', createConversionFunction(
(uri: URI) => uri.toString(),
fromPositionToP,
toArrayConversion(fromLocationToL))];

export function mapped(id: string): boolean {
return !!mappings[id];
}

export function map<T>(id: string, args: any[] | undefined, toDo: (mappedId: string, mappedArgs: any[] | undefined) => T): T {
if (mappings[id]) {
return toDo(mappings[id][0], mappings[id][1](args));
} else {
return toDo(id, args);
}
}

type conversionFunction = ((parameter: any) => any) | undefined;
function createConversionFunction(...conversions: conversionFunction[]): (args: any[] | undefined) => any[] | undefined {
return function (args: any[] | undefined): any[] | undefined {
if (!args) {
return args;
}
return args.map(function (arg: any, index: number): any {
if (index < conversions.length) {
const conversion = conversions[index];
if (conversion) {
return conversion(arg);
}
}
return arg;
});
};
}
// tslint:enable: no-any
function fromPositionToP(p: theia.Position): P {
return P.create(p.line, p.character);
}

function fromRangeToR(r: theia.Range): R {
return R.create(fromPositionToP(r.start), fromPositionToP(r.end));
}

function fromLocationToL(l: theia.Location): L {
return L.create(l.uri.toString(), fromRangeToR(l.range));
}

}

function toArrayConversion<T, U>(f: (a: T) => U): (a: T[]) => U[] {
return function (a: T[]): U[] {
return a.map(f);
};
}

// tslint:disable-next-line:no-any
export function fromWorkspaceEdit(value: theia.WorkspaceEdit, documents?: any): WorkspaceEditDto {
const result: WorkspaceEditDto = {
Expand Down
16 changes: 16 additions & 0 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
// copied from https://github.com/microsoft/vscode/blob/1.37.0/src/vs/workbench/api/common/extHostTypes.ts
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { UUID } from '@phosphor/coreutils/lib/uuid';
import { illegalArgument } from '../common/errors';
Expand Down Expand Up @@ -785,6 +790,17 @@ export class Location {
this.range = new Range(rangeOrPosition, rangeOrPosition);
}
}

static isLocation(thing: {}): thing is theia.Location {
if (thing instanceof Location) {
return true;
}
if (!thing) {
return false;
}
return Range.isRange((<Location>thing).range)
&& URI.isUri((<Location>thing).uri);
}
}

export enum DiagnosticTag {
Expand Down

0 comments on commit 41df06c

Please sign in to comment.