diff --git a/packages/plugin-ext/src/common/index.ts b/packages/plugin-ext/src/common/index.ts index e433357f0f950..9c3af19caa10a 100644 --- a/packages/plugin-ext/src/common/index.ts +++ b/packages/plugin-ext/src/common/index.ts @@ -20,3 +20,4 @@ export * from '../plugin/plugin-context'; export * from '../api/plugin-api'; export * from '../main/node/temp-dir-util'; export * from './plugin-ext-api-contribution'; +export * from './known-commands'; diff --git a/packages/plugin-ext/src/common/known-commands.ts b/packages/plugin-ext/src/common/known-commands.ts new file mode 100644 index 0000000000000..75374c38ebec7 --- /dev/null +++ b/packages/plugin-ext/src/common/known-commands.ts @@ -0,0 +1,233 @@ +/******************************************************************************** + * 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 { Range as R, Position as P, Location as L } from 'vscode-languageserver-types'; +import URI from 'vscode-uri'; +import * as theia from '@theia/plugin'; + +// Here is a mapping of VSCode commands to monaco commands with their conversions +export namespace KnownCommands { + + /** + * Commands that you want to apply custom conversions to rather than pass through the automatic args converter. + * Would be useful in the case where theia provides some command and you need to provide custom conversions + */ + // tslint:disable-next-line:no-any + export const exclusions: { [id: string]: [string, (args: any[] | undefined) => any[] | undefined] } = {}; + exclusions['editor.action.showReferences'] = ['textEditor.commands.showReferences', createConversionFunction( + (uri: URI) => uri.toString(), + fromPositionToP, + toArrayConversion(fromLocationToL))]; + + /** + * Commands that have a name in theia that is different from their name in vscode + */ + export const mappings: { [id: string]: string } = {}; + + /** + * Mapping of all editor.action commands to their monaco counterpart. + * executeCommand inside of the plugin command registry will automatically convert + * incoming arguments from vscode api types to monaco types + */ + mappings['editor.action.select.all'] = 'monaco.editor.action.select.all'; + mappings['editor.action.moveCarretLeftAction'] = 'monaco.editor.action.moveCarretLeftAction'; + mappings['editor.action.moveCarretRightAction'] = 'monaco.editor.action.moveCarretRightAction'; + mappings['editor.action.transposeLetters'] = 'monaco.editor.action.transposeLetters'; + mappings['editor.action.clipboardCopyWithSyntaxHighlightingAction'] = 'monaco.editor.action.clipboardCopyWithSyntaxHighlightingAction'; + mappings['editor.action.commentLine'] = 'monaco.editor.action.commentLine'; + mappings['editor.action.addCommentLine'] = 'monaco.editor.action.addCommentLine'; + mappings['editor.action.removeCommentLine'] = 'monaco.editor.action.removeCommentLine'; + mappings['editor.action.blockComment'] = 'monaco.editor.action.blockComment'; + mappings['editor.action.showContextMenu'] = 'monaco.editor.action.showContextMenu'; + mappings['cursorUndo'] = 'monaco.cursorUndo'; + mappings['editor.unfold'] = 'monaco.editor.unfold'; + mappings['editor.unfoldRecursively'] = 'monaco.editor.unfoldRecursively'; + mappings['editor.fold'] = 'monaco.editor.fold'; + mappings['editor.foldRecursively'] = 'monaco.editor.foldRecursively'; + mappings['editor.foldAll'] = 'monaco.editor.foldAll'; + mappings['editor.unfoldAll'] = 'monaco.editor.unfoldAll'; + mappings['editor.foldAllBlockComments'] = 'monaco.editor.foldAllBlockComments'; + mappings['editor.foldAllMarkerRegions'] = 'monaco.editor.foldAllMarkerRegions'; + mappings['editor.unfoldAllMarkerRegions'] = 'monaco.editor.unfoldAllMarkerRegions'; + mappings['editor.foldLevel1'] = 'monaco.editor.foldLevel1'; + mappings['editor.foldLevel2'] = 'monaco.editor.foldLevel2'; + mappings['editor.foldLevel3'] = 'monaco.editor.foldLevel3'; + mappings['editor.foldLevel4'] = 'monaco.editor.foldLevel4'; + mappings['editor.foldLevel5'] = 'monaco.editor.foldLevel5'; + mappings['editor.foldLevel6'] = 'monaco.editor.foldLevel6'; + mappings['editor.foldLevel7'] = 'monaco.editor.foldLevel7'; + mappings['editor.action.fontZoomIn'] = 'monaco.editor.action.fontZoomIn'; + mappings['editor.action.fontZoomOut'] = 'monaco.editor.action.fontZoomOut'; + mappings['editor.action.fontZoomReset'] = 'monaco.editor.action.fontZoomReset'; + mappings['editor.action.formatDocument'] = 'monaco.editor.action.formatDocument'; + mappings['editor.action.formatSelection'] = 'monaco.editor.action.formatSelection'; + mappings['editor.action.copyLinesUpAction'] = 'monaco.editor.action.copyLinesUpAction'; + mappings['editor.action.copyLinesDownAction'] = 'monaco.editor.action.copyLinesDownAction'; + mappings['editor.action.moveLinesUpAction'] = 'monaco.editor.action.moveLinesUpAction'; + mappings['editor.action.moveLinesDownAction'] = 'monaco.editor.action.moveLinesDownAction'; + mappings['editor.action.sortLinesAscending'] = 'monaco.editor.action.sortLinesAscending'; + mappings['editor.action.sortLinesDescending'] = 'monaco.editor.action.sortLinesDescending'; + mappings['editor.action.trimTrailingWhitespace'] = 'monaco.editor.action.trimTrailingWhitespace'; + mappings['editor.action.deleteLines'] = 'monaco.editor.action.deleteLines'; + mappings['editor.action.indentLines'] = 'monaco.editor.action.indentLines'; + mappings['editor.action.outdentLines'] = 'monaco.editor.action.outdentLines'; + mappings['editor.action.insertLineBefore'] = 'monaco.editor.action.insertLineBefore'; + mappings['editor.action.insertLineAfter'] = 'monaco.editor.action.insertLineAfter'; + mappings['deleteAllLeft'] = 'monaco.deleteAllLeft'; + mappings['deleteAllRight'] = 'monaco.deleteAllRight'; + mappings['editor.action.joinLines'] = 'monaco.editor.action.joinLines'; + mappings['editor.action.transpose'] = 'monaco.editor.action.transpose'; + mappings['editor.action.transformToUppercase'] = 'monaco.editor.action.transformToUppercase'; + mappings['editor.action.transformToLowercase'] = 'monaco.editor.action.transformToLowercase'; + mappings['editor.action.smartSelect.grow'] = 'monaco.editor.action.smartSelect.grow'; + mappings['editor.action.smartSelect.shrink'] = 'monaco.editor.action.smartSelect.shrink'; + mappings['editor.action.toggleHighContrast'] = 'monaco.editor.action.toggleHighContrast'; + mappings['editor.action.gotoLine'] = 'monaco.editor.action.gotoLine'; + mappings['editor.action.quickOutline'] = 'monaco.editor.action.quickOutline'; + mappings['editor.action.inPlaceReplace.up'] = 'monaco.editor.action.inPlaceReplace.up'; + mappings['editor.action.inPlaceReplace.down'] = 'monaco.editor.action.inPlaceReplace.down'; + mappings['editor.action.diffReview.next'] = 'monaco.editor.action.diffReview.next'; + mappings['editor.action.diffReview.prev'] = 'monaco.editor.action.diffReview.prev'; + mappings['editor.action.selectToBracket'] = 'monaco.editor.action.selectToBracket'; + mappings['editor.action.jumpToBracket'] = 'monaco.editor.action.jumpToBracket'; + mappings['editor.action.marker.next'] = 'monaco.editor.action.marker.next'; + mappings['editor.action.marker.prev'] = 'monaco.editor.action.marker.prev'; + mappings['editor.action.marker.nextInFiles'] = 'monaco.editor.action.marker.nextInFiles'; + mappings['editor.action.marker.prevInFiles'] = 'monaco.editor.action.marker.prevInFiles'; + mappings['editor.action.showHover'] = 'monaco.editor.action.showHover'; + mappings['editor.action.openLink'] = 'monaco.editor.action.openLink'; + mappings['editor.action.quickFix'] = 'monaco.editor.action.quickFix'; + mappings['editor.action.refactor'] = 'monaco.editor.action.refactor'; + mappings['editor.action.sourceAction'] = 'monaco.editor.action.sourceAction'; + mappings['editor.action.organizeImports'] = 'monaco.editor.action.organizeImports'; + mappings['editor.action.triggerParameterHints'] = 'monaco.editor.action.triggerParameterHints'; + mappings['editor.action.rename'] = 'monaco.editor.action.rename'; + mappings['editor.action.triggerSuggest'] = 'monaco.editor.action.triggerSuggest'; + mappings['editor.action.wordHighlight.next'] = 'monaco.editor.action.wordHighlight.next'; + mappings['editor.action.wordHighlight.prev'] = 'monaco.editor.action.wordHighlight.prev'; + mappings['editor.action.showAccessibilityHelp'] = 'monaco.editor.action.showAccessibilityHelp'; + mappings['editor.action.inspectTokens'] = 'monaco.editor.action.inspectTokens'; + mappings['actions.findWithSelection'] = 'monaco.actions.findWithSelection'; + mappings['editor.action.nextMatchFindAction'] = 'monaco.editor.action.nextMatchFindAction'; + mappings['editor.action.previousMatchFindAction'] = 'monaco.editor.action.previousMatchFindAction'; + mappings['editor.action.nextSelectionMatchFindAction'] = 'monaco.editor.action.nextSelectionMatchFindAction'; + mappings['editor.action.previousSelectionMatchFindAction'] = 'monaco.editor.action.previousSelectionMatchFindAction'; + mappings['editor.action.insertCursorAbove'] = 'monaco.editor.action.insertCursorAbove'; + mappings['editor.action.insertCursorBelow'] = 'monaco.editor.action.insertCursorBelow'; + mappings['editor.action.insertCursorAtEndOfEachLineSelected'] = 'monaco.editor.action.insertCursorAtEndOfEachLineSelected'; + mappings['editor.action.addSelectionToNextFindMatch'] = 'monaco.editor.action.addSelectionToNextFindMatch'; + mappings['editor.action.addSelectionToPreviousFindMatch'] = 'monaco.editor.action.addSelectionToPreviousFindMatch'; + mappings['editor.action.moveSelectionToNextFindMatch'] = 'monaco.editor.action.moveSelectionToNextFindMatch'; + mappings['editor.action.moveSelectionToPreviousFindMatch'] = 'monaco.editor.action.moveSelectionToPreviousFindMatch'; + mappings['editor.action.selectHighlights'] = 'monaco.editor.action.selectHighlights'; + mappings['editor.action.changeAll'] = 'monaco.editor.action.changeAll'; + mappings['editor.action.goToDeclaration'] = 'monaco.editor.action.goToDeclaration'; + mappings['editor.action.openDeclarationToTheSide'] = 'monaco.editor.action.openDeclarationToTheSide'; + mappings['editor.action.previewDeclaration'] = 'monaco.editor.action.previewDeclaration'; + mappings['editor.action.peekImplementation'] = 'monaco.editor.action.peekImplementation'; + mappings['editor.action.goToTypeDefinition'] = 'monaco.editor.action.goToTypeDefinition'; + mappings['editor.action.peekTypeDefinition'] = 'monaco.editor.action.peekTypeDefinition'; + mappings['editor.action.referenceSearch.trigger'] = 'monaco.editor.action.referenceSearch.trigger'; + + /** + * Navigation + */ + mappings['workbench.action.gotoLine'] = 'monaco.editor.action.gotoLine'; + mappings['workbench.action.gotoSymbol'] = 'monaco.editor.action.quickOutline'; + mappings['workbench.actions.view.problems'] = 'problemsView:toggle'; + + /** + * File Management + */ + mappings['workbench.action.files.saveAs'] = 'file.saveAs'; + + /** + * Display + */ + mappings['workbench.view.explorer'] = 'navigator.reveal'; + mappings['workbench.view.search'] = 'search-in-workspace.toggle'; + mappings['workbench.view.scm'] = 'scmView:toggle'; + mappings['workbench.view.debug'] = 'debug:toggle'; + mappings['workbench.view.extensions'] = 'pluginsView:toggle'; + mappings['workbench.action.output.toggleOutput'] = 'output:toggle'; + mappings['workbench.action.terminal.openNativeConsole'] = 'terminal:new'; + + /** + * Search + */ + mappings['workbench.view.search'] = 'search-in-workspace.open'; + + // Map all the properties from exclusions from their vscode command to their theia command + for (const mappedFrom in exclusions) { + if (!exclusions.hasOwnProperty(mappedFrom)) { + continue; + } + const mappedTo = exclusions[mappedFrom]; + mappings[mappedFrom] = mappedTo[0]; + } + + // tslint:disable-next-line:no-any + export function map(id: string, args: any[] | undefined, toDo: (mappedId: string, mappedArgs: any[] | undefined) => T): T { + if (exclusions[id]) { + return toDo(exclusions[id][0], exclusions[id][1](args)); + } else if (mappings[id]) { + return toDo(mappings[id], args); + } else { + return toDo(id, args); + } + } + + // tslint:disable-next-line:no-any + type conversionFunction = ((parameter: any) => any) | undefined; + // tslint:disable-next-line:no-any + function createConversionFunction(...conversions: conversionFunction[]): (args: any[] | undefined) => any[] | undefined { + // tslint:disable-next-line:no-any + return function (args: any[] | undefined): any[] | undefined { + if (!args) { + return args; + } + // tslint:disable-next-line:no-any + 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(f: (a: T) => U): (a: T[]) => U[] { + return function (a: T[]) { + return a.map(f); + }; +} diff --git a/packages/plugin-ext/src/common/object.ts b/packages/plugin-ext/src/common/object.ts new file mode 100644 index 0000000000000..ac359749c87ba --- /dev/null +++ b/packages/plugin-ext/src/common/object.ts @@ -0,0 +1,130 @@ +/******************************************************************************** + * Copyright (C) 2018 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 + ********************************************************************************/ + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// copied from https://github.com/microsoft/vscode/blob/master/src/vs/base/common/objects.ts +// with small modifications + +// tslint:disable-next-line:no-any +export function cloneAndChange(obj: any, changer: (orig: any) => any): any { + return _cloneAndChange(obj, changer, new Set()); +} + +// tslint:disable-next-line:no-any +function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set): any { + if (isUndefinedOrNull(obj)) { + return obj; + } + + const changed = changer(obj); + if (typeof changed !== 'undefined') { + return changed; + } + + if (isArray(obj)) { + // tslint:disable-next-line:no-any + 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 (const i2 in obj) { + if (Object.prototype.hasOwnProperty.call(obj, i2)) { + // tslint:disable-next-line:no-any + (r2 as any)[i2] = _cloneAndChange(obj[i2], changer, seen); + } + } + seen.delete(obj); + return r2; + } + + return obj; +} + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// copied from https://github.com/microsoft/vscode/blob/master/src/vs/base/common/types.ts +// with small modifications + +const _typeof = { + number: 'number', + string: 'string', + undefined: 'undefined', + object: 'object', + function: 'function' +}; + +/** + * @returns whether the provided parameter is a JavaScript Array or not. + */ +// tslint:disable-next-line:no-any +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 of type `object` but **not** + * `null`, an `array`, a `regexp`, nor a `date`. + */ +// tslint:disable-next-line:no-any +export function isObject(obj: any): obj is Object { + // The method can't do a type cast since there are type (like strings) which + // are subclasses of any put not positvely matched by the function. Hence type + // narrowing results in wrong results. + return typeof obj === _typeof.object + && obj !== null + && !Array.isArray(obj) + && !(obj instanceof RegExp) + && !(obj instanceof Date); +} + +/** + * @returns whether the provided parameter is undefined. + */ +// tslint:disable-next-line:no-any +export function isUndefined(obj: any): obj is undefined { + return typeof (obj) === _typeof.undefined; +} + +/** + * @returns whether the provided parameter is undefined or null. + */ +// tslint:disable-next-line:no-any +export function isUndefinedOrNull(obj: any): obj is undefined | null { + return isUndefined(obj) || obj === null; +} diff --git a/packages/plugin-ext/src/main/browser/keybindings/keybindings-contribution-handler.ts b/packages/plugin-ext/src/main/browser/keybindings/keybindings-contribution-handler.ts index c4ac1b7f78f6b..95ba08b75e474 100644 --- a/packages/plugin-ext/src/main/browser/keybindings/keybindings-contribution-handler.ts +++ b/packages/plugin-ext/src/main/browser/keybindings/keybindings-contribution-handler.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { injectable, inject } from 'inversify'; -import { PluginContribution, Keybinding as PluginKeybinding } from '../../../common'; +import { PluginContribution, Keybinding as PluginKeybinding, KnownCommands } from '../../../common'; import { Keybinding, KeybindingRegistry, KeybindingScope } from '@theia/core/lib/browser/keybinding'; import { ILogger } from '@theia/core/lib/common/logger'; import { OS } from '@theia/core/lib/common/os'; @@ -56,7 +56,16 @@ export class KeybindingsContributionPointHandler { if (!keybinding) { return undefined; } - const { command, when } = pluginKeybinding; + let { command, when } = pluginKeybinding; + + /** + * Commands must be converted to their theia counterparts + * otherwise the command registry cannot find a handler + */ + if (KnownCommands.mappings[command]) { + command = KnownCommands.mappings[command]; + } + return { keybinding, command, when }; } diff --git a/packages/plugin-ext/src/plugin/command-registry.ts b/packages/plugin-ext/src/plugin/command-registry.ts index 7c6e7785d49dc..be13f8525d0c1 100644 --- a/packages/plugin-ext/src/plugin/command-registry.ts +++ b/packages/plugin-ext/src/plugin/command-registry.ts @@ -17,8 +17,10 @@ import * as theia from '@theia/plugin'; import { CommandRegistryExt, PLUGIN_RPC_CONTEXT as Ext, CommandRegistryMain } from '../api/plugin-api'; import { RPCProtocol } from '../api/rpc-protocol'; -import { Disposable } from './types-impl'; -import { KnownCommands } from './type-converters'; +import { Disposable, Range, Position, Location } from './types-impl'; +import { cloneAndChange } from '../common/object'; +import { fromRange, fromPosition, fromLocation } from './type-converters'; +import { KnownCommands } from '../common/known-commands'; // tslint:disable-next-line:no-any export type Handler = (...args: any[]) => T | PromiseLike; @@ -90,9 +92,27 @@ export class CommandRegistryImpl implements CommandRegistryExt { executeCommand(id: string, ...args: any[]): PromiseLike { if (this.handlers.has(id)) { return this.executeLocalCommand(id, ...args); - } else { + } else if (KnownCommands.exclusions.hasOwnProperty(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 { + // Automatically convert the incoming arguments from 0 based types (VSCode API) to 1 based types (Monaco) + args = cloneAndChange(args, function (value: any) { + if (Position.isPosition(value)) { + return fromPosition(value); + } + if (Range.isRange(value)) { + return fromRange(value); + } + if (Location.isLocation(value)) { + return fromLocation(value); + } + if (!Array.isArray(value)) { + return value; + } + }); + return this.proxy.$executeCommand(id, args); } } // tslint:enable:no-any diff --git a/packages/plugin-ext/src/plugin/type-converters.ts b/packages/plugin-ext/src/plugin/type-converters.ts index 22025f62caf41..8261d4734bb97 100644 --- a/packages/plugin-ext/src/plugin/type-converters.ts +++ b/packages/plugin-ext/src/plugin/type-converters.ts @@ -24,7 +24,8 @@ 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 { KnownCommands } from '../common/known-commands'; export function toViewColumn(ep?: EditorPosition): theia.ViewColumn | undefined { if (typeof ep !== 'number') { @@ -443,60 +444,6 @@ export function toInternalCommand(external: theia.Command): model.Command { })); } -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 map(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(f: (a: T) => U): (a: T[]) => U[] { - return function (a: T[]) { - return a.map(f); - }; -} - // tslint:disable-next-line:no-any export function fromWorkspaceEdit(value: theia.WorkspaceEdit, documents?: any): WorkspaceEditDto { const result: WorkspaceEditDto = { diff --git a/packages/plugin-ext/src/plugin/types-impl.ts b/packages/plugin-ext/src/plugin/types-impl.ts index 1b47d78505532..67fb98f7e5847 100644 --- a/packages/plugin-ext/src/plugin/types-impl.ts +++ b/packages/plugin-ext/src/plugin/types-impl.ts @@ -785,6 +785,23 @@ export class Location { this.range = new Range(rangeOrPosition, rangeOrPosition); } } + + /*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + // copied from https://github.com/microsoft/vscode/blob/master/src/vs/workbench/api/common/extHostTypes.ts + // tslint:disable-next-line:no-any + static isLocation(thing: any): thing is Location { + if (thing instanceof Location) { + return true; + } + if (!thing) { + return false; + } + return Range.isRange((thing).range) + && URI.isUri((thing).uri); + } } export enum DiagnosticTag {