Skip to content

Commit 1902dce

Browse files
committed
💄
1 parent 599b29c commit 1902dce

3 files changed

Lines changed: 57 additions & 57 deletions

File tree

src/vs/base/common/service.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict';
77

8-
import { Promise } from 'vs/base/common/winjs.base';
8+
import { Promise, TPromise } from 'vs/base/common/winjs.base';
99
import { assign } from 'vs/base/common/objects';
1010
import { IDisposable, fnToDisposable } from 'vs/base/common/lifecycle';
1111
import Event, { Emitter } from 'vs/base/common/event';
@@ -71,6 +71,10 @@ export interface IServiceMap {
7171
[name: string]: any;
7272
}
7373

74+
export interface IClient {
75+
getService<TService>(serviceName: string, serviceCtor: IServiceCtor<TService>): TService;
76+
}
77+
7478
const ServiceEventProperty = '$__SERVICE_EVENT';
7579

7680
/**
@@ -191,7 +195,7 @@ export class Server {
191195
}
192196
}
193197

194-
export class Client {
198+
export class Client implements IClient {
195199

196200
private state: ServiceState;
197201
private bufferedRequests: IRequest[];
@@ -338,4 +342,51 @@ export class Client {
338342
// noop
339343
}
340344
}
345+
}
346+
347+
/**
348+
* Useful when the service itself is needed right away but the client
349+
* is wrapped within a promise.
350+
*/
351+
export function getService<TService>(clientPromise: TPromise<IClient>, serviceName: string, serviceCtor: IServiceCtor<TService>): TService {
352+
let _servicePromise: TPromise<TService>;
353+
let servicePromise = () => {
354+
if (!_servicePromise) {
355+
_servicePromise = clientPromise.then(client => client.getService(serviceName, serviceCtor));
356+
}
357+
return _servicePromise;
358+
};
359+
360+
return Object.keys(serviceCtor.prototype)
361+
.filter(key => key !== 'constructor')
362+
.reduce((result, key) => {
363+
if (isServiceEvent(serviceCtor.prototype[key])) {
364+
let promise: TPromise<void>;
365+
let disposable: IDisposable;
366+
367+
const emitter = new Emitter<any>({
368+
onFirstListenerAdd: () => {
369+
promise = servicePromise().then(service => {
370+
disposable = service[key](e => emitter.fire(e));
371+
});
372+
},
373+
onLastListenerRemove: () => {
374+
if (disposable) {
375+
disposable.dispose();
376+
disposable = null;
377+
}
378+
promise.cancel();
379+
promise = null;
380+
}
381+
});
382+
383+
return assign(result, { [key]: emitter.event });
384+
}
385+
386+
return assign(result, {
387+
[key]: (...args) => {
388+
return servicePromise().then(service => service[key](...args));
389+
}
390+
});
391+
}, {} as TService);
341392
}

src/vs/base/node/service.net.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import net = require('net');
99
import { IDisposable } from 'vs/base/common/lifecycle';
1010
import Event, { Emitter } from 'vs/base/common/event';
11-
import { Server as IPCServer, Client as IPCClient, IServiceCtor, IServiceMap, IMessagePassingProtocol } from 'vs/base/common/service';
11+
import { Server as IPCServer, Client as IPCClient, IServiceCtor, IServiceMap, IMessagePassingProtocol, IClient } from 'vs/base/common/service';
1212
import { TPromise } from 'vs/base/common/winjs.base';
1313

1414
function bufferIndexOf(buffer: Buffer, value: number, start = 0) {
@@ -92,7 +92,7 @@ export class Server implements IDisposable {
9292
}
9393
}
9494

95-
export class Client implements IDisposable {
95+
export class Client implements IDisposable, IClient {
9696

9797
private ipcClient: IPCClient;
9898
private _onClose = new Emitter<void>();

src/vs/workbench/electron-browser/shell.ts

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -97,63 +97,12 @@ import {IUntitledEditorService, UntitledEditorService} from 'vs/workbench/servic
9797
import {CrashReporter} from 'vs/workbench/electron-browser/crashReporter';
9898
import {IThemeService, DEFAULT_THEME_ID} from 'vs/workbench/services/themes/common/themeService';
9999
import {ThemeService} from 'vs/workbench/services/themes/node/themeService';
100-
import { IServiceCtor, isServiceEvent } from 'vs/base/common/service';
100+
import { IServiceCtor, isServiceEvent, getService } from 'vs/base/common/service';
101101
import { connect, Client } from 'vs/base/node/service.net';
102102
import { IExtensionsService } from 'vs/workbench/parts/extensions/common/extensions';
103103
import { ExtensionsService } from 'vs/workbench/parts/extensions/node/extensionsService';
104104
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
105105

106-
/**
107-
* This ugly code is needed because at the point when we need shared services
108-
* in the instantiation service, the connection to the shared process is not yet
109-
* completed. This create a delayed service wrapper that waits on that connection
110-
* and then relays all requests to the shared services.
111-
*
112-
* TODO@Joao remove
113-
*/
114-
export function getDelayedService<TService>(clientPromise: TPromise<Client>, serviceName: string, serviceCtor: IServiceCtor<TService>): TService {
115-
let _servicePromise: TPromise<TService>;
116-
let servicePromise = () => {
117-
if (!_servicePromise) {
118-
_servicePromise = clientPromise.then(client => client.getService(serviceName, serviceCtor));
119-
}
120-
return _servicePromise;
121-
};
122-
123-
return Object.keys(serviceCtor.prototype)
124-
.filter(key => key !== 'constructor')
125-
.reduce((result, key) => {
126-
if (isServiceEvent(serviceCtor.prototype[key])) {
127-
let promise: TPromise<void>;
128-
let disposable: IDisposable;
129-
130-
const emitter = new Emitter<any>({
131-
onFirstListenerAdd: () => {
132-
promise = servicePromise().then(service => {
133-
disposable = service[key](e => emitter.fire(e));
134-
});
135-
},
136-
onLastListenerRemove: () => {
137-
if (disposable) {
138-
disposable.dispose();
139-
disposable = null;
140-
}
141-
promise.cancel();
142-
promise = null;
143-
}
144-
});
145-
146-
return objects.assign(result, { [key]: emitter.event });
147-
}
148-
149-
return objects.assign(result, {
150-
[key]: (...args) => {
151-
return servicePromise().then(service => service[key](...args));
152-
}
153-
});
154-
}, {} as TService);
155-
}
156-
157106
/**
158107
* The Monaco Workbench Shell contains the Monaco workbench with a rich header containing navigation and the activity bar.
159108
* With the Shell being the top level element in the page, it is also responsible for driving the layouting.
@@ -220,7 +169,7 @@ export class WorkbenchShell {
220169
});
221170
}, errors.onUnexpectedError);
222171

223-
instantiationService.addSingleton(IExtensionsService, getDelayedService<IExtensionsService>(sharedProcessClientPromise, 'ExtensionService', ExtensionsService));
172+
instantiationService.addSingleton(IExtensionsService, getService<IExtensionsService>(sharedProcessClientPromise, 'ExtensionService', ExtensionsService));
224173

225174
// Workbench
226175
this.workbench = new Workbench(workbenchContainer.getHTMLElement(), this.workspace, this.configuration, this.options, instantiationService);

0 commit comments

Comments
 (0)