@@ -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,51 @@ export class CommandRegistryImpl implements CommandRegistryExt {
123130 this . argumentProcessors . push ( processor ) ;
124131 }
125132}
133+
134+ export class CommandsConverter {
135+
136+ private readonly safeCommandId : string ;
137+ private readonly commands : CommandRegistryImpl ;
138+ private readonly commandsMap = new Map < number , theia . Command > ( ) ;
139+ private handle = 0 ;
140+ private isCommandRegistered : boolean ;
141+
142+ constructor ( commands : CommandRegistryImpl ) {
143+ this . safeCommandId = `theia_safe_cmd_${ Date . now ( ) . toString ( ) } ` ;
144+ this . commands = commands ;
145+ this . isCommandRegistered = false ;
146+ }
147+
148+ /**
149+ * Convert to a command that can be safely passed over JSON-RPC.
150+ */
151+ toSafeCommand ( command : theia . Command , disposables : DisposableCollection ) : theia . Command {
152+ if ( ! this . isCommandRegistered ) {
153+ this . commands . registerCommand ( { id : this . safeCommandId } , this . executeSafeCommand , this ) ;
154+ this . isCommandRegistered = true ;
155+ }
156+
157+ const result : theia . Command = { } ;
158+ Object . assign ( result , command ) ;
159+
160+ if ( command . command && command . arguments && command . arguments . length > 0 ) {
161+ const id = this . handle ++ ;
162+ this . commandsMap . set ( id , command ) ;
163+ disposables . push ( new Disposable ( ( ) => this . commandsMap . delete ( id ) ) ) ;
164+ result . command = this . safeCommandId ;
165+ result . arguments = [ id ] ;
166+ }
167+
168+ return result ;
169+ }
170+
171+ // tslint:disable-next-line:no-any
172+ private executeSafeCommand < R > ( ...args : any [ ] ) : PromiseLike < R | undefined > {
173+ const command = this . commandsMap . get ( args [ 0 ] ) ;
174+ if ( ! command || ! command . command ) {
175+ return Promise . reject ( 'command NOT FOUND' ) ;
176+ }
177+ return this . commands . executeCommand ( command . command , ...( command . arguments || [ ] ) ) ;
178+ }
179+
180+ }
0 commit comments