提交 2fd817b5 编写于 作者: B Benjamin Pasero

introduce extensions registered event (for #38323)

上级 9b829cde
......@@ -23,6 +23,6 @@ export class MenuService implements IMenuService {
}
createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
return new Menu(id, this._extensionService.onReady(), this._commandService, contextKeyService);
return new Menu(id, this._extensionService.whenInstalledExtensionsRegistered(), this._commandService, contextKeyService);
}
}
......@@ -13,17 +13,23 @@ import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKe
import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtensionPointContribution, IExtensionDescription, IExtensionsStatus, IExtensionService, ActivationTimes } from 'vs/platform/extensions/common/extensions';
import Event, { Emitter } from 'vs/base/common/event';
// --- service instances
class MockExtensionService implements IExtensionService {
public _serviceBrand: any;
private _onDidRegisterExtensions = new Emitter<IExtensionDescription[]>();
public get onDidRegisterExtensions(): Event<IExtensionDescription[]> {
return this._onDidRegisterExtensions.event;
}
public activateByEvent(activationEvent: string): TPromise<void> {
throw new Error('Not implemented');
}
public onReady(): TPromise<boolean> {
public whenInstalledExtensionsRegistered(): TPromise<boolean> {
return TPromise.as(true);
}
......
......@@ -27,7 +27,7 @@ export class CommandService extends Disposable implements ICommandService {
@IContextKeyService private _contextKeyService: IContextKeyService
) {
super();
this._extensionService.onReady().then(value => this._extensionHostIsReady = value);
this._extensionService.whenInstalledExtensionsRegistered().then(value => this._extensionHostIsReady = value);
}
executeCommand<T>(id: string, ...args: any[]): TPromise<T> {
......
......@@ -15,13 +15,18 @@ import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistr
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { SimpleConfigurationService } from 'vs/editor/standalone/browser/simpleServices';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import Event, { Emitter } from 'vs/base/common/event';
class SimpleExtensionService implements IExtensionService {
_serviceBrand: any;
private _onDidRegisterExtensions = new Emitter<IExtensionDescription[]>();
get onDidRegisterExtensions(): Event<IExtensionDescription[]> {
return this._onDidRegisterExtensions.event;
}
activateByEvent(activationEvent: string): TPromise<void> {
return this.onReady().then(() => { });
return this.whenInstalledExtensionsRegistered().then(() => { });
}
onReady(): TPromise<boolean> {
whenInstalledExtensionsRegistered(): TPromise<boolean> {
return TPromise.as(true);
}
readExtensionPointContributions<T>(extPoint: IExtensionPoint<T>): TPromise<ExtensionPointContribution<T>[]> {
......@@ -96,7 +101,7 @@ suite('CommandService', function () {
let reg = CommandsRegistry.registerCommand('bar', () => callCounter += 1);
let service = new CommandService(new InstantiationService(), new class extends SimpleExtensionService {
onReady() {
whenInstalledExtensionsRegistered() {
return new TPromise<boolean>(_resolve => { /*ignore*/ });
}
}, new ContextKeyService(new SimpleConfigurationService()));
......
......@@ -8,6 +8,7 @@ import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry';
import Event from 'vs/base/common/event';
export interface IExtensionDescription {
readonly id: string;
......@@ -70,15 +71,25 @@ export class ExtensionPointContribution<T> {
export interface IExtensionService {
_serviceBrand: any;
/**
* An event emitted when extensions are registered after their extension points got handled.
*
* This event will also fire on startup to signal the installed extensions.
*
* @returns the extensions that got registered
*/
onDidRegisterExtensions: Event<IExtensionDescription[]>;
/**
* Send an activation event and activate interested extensions.
*/
activateByEvent(activationEvent: string): TPromise<void>;
/**
* Block on this signal any interactions with extensions.
* An promise that resolves when the installed extensions are registered after
* their extension points got handled.
*/
onReady(): TPromise<boolean>;
whenInstalledExtensionsRegistered(): TPromise<boolean>;
/**
* Return all registered extensions
......
......@@ -65,8 +65,8 @@ export class ResourceLabel extends IconLabel {
private registerListeners(): void {
// update when extensions are loaded with potentially new languages
this.extensionService.onReady().then(() => this.render(true /* clear cache */));
// update when extensions are registered with potentially new languages
this.toDispose.push(this.extensionService.onDidRegisterExtensions(() => this.render(true /* clear cache */)));
// react to model mode changes
this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e)));
......
......@@ -224,7 +224,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
private registerListeners(): void {
this.toUnbind.push(this.stacks.onModelChanged(e => this.onStacksChanged(e)));
this.toUnbind.push(this.editorGroupService.onTabOptionsChanged(options => this.updateTabOptions(options, true)));
this.extensionService.onReady().then(() => this.onExtensionsReady());
this.toUnbind.push(this.extensionService.onDidRegisterExtensions(() => this.onDidRegisterExtensions()));
}
private updateTabOptions(tabOptions: IEditorTabOptions, refresh?: boolean): void {
......@@ -276,7 +276,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
});
}
private onExtensionsReady(): void {
private onDidRegisterExtensions(): void {
// Up to date title areas
POSITIONS.forEach(position => this.getTitleAreaControl(position).update());
......
......@@ -238,7 +238,7 @@ export class ViewsViewlet extends PanelViewlet {
this._register(this.contextKeyService.onDidChangeContext(this.onContextChanged, this));
// Update headers after and title contributed views after available, since we read from cache in the beginning to know if the viewlet has single view or not. Ref #29609
this.extensionService.onReady().then(() => {
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
this.areExtensionsReady = true;
this.updateHeaders();
});
......
......@@ -261,7 +261,7 @@ export class WorkbenchShell {
this.timerService.workbenchStarted = Date.now();
this.timerService.restoreEditorsDuration = info.restoreEditorsDuration;
this.timerService.restoreViewletDuration = info.restoreViewletDuration;
this.extensionService.onReady().done(() => {
this.extensionService.whenInstalledExtensionsRegistered().done(() => {
/* __GDPR__
"startupTime" : {
"${include}": [
......@@ -377,7 +377,7 @@ export class WorkbenchShell {
serviceCollection.set(IExtensionService, this.extensionService);
this.timerService.beforeExtensionLoad = Date.now();
this.extensionService.onReady().done(() => {
this.extensionService.whenInstalledExtensionsRegistered().done(() => {
this.timerService.afterExtensionLoad = Date.now();
});
......
......@@ -306,7 +306,7 @@ export class ElectronWindow extends Themable {
};
// Send over all extension viewlets when extensions are ready
this.extensionService.onReady().then(() => {
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
ipc.send('vscode:extensionViewlets', JSON.stringify(this.viewletService.getViewlets().filter(v => !!v.extensionId).map(v => { return { id: v.id, label: v.name }; })));
});
......@@ -380,7 +380,7 @@ export class ElectronWindow extends Themable {
}
private resolveKeybindings(actionIds: string[]): TPromise<{ id: string; label: string, isNative: boolean; }[]> {
return TPromise.join([this.lifecycleService.when(LifecyclePhase.Running), this.extensionService.onReady()]).then(() => {
return TPromise.join([this.lifecycleService.when(LifecyclePhase.Running), this.extensionService.whenInstalledExtensionsRegistered()]).then(() => {
return arrays.coalesce(actionIds.map(id => {
const binding = this.keybindingService.lookupKeybinding(id);
if (!binding) {
......
......@@ -655,7 +655,7 @@ export class DebugService implements debug.IDebugService {
// make sure to save all files and that the configuration is up to date
return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(root).then(() =>
this.extensionService.onReady().then(() => {
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
if (this.model.getProcesses().length === 0) {
this.removeReplExpressions();
this.allProcesses.clear();
......
......@@ -167,7 +167,7 @@ export class BetterMergeDisabled implements IWorkbenchContribution {
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
@ITelemetryService telemetryService: ITelemetryService,
) {
extensionService.onReady().then(() => {
extensionService.whenInstalledExtensionsRegistered().then(() => {
if (storageService.getBoolean(BetterMergeDisabledNowKey, StorageScope.GLOBAL, false)) {
storageService.remove(BetterMergeDisabledNowKey, StorageScope.GLOBAL);
/* __GDPR__
......
......@@ -31,7 +31,7 @@ class StartupProfiler implements IWorkbenchContribution {
@IExtensionService extensionService: IExtensionService,
) {
// wait for everything to be ready
extensionService.onReady().then(() => {
extensionService.whenInstalledExtensionsRegistered().then(() => {
this._stopProfiling();
});
}
......
......@@ -143,7 +143,7 @@ export class KeybindingsEditorModel extends EditorModel {
}
public resolve(editorActionsLabels: { [id: string]: string; }): TPromise<EditorModel> {
return this.extensionService.onReady()
return this.extensionService.whenInstalledExtensionsRegistered()
.then(() => {
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
......
......@@ -44,7 +44,7 @@ suite('Keybindings Editor Model test', () => {
instantiationService = new TestInstantiationService();
instantiationService.stub(IKeybindingService, {});
instantiationService.stub(IExtensionService, {}, 'onReady', () => TPromise.as(null));
instantiationService.stub(IExtensionService, {}, 'whenInstalledExtensionsRegistered', () => TPromise.as(null));
testObject = instantiationService.createInstance(KeybindingsEditorModel, OS);
......
......@@ -103,7 +103,7 @@ class SnippetsService implements ISnippetsService {
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IExtensionService extensionService: IExtensionService,
) {
this._wait = Promise.resolve(extensionService.onReady());
this._wait = Promise.resolve(extensionService.whenInstalledExtensionsRegistered());
this._userSnippetsFolder = join(_environmentService.appSettingsHome, 'snippets');
this._prepUserSnippetsWatching();
this._prepExtensionSnippets();
......
......@@ -703,7 +703,7 @@ export class DefaultConfigurationExportHelper {
}
private writeConfigModelAndQuit(targetPath: string): TPromise<void> {
return this.extensionService.onReady()
return this.extensionService.whenInstalledExtensionsRegistered()
.then(() => this.writeConfigModel(targetPath))
.then(() => this.commandService.executeCommand('workbench.action.quit'))
.then(() => { });
......
......@@ -34,6 +34,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { mark, time } from 'vs/base/common/performance';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { Barrier } from 'vs/base/common/async';
import Event, { Emitter } from 'vs/base/common/event';
const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions'));
......@@ -54,8 +55,10 @@ const NO_OP_VOID_PROMISE = TPromise.wrap<void>(void 0);
export class ExtensionService implements IExtensionService {
public _serviceBrand: any;
private _onDidRegisterExtensions: Emitter<IExtensionDescription[]>;
private _registry: ExtensionDescriptionRegistry;
private readonly _barrier: Barrier;
private readonly _installedExtensionsReady: Barrier;
private readonly _isDev: boolean;
private readonly _extensionsStatus: { [id: string]: IExtensionsStatus };
private _allRequestedActivateEvents: { [activationEvent: string]: boolean; };
......@@ -87,11 +90,13 @@ export class ExtensionService implements IExtensionService {
@ILifecycleService lifecycleService: ILifecycleService
) {
this._registry = null;
this._barrier = new Barrier();
this._installedExtensionsReady = new Barrier();
this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment;
this._extensionsStatus = {};
this._allRequestedActivateEvents = Object.create(null);
this._onDidRegisterExtensions = new Emitter<IExtensionDescription[]>();
this._extensionHostProcessFinishedActivateEvents = Object.create(null);
this._extensionHostProcessActivationTimes = Object.create(null);
this._extensionHostProcessWorker = null;
......@@ -107,6 +112,10 @@ export class ExtensionService implements IExtensionService {
});
}
public get onDidRegisterExtensions(): Event<IExtensionDescription[]> {
return this._onDidRegisterExtensions.event;
}
public restartExtensionHost(): void {
this._stopExtensionHostProcess();
this._startExtensionHostProcess(Object.keys(this._allRequestedActivateEvents));
......@@ -222,7 +231,7 @@ export class ExtensionService implements IExtensionService {
// ---- begin IExtensionService
public activateByEvent(activationEvent: string): TPromise<void> {
if (this._barrier.isOpen()) {
if (this._installedExtensionsReady.isOpen()) {
// Extensions have been scanned and interpreted
if (!this._registry.containsActivationEvent(activationEvent)) {
......@@ -240,7 +249,7 @@ export class ExtensionService implements IExtensionService {
// Record the fact that this activationEvent was requested (in case of a restart)
this._allRequestedActivateEvents[activationEvent] = true;
return this._barrier.wait().then(() => this._activateByEvent(activationEvent));
return this._installedExtensionsReady.wait().then(() => this._activateByEvent(activationEvent));
}
}
......@@ -255,18 +264,18 @@ export class ExtensionService implements IExtensionService {
});
}
public onReady(): TPromise<boolean> {
return this._barrier.wait();
public whenInstalledExtensionsRegistered(): TPromise<boolean> {
return this._installedExtensionsReady.wait();
}
public getExtensions(): TPromise<IExtensionDescription[]> {
return this.onReady().then(() => {
return this._installedExtensionsReady.wait().then(() => {
return this._registry.getAllExtensionDescriptions();
});
}
public readExtensionPointContributions<T>(extPoint: IExtensionPoint<T>): TPromise<ExtensionPointContribution<T>[]> {
return this.onReady().then(() => {
return this._installedExtensionsReady.wait().then(() => {
let availableExtensions = this._registry.getAllExtensionDescriptions();
let result: ExtensionPointContribution<T>[] = [], resultLen = 0;
......@@ -343,7 +352,8 @@ export class ExtensionService implements IExtensionService {
}
}
mark('extensionHostReady');
this._barrier.open();
this._installedExtensionsReady.open();
this._onDidRegisterExtensions.fire(availableExtensions);
});
}
......
......@@ -138,7 +138,7 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl {
protected _onReady(): TPromise<boolean> {
if (!this._onReadyPromise) {
this._onReadyPromise = this._extensionService.onReady().then(() => {
this._onReadyPromise = this._extensionService.whenInstalledExtensionsRegistered().then(() => {
this.updateMime();
return true;
});
......
......@@ -133,7 +133,7 @@ export class ColorThemeStore {
}
public getColorThemes(): TPromise<IColorTheme[]> {
return this.extensionService.onReady().then(isReady => {
return this.extensionService.whenInstalledExtensionsRegistered().then(isReady => {
return this.extensionsColorThemes;
});
}
......
......@@ -129,7 +129,7 @@ export class FileIconThemeStore {
}
public getFileIconThemes(): TPromise<FileIconThemeData[]> {
return this.extensionService.onReady().then(isReady => {
return this.extensionService.whenInstalledExtensionsRegistered().then(isReady => {
return this.knownIconThemes;
});
}
......
......@@ -45,7 +45,7 @@ export class ViewletService implements IViewletService {
this.extensionViewletsLoadedPromiseComplete = c;
});
this.extensionService.onReady().then(() => {
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
const viewlets = this.viewletRegistry.getViewlets();
viewlets.forEach(v => {
if (!!v.extensionId) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册