@@ -19,9 +19,10 @@ import { CommandRegistryExt, PLUGIN_RPC_CONTEXT as Ext, CommandRegistryMain } fr
1919import { RPCProtocol } from '../common/rpc-protocol' ;
2020import { Disposable } from './types-impl' ;
2121import { KnownCommands } from './type-converters' ;
22+ import { DisposableCollection } from '@theia/core' ;
2223
2324// tslint:disable-next-line:no-any
24- export type Handler = < T > ( ...args : any [ ] ) => T | PromiseLike < T > ;
25+ export type Handler = < T > ( ...args : any [ ] ) => T | PromiseLike < T | undefined > ;
2526
2627export interface ArgumentProcessor {
2728 // tslint:disable-next-line:no-any
@@ -34,10 +35,16 @@ export class CommandRegistryImpl implements CommandRegistryExt {
3435 private readonly commands = new Set < string > ( ) ;
3536 private readonly handlers = new Map < string , Handler > ( ) ;
3637 private readonly argumentProcessors : ArgumentProcessor [ ] ;
38+ private readonly commandsConverter : CommandsConverter ;
3739
3840 constructor ( rpc : RPCProtocol ) {
3941 this . proxy = rpc . getProxy ( Ext . COMMAND_REGISTRY_MAIN ) ;
4042 this . argumentProcessors = [ ] ;
43+ this . commandsConverter = new CommandsConverter ( this ) ;
44+ }
45+
46+ get converter ( ) : CommandsConverter {
47+ return this . commandsConverter ;
4148 }
4249
4350 // tslint:disable-next-line:no-any
@@ -78,7 +85,7 @@ export class CommandRegistryImpl implements CommandRegistryExt {
7885 }
7986
8087 // tslint:disable-next-line:no-any
81- $executeCommand < T > ( id : string , ...args : any [ ] ) : PromiseLike < T > {
88+ $executeCommand < T > ( id : string , ...args : any [ ] ) : PromiseLike < T | undefined > {
8289 if ( this . handlers . has ( id ) ) {
8390 return this . executeLocalCommand ( id , ...args ) ;
8491 } else {
@@ -102,7 +109,7 @@ export class CommandRegistryImpl implements CommandRegistryExt {
102109 }
103110
104111 // tslint:disable-next-line:no-any
105- private async executeLocalCommand < T > ( id : string , ...args : any [ ] ) : Promise < T > {
112+ private async executeLocalCommand < T > ( id : string , ...args : any [ ] ) : Promise < T | undefined > {
106113 const handler = this . handlers . get ( id ) ;
107114 if ( handler ) {
108115 return handler < T > ( ...args . map ( arg => this . argumentProcessors . reduce ( ( r , p ) => p . processArgument ( r ) , arg ) ) ) ;
@@ -123,3 +130,57 @@ export class CommandRegistryImpl implements CommandRegistryExt {
123130 this . argumentProcessors . push ( processor ) ;
124131 }
125132}
133+
134+ /*---------------------------------------------------------------------------------------------
135+ * Copyright (c) Microsoft Corporation. All rights reserved.
136+ * Licensed under the MIT License. See License.txt in the project root for license information.
137+ *--------------------------------------------------------------------------------------------*/
138+
139+ // copied and modified from https://github.com/microsoft/vscode/blob/1.37.1/src/vs/workbench/api/common/extHostCommands.ts#L217-L259
140+ export class CommandsConverter {
141+
142+ private readonly safeCommandId : string ;
143+ private readonly commands : CommandRegistryImpl ;
144+ private readonly commandsMap = new Map < number , theia . Command > ( ) ;
145+ private handle = 0 ;
146+ private isSafeCommandRegistered : boolean ;
147+
148+ constructor ( commands : CommandRegistryImpl ) {
149+ this . safeCommandId = `theia_safe_cmd_${ Date . now ( ) . toString ( ) } ` ;
150+ this . commands = commands ;
151+ this . isSafeCommandRegistered = false ;
152+ }
153+
154+ /**
155+ * Convert to a command that can be safely passed over JSON-RPC.
156+ */
157+ toSafeCommand ( command : theia . Command , disposables : DisposableCollection ) : theia . Command {
158+ if ( ! this . isSafeCommandRegistered ) {
159+ this . commands . registerCommand ( { id : this . safeCommandId } , this . executeSafeCommand , this ) ;
160+ this . isSafeCommandRegistered = true ;
161+ }
162+
163+ const result : theia . Command = { } ;
164+ Object . assign ( result , command ) ;
165+
166+ if ( command . command && command . arguments && command . arguments . length > 0 ) {
167+ const id = this . handle ++ ;
168+ this . commandsMap . set ( id , command ) ;
169+ disposables . push ( new Disposable ( ( ) => this . commandsMap . delete ( id ) ) ) ;
170+ result . command = this . safeCommandId ;
171+ result . arguments = [ id ] ;
172+ }
173+
174+ return result ;
175+ }
176+
177+ // tslint:disable-next-line:no-any
178+ private executeSafeCommand < R > ( ...args : any [ ] ) : PromiseLike < R | undefined > {
179+ const command = this . commandsMap . get ( args [ 0 ] ) ;
180+ if ( ! command || ! command . command ) {
181+ return Promise . reject ( 'command NOT FOUND' ) ;
182+ }
183+ return this . commands . executeCommand ( command . command , ...( command . arguments || [ ] ) ) ;
184+ }
185+
186+ }
0 commit comments