diff --git a/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts b/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts index a076c013d00e4dd31659036763aef4aec725a8b7..451dc780ffc0c75ef5cdbfd423494224ea063d41 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts @@ -7,22 +7,22 @@ import Severity from 'vs/base/common/severity'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { MainProcessExtensionServiceShape } from '../node/extHost.protocol'; -import { MainProcessExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService"; +import { ExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService"; export class MainProcessExtensionServiceAPI extends MainProcessExtensionServiceShape { - private readonly _extensionService: MainProcessExtensionService; + private readonly _extensionService: ExtensionService; constructor( @IExtensionService extensionService: IExtensionService) { super(); - if (extensionService instanceof MainProcessExtensionService) { + if (extensionService instanceof ExtensionService) { this._extensionService = extensionService; } } $localShowMessage(severity: Severity, msg: string): void { - this._extensionService._localShowMessage(severity, msg); + this._extensionService._logOrShowMessage(severity, msg); } $onExtensionActivated(extensionId: string): void { } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 294376c14dfaeafe540ab4f554db7fcf1348ed31..80d82660f41f2e7ad547eee33a3cf5b315020da3 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -49,7 +49,7 @@ import { IntegrityServiceImpl } from 'vs/platform/integrity/node/integrityServic import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; -import { MainProcessExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService"; +import { ExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService"; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -118,7 +118,7 @@ export class WorkbenchShell { private configurationService: IConfigurationService; private contextService: IWorkspaceContextService; private telemetryService: ITelemetryService; - private extensionService: MainProcessExtensionService; + private extensionService: ExtensionService; private broadcastService: IBroadcastService; private timerService: ITimerService; private themeService: WorkbenchThemeService; @@ -321,7 +321,7 @@ export class WorkbenchShell { serviceCollection.set(IExtensionEnablementService, extensionEnablementService); disposables.push(extensionEnablementService); - this.extensionService = instantiationService.createInstance(MainProcessExtensionService); + this.extensionService = instantiationService.createInstance(ExtensionService); serviceCollection.set(IExtensionService, this.extensionService); serviceCollection.set(IThreadService, this.extensionService); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index b4316cdfa97165734444e031226e89ad42660d8b..e41944cd4aef5b075c1b8b2982f553f86f15bb6c 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -31,7 +31,7 @@ import { createServer, Server } from 'net'; import Event, { Emitter, debounceEvent, mapEvent, any } from 'vs/base/common/event'; import { fromEventEmitter } from 'vs/base/node/event'; import { IInitData, IWorkspaceData } from 'vs/workbench/api/node/extHost.protocol'; -import { MainProcessExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService"; +import { ExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService"; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { ICrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService'; import { IBroadcastService, IBroadcast } from "vs/platform/broadcast/electron-browser/broadcastService"; @@ -76,7 +76,7 @@ export class ExtensionHostProcessWorker { public readonly messagingProtocol = new LazyMessagePassingProtol(); - private extensionService: MainProcessExtensionService; + private extensionService: ExtensionService; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @@ -122,7 +122,7 @@ export class ExtensionHostProcessWorker { } } - public start(extensionService: MainProcessExtensionService): void { + public start(extensionService: ExtensionService): void { this.extensionService = extensionService; TPromise.join([this.tryListenOnPipe(), this.tryFindDebugPort()]).then(data => { diff --git a/src/vs/workbench/node/extensionPoints.ts b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts similarity index 78% rename from src/vs/workbench/node/extensionPoints.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts index 8f1f53391e8283a9e5e1ba604f49e66e3d299569..60261ce5e0df5a76611d3d3670f1dcc892689f8a 100644 --- a/src/vs/workbench/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts @@ -8,8 +8,7 @@ import * as nls from 'vs/nls'; import * as Platform from 'vs/base/common/platform'; import pfs = require('vs/base/node/pfs'); -import { IExtensionDescription, IMessage } from 'vs/platform/extensions/common/extensions'; -import Severity from 'vs/base/common/severity'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { TPromise } from 'vs/base/common/winjs.base'; import { groupBy, values } from 'vs/base/common/collections'; import { join, normalize, extname } from 'path'; @@ -32,58 +31,23 @@ const nlsConfig: NlsConfiguration = { pseudo: Platform.locale === 'pseudo' }; -export interface IMessagesCollector { +export interface ILog { error(source: string, message: string): void; warn(source: string, message: string): void; info(source: string, message: string): void; } -export class MessagesCollector implements IMessagesCollector { - - private _messages: IMessage[]; - - constructor() { - this._messages = []; - } - - public getMessages(): IMessage[] { - return this._messages; - } - - private _msg(source: string, type: Severity, message: string): void { - this._messages.push({ - type: type, - message: message, - source: source, - extensionId: undefined, - extensionPointId: undefined - }); - } - - public error(source: string, message: string): void { - this._msg(source, Severity.Error, message); - } - - public warn(source: string, message: string): void { - this._msg(source, Severity.Warning, message); - } - - public info(source: string, message: string): void { - this._msg(source, Severity.Info, message); - } -} - abstract class ExtensionManifestHandler { protected _ourVersion: string; - protected _collector: IMessagesCollector; + protected _log: ILog; protected _absoluteFolderPath: string; protected _isBuiltin: boolean; protected _absoluteManifestPath: string; - constructor(ourVersion: string, collector: IMessagesCollector, absoluteFolderPath: string, isBuiltin: boolean) { + constructor(ourVersion: string, log: ILog, absoluteFolderPath: string, isBuiltin: boolean) { this._ourVersion = ourVersion; - this._collector = collector; + this._log = log; this._absoluteFolderPath = absoluteFolderPath; this._isBuiltin = isBuiltin; this._absoluteManifestPath = join(absoluteFolderPath, MANIFEST_FILE); @@ -97,7 +61,7 @@ class ExtensionManifestParser extends ExtensionManifestHandler { try { return JSON.parse(manifestContents.toString()); } catch (e) { - this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, getParseErrorMessage(e.message))); + this._log.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, getParseErrorMessage(e.message))); } return null; }, (err) => { @@ -105,7 +69,7 @@ class ExtensionManifestParser extends ExtensionManifestHandler { return null; } - this._collector.error(this._absoluteFolderPath, nls.localize('fileReadFail', "Cannot read file {0}: {1}.", this._absoluteManifestPath, err.message)); + this._log.error(this._absoluteFolderPath, nls.localize('fileReadFail', "Cannot read file {0}: {1}.", this._absoluteManifestPath, err.message)); return null; }); } @@ -132,16 +96,16 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { return ExtensionManifestNLSReplacer.resolveOriginalMessageBundle(messageBundle.original, errors).then(originalMessages => { if (errors.length > 0) { errors.forEach((error) => { - this._collector.error(this._absoluteFolderPath, nls.localize('jsonsParseFail', "Failed to parse {0} or {1}: {2}.", messageBundle.localized, messageBundle.original, getParseErrorMessage(error.error))); + this._log.error(this._absoluteFolderPath, nls.localize('jsonsParseFail', "Failed to parse {0} or {1}: {2}.", messageBundle.localized, messageBundle.original, getParseErrorMessage(error.error))); }); return extensionDescription; } - ExtensionManifestNLSReplacer._replaceNLStrings(extensionDescription, messages, originalMessages, this._collector, this._absoluteFolderPath); + ExtensionManifestNLSReplacer._replaceNLStrings(extensionDescription, messages, originalMessages, this._log, this._absoluteFolderPath); return extensionDescription; }); }, (err) => { - this._collector.error(this._absoluteFolderPath, nls.localize('fileReadFail', "Cannot read file {0}: {1}.", messageBundle.localized, err.message)); + this._log.error(this._absoluteFolderPath, nls.localize('fileReadFail', "Cannot read file {0}: {1}.", messageBundle.localized, err.message)); return null; }); }); @@ -196,7 +160,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { * This routine makes the following assumptions: * The root element is an object literal */ - private static _replaceNLStrings(literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string }, collector: IMessagesCollector, messageScope: string): void { + private static _replaceNLStrings(literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string }, log: ILog, messageScope: string): void { function processEntry(obj: any, key: string | number, command?: boolean) { let value = obj[key]; if (Types.isString(value)) { @@ -212,7 +176,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { } obj[key] = command && (key === 'title' || key === 'category') && originalMessages ? { value: message, original: originalMessages[messageKey] } : message; } else { - collector.warn(messageScope, nls.localize('missingNLSKey', "Couldn't find message for key {0}.", messageKey)); + log.warn(messageScope, nls.localize('missingNLSKey', "Couldn't find message for key {0}.", messageKey)); } } } else if (Types.isObject(value)) { @@ -258,14 +222,14 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { let notices: string[] = []; if (!isValidExtensionDescription(this._ourVersion, this._absoluteFolderPath, extensionDescription, notices)) { notices.forEach((error) => { - this._collector.error(this._absoluteFolderPath, error); + this._log.error(this._absoluteFolderPath, error); }); return null; } // in this case the notices are warnings notices.forEach((error) => { - this._collector.warn(this._absoluteFolderPath, error); + this._log.warn(this._absoluteFolderPath, error); }); // id := `publisher.name` @@ -289,26 +253,26 @@ export class ExtensionScanner { */ public static scanExtension( version: string, - collector: IMessagesCollector, + log: ILog, absoluteFolderPath: string, isBuiltin: boolean ): TPromise { absoluteFolderPath = normalize(absoluteFolderPath); - let parser = new ExtensionManifestParser(version, collector, absoluteFolderPath, isBuiltin); + let parser = new ExtensionManifestParser(version, log, absoluteFolderPath, isBuiltin); return parser.parse().then((extensionDescription) => { if (extensionDescription === null) { return null; } - let nlsReplacer = new ExtensionManifestNLSReplacer(version, collector, absoluteFolderPath, isBuiltin); + let nlsReplacer = new ExtensionManifestNLSReplacer(version, log, absoluteFolderPath, isBuiltin); return nlsReplacer.replaceNLS(extensionDescription); }).then((extensionDescription) => { if (extensionDescription === null) { return null; } - let validator = new ExtensionManifestValidator(version, collector, absoluteFolderPath, isBuiltin); + let validator = new ExtensionManifestValidator(version, log, absoluteFolderPath, isBuiltin); return validator.validate(extensionDescription); }); } @@ -318,7 +282,7 @@ export class ExtensionScanner { */ public static scanExtensions( version: string, - collector: IMessagesCollector, + log: ILog, absoluteFolderPath: string, isBuiltin: boolean ): TPromise { @@ -362,10 +326,10 @@ export class ExtensionScanner { return [...nonGallery, ...latest]; }) - .then(folders => TPromise.join(folders.map(f => this.scanExtension(version, collector, join(absoluteFolderPath, f), isBuiltin)))) + .then(folders => TPromise.join(folders.map(f => this.scanExtension(version, log, join(absoluteFolderPath, f), isBuiltin)))) .then(extensionDescriptions => extensionDescriptions.filter(item => item !== null)) .then(null, err => { - collector.error(absoluteFolderPath, err); + log.error(absoluteFolderPath, err); return []; }); }); @@ -377,22 +341,22 @@ export class ExtensionScanner { */ public static scanOneOrMultipleExtensions( version: string, - collector: IMessagesCollector, + log: ILog, absoluteFolderPath: string, isBuiltin: boolean ): TPromise { return pfs.fileExists(join(absoluteFolderPath, MANIFEST_FILE)).then((exists) => { if (exists) { - return this.scanExtension(version, collector, absoluteFolderPath, isBuiltin).then((extensionDescription) => { + return this.scanExtension(version, log, absoluteFolderPath, isBuiltin).then((extensionDescription) => { if (extensionDescription === null) { return []; } return [extensionDescription]; }); } - return this.scanExtensions(version, collector, absoluteFolderPath, isBuiltin); + return this.scanExtensions(version, log, absoluteFolderPath, isBuiltin); }, (err) => { - collector.error(absoluteFolderPath, err); + log.error(absoluteFolderPath, err); return []; }); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 6325fa295695378648252f7ef435d0bdfc2436b7..4671dbee58edb00543ac57d8076b33ea4938fd4d 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -15,7 +15,7 @@ import { IMessage, IExtensionDescription, IExtensionsStatus, IExtensionService, import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions, getGloballyDisabledExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionsRegistry, ExtensionPoint, IExtensionPointUser, ExtensionMessageCollector, IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry'; -import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints'; +import { ExtensionScanner, ILog } from 'vs/workbench/services/extensions/electron-browser/extensionPoints'; import { IMessageService } from 'vs/platform/message/common/message'; import { IThreadService, ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, ExtHostExtensionServiceShape } from "vs/workbench/api/node/extHost.protocol"; @@ -29,52 +29,56 @@ import { MainThreadService } from "vs/workbench/services/thread/electron-browser const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions')); function messageWithSource(msg: IMessage): string { - return (msg.source ? '[' + msg.source + ']: ' : '') + msg.message; + return messageWithSource2(msg.source, msg.message); +} + +function messageWithSource2(source: string, message: string): string { + if (source) { + return `[${source}]: ${message}`; + } + return message; } const hasOwnProperty = Object.hasOwnProperty; const NO_OP_VOID_PROMISE = TPromise.as(void 0); -export abstract class AbstractExtensionService { - public _serviceBrand: any; +/** + * A barrier that is initially closed and then becomes opened permanently. + */ +class Barrier { - private _onReady: TPromise; - private _onReadyC: (v: boolean) => void; - private _isReady: boolean; - protected _registry: ExtensionDescriptionRegistry; + private _isOpen: boolean; + private _promise: TPromise; + private _completePromise: (v: boolean) => void; constructor() { - this._isReady = false; - this._onReady = new TPromise((c, e, p) => { - this._onReadyC = c; + this._isOpen = false; + this._promise = new TPromise((c, e, p) => { + this._completePromise = c; }, () => { console.warn('You should really not try to cancel this ready promise!'); }); - this._registry = new ExtensionDescriptionRegistry(); } - protected _triggerOnReady(): void { - this._isReady = true; - this._onReadyC(true); + public isOpen(): boolean { + return this._isOpen; } - public onReady(): TPromise { - return this._onReady; + public open(): void { + this._isOpen = true; + this._completePromise(true); } - public activateByEvent(activationEvent: string): TPromise { - if (this._isReady) { - return this._activateByEvent(activationEvent); - } else { - return this._onReady.then(() => this._activateByEvent(activationEvent)); - } + public wait(): TPromise { + return this._promise; } - - protected abstract _activateByEvent(activationEvent: string): TPromise; } -export class MainProcessExtensionService extends AbstractExtensionService implements IThreadService, IExtensionService { +export class ExtensionService implements IThreadService, IExtensionService { + public _serviceBrand: any; + private _registry: ExtensionDescriptionRegistry; + private readonly _barrier: Barrier; private readonly _isDev: boolean; private readonly _extensionsStatus: { [id: string]: IExtensionsStatus }; /** @@ -92,8 +96,8 @@ export class MainProcessExtensionService extends AbstractExtensionService implem @IExtensionEnablementService private readonly _extensionEnablementService: IExtensionEnablementService, @IStorageService private readonly _storageService: IStorageService, ) { - super(); - + this._registry = null; + this._barrier = new Barrier(); this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; this._extensionsStatus = {}; this._alreadyActivatedEvents = Object.create(null); @@ -120,8 +124,13 @@ export class MainProcessExtensionService extends AbstractExtensionService implem // ---- begin IExtensionService - // public activateByEvent(activationEvent: string): TPromise { - // } + public activateByEvent(activationEvent: string): TPromise { + if (this._barrier.isOpen) { + return this._activateByEvent(activationEvent); + } else { + return this._barrier.wait().then(() => this._activateByEvent(activationEvent)); + } + } protected _activateByEvent(activationEvent: string): TPromise { if (this._alreadyActivatedEvents[activationEvent]) { @@ -132,8 +141,9 @@ export class MainProcessExtensionService extends AbstractExtensionService implem }); } - // public onReady(): TPromise { - // } + public onReady(): TPromise { + return this._barrier.wait(); + } public getExtensions(): TPromise { return this.onReady().then(() => { @@ -164,33 +174,15 @@ export class MainProcessExtensionService extends AbstractExtensionService implem // ---- end IExtensionService - private _handleMessage(msg: IMessage) { - - if (!this._extensionsStatus[msg.source]) { - this._extensionsStatus[msg.source] = { messages: [] }; - } - this._extensionsStatus[msg.source].messages.push(msg); - - this._localShowMessage( - msg.type, messageWithSource(msg), - this._environmentService.extensionDevelopmentPath === msg.source - ); - - if (!this._isDev && msg.extensionId) { - const { type, extensionId, extensionPointId, message } = msg; - this._telemetryService.publicLog('extensionsMessage', { - type, extensionId, extensionPointId, message - }); - } - } - // --- impl private _initialize(): void { - MainProcessExtensionService._scanInstalledExtensions(this._environmentService).done(([installedExtensions, messages]) => { - messages.forEach(entry => this._localShowMessage(entry.type, this._isDev ? (entry.source ? '[' + entry.source + ']: ' : '') + entry.message : entry.message)); + const log = new Logger((severity, source, message) => { + this._logOrShowMessage(severity, this._isDev ? messageWithSource2(source, message) : message); + }); + ExtensionService._scanInstalledExtensions(this._environmentService, log).then((installedExtensions) => { const disabledExtensions = [ ...getGloballyDisabledExtensions(this._extensionEnablementService, this._storageService, installedExtensions), ...this._extensionEnablementService.getWorkspaceDisabledExtensions() @@ -201,16 +193,55 @@ export class MainProcessExtensionService extends AbstractExtensionService implem disabledCount: disabledExtensions.length }); - this._onExtensionDescriptions(disabledExtensions.length ? installedExtensions.filter(e => disabledExtensions.every(id => !areSameExtensions({ id }, e))) : installedExtensions); + if (disabledExtensions.length === 0) { + return installedExtensions; + } + return installedExtensions.filter(e => disabledExtensions.every(id => !areSameExtensions({ id }, e))); + + }).then((extensionDescriptions) => { + this._registry = new ExtensionDescriptionRegistry(); + this._registry.registerExtensions(extensionDescriptions); + + let availableExtensions = this._registry.getAllExtensionDescriptions(); + let extensionPoints = ExtensionsRegistry.getExtensionPoints(); + + let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); + + for (let i = 0, len = extensionPoints.length; i < len; i++) { + ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + } + + this._barrier.open(); }); } - private static _scanInstalledExtensions(environmentService: IEnvironmentService): TPromise<[IExtensionDescription[], IMessage[]]> { - const collector = new MessagesCollector(); + private _handleExtensionPointMessage(msg: IMessage) { + + if (!this._extensionsStatus[msg.source]) { + this._extensionsStatus[msg.source] = { messages: [] }; + } + this._extensionsStatus[msg.source].messages.push(msg); + + if (msg.source === this._environmentService.extensionDevelopmentPath) { + // This message is about the extension currently being developed + this._showMessageToUser(msg.type, messageWithSource(msg)); + } else { + this._logMessageInConsole(msg.type, messageWithSource(msg)); + } + + if (!this._isDev && msg.extensionId) { + const { type, extensionId, extensionPointId, message } = msg; + this._telemetryService.publicLog('extensionsMessage', { + type, extensionId, extensionPointId, message + }); + } + } + + private static _scanInstalledExtensions(environmentService: IEnvironmentService, log: ILog): TPromise { const version = pkg.version; - const builtinExtensions = ExtensionScanner.scanExtensions(version, collector, SystemExtensionsRoot, true); - const userExtensions = environmentService.disableExtensions || !environmentService.extensionsPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, collector, environmentService.extensionsPath, false); - const developedExtensions = environmentService.disableExtensions || !environmentService.isExtensionDevelopment ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, collector, environmentService.extensionDevelopmentPath, false); + const builtinExtensions = ExtensionScanner.scanExtensions(version, log, SystemExtensionsRoot, true); + const userExtensions = environmentService.disableExtensions || !environmentService.extensionsPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, log, environmentService.extensionsPath, false); + const developedExtensions = environmentService.disableExtensions || !environmentService.isExtensionDevelopment ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, log, environmentService.extensionDevelopmentPath, false); return TPromise.join([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => { const builtinExtensions = extensionDescriptions[0]; @@ -223,45 +254,26 @@ export class MainProcessExtensionService extends AbstractExtensionService implem }); userExtensions.forEach((userExtension) => { if (result.hasOwnProperty(userExtension.id)) { - collector.warn(userExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath)); + log.warn(userExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath)); } result[userExtension.id] = userExtension; }); developedExtensions.forEach(developedExtension => { - collector.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath)); + log.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath)); if (result.hasOwnProperty(developedExtension.id)) { - collector.warn(developedExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath)); + log.warn(developedExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath)); } result[developedExtension.id] = developedExtension; }); return Object.keys(result).map(name => result[name]); }).then(null, err => { - collector.error('', err); + log.error('', err); return []; - }).then<[IExtensionDescription[], IMessage[]]>(extensions => { - const messages = collector.getMessages(); - const result: [IExtensionDescription[], IMessage[]] = [extensions, messages]; - return result; }); } - private _onExtensionDescriptions(extensionDescriptions: IExtensionDescription[]): void { - this._registry.registerExtensions(extensionDescriptions); - - let availableExtensions = this._registry.getAllExtensionDescriptions(); - let extensionPoints = ExtensionsRegistry.getExtensionPoints(); - - for (let i = 0, len = extensionPoints.length; i < len; i++) { - this._handleExtensionPoint(extensionPoints[i], availableExtensions); - } - - this._triggerOnReady(); - } - - private _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[]): void { - let messageHandler = (msg: IMessage) => this._handleMessage(msg); - + private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { let users: IExtensionPointUser[] = [], usersLen = 0; for (let i = 0, len = availableExtensions.length; i < len; i++) { let desc = availableExtensions[i]; @@ -278,14 +290,16 @@ export class MainProcessExtensionService extends AbstractExtensionService implem extensionPoint.acceptUsers(users); } - // -- called by extension host - - public _localShowMessage(severity: Severity, msg: string, useMessageService: boolean = this._isDev): void { - // Only show nasty intrusive messages if doing extension development - // and print all other messages to the console - if (useMessageService && (severity === Severity.Error || severity === Severity.Warning)) { + private _showMessageToUser(severity: Severity, msg: string): void { + if (severity === Severity.Error || severity === Severity.Warning) { this._messageService.show(severity, msg); - } else if (severity === Severity.Error) { + } else { + this._logMessageInConsole(severity, msg); + } + } + + private _logMessageInConsole(severity: Severity, msg: string): void { + if (severity === Severity.Error) { console.error(msg); } else if (severity === Severity.Warning) { console.warn(msg); @@ -293,4 +307,37 @@ export class MainProcessExtensionService extends AbstractExtensionService implem console.log(msg); } } + + // -- called by extension host + + public _logOrShowMessage(severity: Severity, msg: string): void { + if (this._isDev) { + this._showMessageToUser(severity, msg); + } else { + this._logMessageInConsole(severity, msg); + } + } +} + +export class Logger implements ILog { + + private readonly _messageHandler: (severity: Severity, source: string, message: string) => void; + + constructor( + messageHandler: (severity: Severity, source: string, message: string) => void + ) { + this._messageHandler = messageHandler; + } + + public error(source: string, message: string): void { + this._messageHandler(Severity.Error, source, message); + } + + public warn(source: string, message: string): void { + this._messageHandler(Severity.Warning, source, message); + } + + public info(source: string, message: string): void { + this._messageHandler(Severity.Info, source, message); + } }