Skip to content

Commit 94a1ec7

Browse files
authored
Merge pull request microsoft#165783 from microsoft/dev/joyceerhl/gothic-wallaby
Generate implicit activation events from declared extension contributions
2 parents 91c7eaf + 77accd5 commit 94a1ec7

File tree

11 files changed

+98
-29
lines changed

11 files changed

+98
-29
lines changed

src/vs/platform/extensionManagement/common/extensionsScannerService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { IExtensionsProfileScannerService, IScannedProfileExtension } from 'vs/p
3636
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
3737
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
3838
import { localizeManifest } from 'vs/platform/extensionManagement/common/extensionNls';
39+
import { ImplicitActivationEvents } from 'vs/platform/extensionManagement/common/implicitActivationEvents';
3940

4041
export type IScannedExtensionManifest = IRelaxedExtensionManifest & { __metadata?: Metadata };
4142

@@ -577,6 +578,7 @@ class ExtensionsScanner extends Disposable {
577578
const identifier = metadata?.id ? { id, uuid: metadata.id } : { id };
578579
const type = metadata?.isSystem ? ExtensionType.System : input.type;
579580
const isBuiltin = type === ExtensionType.System || !!metadata?.isBuiltin;
581+
ImplicitActivationEvents.updateManifest(manifest);
580582
manifest = await this.translateManifest(input.location, manifest, ExtensionScannerInput.createNlsConfiguration(input));
581583
const extension = {
582584
type,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { onUnexpectedError } from 'vs/base/common/errors';
7+
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
8+
9+
export interface IActivationEventsGenerator<T> {
10+
(contribution: T, result: { push(item: string): void }): void;
11+
}
12+
13+
export class ImplicitActivationEventsImpl {
14+
15+
private readonly _generators = new Map<string, IActivationEventsGenerator<any>>();
16+
17+
public register<T>(extensionPointName: string, generator: IActivationEventsGenerator<T>): void {
18+
this._generators.set(extensionPointName, generator);
19+
}
20+
21+
public updateManifest(manifest: IExtensionManifest) {
22+
if (!Array.isArray(manifest.activationEvents) || !manifest.contributes) {
23+
return;
24+
}
25+
if (typeof manifest.main === 'undefined' && typeof manifest.browser === 'undefined') {
26+
return;
27+
}
28+
29+
for (const extPointName in manifest.contributes) {
30+
const generator = this._generators.get(extPointName);
31+
if (!generator) {
32+
// There's no generator for this extension point
33+
continue;
34+
}
35+
const contrib = (manifest.contributes as any)[extPointName];
36+
const contribArr = Array.isArray(contrib) ? contrib : [contrib];
37+
try {
38+
generator(contribArr, manifest.activationEvents);
39+
} catch (err) {
40+
onUnexpectedError(err);
41+
}
42+
}
43+
}
44+
}
45+
46+
export const ImplicitActivationEvents: ImplicitActivationEventsImpl = new ImplicitActivationEventsImpl();

src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,14 @@ const notebookPreloadContribution: IJSONSchema = {
232232

233233
export const notebooksExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookEditorContribution[]>({
234234
extensionPoint: 'notebooks',
235-
jsonSchema: notebookProviderContribution
235+
jsonSchema: notebookProviderContribution,
236+
activationEventsGenerator: (contribs: INotebookEditorContribution[], result: { push(item: string): void }) => {
237+
for (const contrib of contribs) {
238+
if (contrib.type) {
239+
result.push(`onNotebookSerializer:${contrib.type}`);
240+
}
241+
}
242+
}
236243
});
237244

238245
export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookRendererContribution[]>({

src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -606,20 +606,7 @@ export class NotebookService extends Disposable implements INotebookService {
606606
}
607607

608608
await this._extensionService.whenInstalledExtensionsRegistered();
609-
610-
const info = this._notebookProviderInfoStore?.get(viewType);
611-
const waitFor: Promise<any>[] = [Event.toPromise(Event.filter(this.onAddViewType, () => {
612-
return this._notebookProviders.has(viewType);
613-
}))];
614-
615-
if (info && info.extension) {
616-
const extensionManifest = await this._extensionService.getExtension(info.extension.value);
617-
if (extensionManifest?.activationEvents && extensionManifest.activationEvents.indexOf(`onNotebook:${viewType}`) >= 0) {
618-
waitFor.push(this._extensionService._activateById(info.extension, { startup: false, activationEvent: `onNotebook:${viewType}}`, extensionId: info.extension }));
619-
}
620-
}
621-
622-
await Promise.race(waitFor);
609+
await this._extensionService.activateByEvent(`onNotebookSerializer:${viewType}`);
623610

624611
return this._notebookProviders.has(viewType);
625612
}

src/vs/workbench/contrib/terminal/common/terminal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Event } from 'vs/base/common/event';
88
import { IDisposable } from 'vs/base/common/lifecycle';
99
import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform';
1010
import { IExtensionPointDescriptor } from 'vs/workbench/services/extensions/common/extensionsRegistry';
11-
import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, ITerminalProfileObject, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, TerminalLocationString, IProcessProperty, TitleEventSource, ProcessPropertyType, IFixedTerminalDimensions, IExtensionTerminalProfile, ICreateContributedTerminalProfileOptions, IProcessPropertyMap, ITerminalEnvironment, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal';
11+
import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, ITerminalProfileObject, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, TerminalLocationString, IProcessProperty, TitleEventSource, ProcessPropertyType, IFixedTerminalDimensions, IExtensionTerminalProfile, ICreateContributedTerminalProfileOptions, IProcessPropertyMap, ITerminalEnvironment, ITerminalProcessOptions, ITerminalContributions } from 'vs/platform/terminal/common/terminal';
1212
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
1313
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1414
import { URI } from 'vs/base/common/uri';
@@ -710,7 +710,7 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
710710
'workbench.action.toggleMaximizedPanel'
711711
];
712712

713-
export const terminalContributionsDescriptor: IExtensionPointDescriptor = {
713+
export const terminalContributionsDescriptor: IExtensionPointDescriptor<ITerminalContributions> = {
714714
extensionPoint: 'terminal',
715715
defaultExtensionKind: ['workspace'],
716716
jsonSchema: {

src/vs/workbench/services/actions/common/menusExtensionPoint.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,14 @@ const _commandRegistrations = new DisposableStore();
623623

624624
export const commandsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.IUserFriendlyCommand[]>({
625625
extensionPoint: 'commands',
626-
jsonSchema: schema.commandsContribution
626+
jsonSchema: schema.commandsContribution,
627+
activationEventsGenerator: (contribs: schema.IUserFriendlyCommand[], result: { push(item: string): void }) => {
628+
for (const contrib of contribs) {
629+
if (contrib.command) {
630+
result.push(`onCommand:${contrib.command}`);
631+
}
632+
}
633+
}
627634
});
628635

629636
commandsExtensionPoint.setHandler(extensions => {

src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLo
1515
import { IProductService } from 'vs/platform/product/common/productService';
1616
import { ITranslations, localizeManifest } from 'vs/platform/extensionManagement/common/extensionNls';
1717
import { ILogService } from 'vs/platform/log/common/log';
18+
import { ImplicitActivationEvents } from 'vs/platform/extensionManagement/common/implicitActivationEvents';
1819

1920
interface IBundledExtension {
2021
extensionPath: string;
@@ -74,6 +75,7 @@ export class BuiltinExtensionsScannerService implements IBuiltinExtensionsScanne
7475
}
7576
browserNlsBundleUris.en = uriIdentityService.extUri.resolvePath(builtinExtensionsServiceUrl!, e.browserNlsMetadataPath);
7677
}
78+
ImplicitActivationEvents.updateManifest(e.packageJSON);
7779
return {
7880
identifier: { id },
7981
location: uriIdentityService.extUri.joinPath(builtinExtensionsServiceUrl!, e.extensionPath),

src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { IStringDictionary } from 'vs/base/common/collections';
4343
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
4444
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
4545
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
46+
import { ImplicitActivationEvents } from 'vs/platform/extensionManagement/common/implicitActivationEvents';
4647

4748
type GalleryExtensionInfo = { readonly id: string; preRelease?: boolean; migrateStorageFrom?: string };
4849
type ExtensionInfo = { readonly id: string; preRelease: boolean };
@@ -662,6 +663,8 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
662663
};
663664
}
664665

666+
ImplicitActivationEvents.updateManifest(manifest);
667+
665668
const packageNLSUri = webExtension.packageNLSUris?.get(Language.value().toLowerCase());
666669
if (packageNLSUri || webExtension.fallbackPackageNLSUri) {
667670
manifest = packageNLSUri

src/vs/workbench/services/extensions/common/extensions.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -556,12 +556,6 @@ export interface IExtensionService {
556556
* @param env New properties for the remote extension host
557557
*/
558558
setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
559-
560-
/**
561-
* Please do not use!
562-
* (This is public such that the extension host process can coordinate with and call back in the IExtensionService)
563-
*/
564-
_activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
565559
}
566560

567561
export interface IInternalExtensionService {
@@ -626,5 +620,4 @@ export class NullExtensionService implements IExtensionService {
626620
async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> { }
627621
canAddExtension(): boolean { return false; }
628622
canRemoveExtension(): boolean { return false; }
629-
_activateById(_extensionId: ExtensionIdentifier, _reason: ExtensionActivationReason): Promise<void> { return Promise.resolve(); }
630623
}

src/vs/workbench/services/extensions/common/extensionsRegistry.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES } from
1515
import { ExtensionKind } from 'vs/platform/environment/common/environment';
1616
import { allApiProposals } from 'vs/workbench/services/extensions/common/extensionsApiProposals';
1717
import { productSchemaId } from 'vs/platform/product/common/productService';
18+
import { ImplicitActivationEvents, IActivationEventsGenerator } from 'vs/platform/extensionManagement/common/implicitActivationEvents';
1819

1920
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
2021

@@ -559,23 +560,33 @@ export const schema: IJSONSchema = {
559560
}
560561
};
561562

562-
export interface IExtensionPointDescriptor {
563+
export type toArray<T> = T extends Array<any> ? T : T[];
564+
565+
export interface IExtensionPointDescriptor<T> {
563566
extensionPoint: string;
564567
deps?: IExtensionPoint<any>[];
565568
jsonSchema: IJSONSchema;
566569
defaultExtensionKind?: ExtensionKind[];
570+
/**
571+
* A function which runs before the extension point has been validated and which
572+
* can should collect automatic activation events from the contribution.
573+
*/
574+
activationEventsGenerator?: IActivationEventsGenerator<toArray<T>>;
567575
}
568576

569577
export class ExtensionsRegistryImpl {
570578

571579
private readonly _extensionPoints = new Map<string, ExtensionPoint<any>>();
572580

573-
public registerExtensionPoint<T>(desc: IExtensionPointDescriptor): IExtensionPoint<T> {
581+
public registerExtensionPoint<T>(desc: IExtensionPointDescriptor<T>): IExtensionPoint<T> {
574582
if (this._extensionPoints.has(desc.extensionPoint)) {
575583
throw new Error('Duplicate extension point: ' + desc.extensionPoint);
576584
}
577585
const result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind);
578586
this._extensionPoints.set(desc.extensionPoint, result);
587+
if (desc.activationEventsGenerator) {
588+
ImplicitActivationEvents.register(desc.extensionPoint, desc.activationEventsGenerator);
589+
}
579590

580591
schema.properties!['contributes'].properties![desc.extensionPoint] = desc.jsonSchema;
581592
schemaRegistry.registerSchema(schemaId, schema);

0 commit comments

Comments
 (0)