Rework opener api proposal

For #109277

- Add more explicit two phase structure to api
- Make opener pass along label when registered
This commit is contained in:
Matt Bierner
2021-01-12 16:14:20 -08:00
parent 6184addcd1
commit 47a135e715
7 changed files with 159 additions and 169 deletions

View File

@@ -7,13 +7,16 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { Disposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { ExtHostContext, ExtHostUriOpener, ExtHostUriOpenersShape, IExtHostContext, MainContext, MainThreadUriOpenersShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExternalOpenerEntry, ExternalOpenerSet, IExternalOpenerProvider, IExternalUriOpenerService } from 'vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtHostContext, ExtHostUriOpenersShape, IExtHostContext, MainContext, MainThreadUriOpenersShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExternalOpenerEntry, IExternalOpenerProvider, IExternalUriOpenerService } from 'vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { extHostNamedCustomer } from '../common/extHostCustomers';
interface RegisteredOpenerMetadata {
readonly schemes: ReadonlySet<string>;
readonly extensionId: ExtensionIdentifier;
readonly label: string;
}
@extHostNamedCustomer(MainContext.MainThreadUriOpeners)
@@ -33,12 +36,12 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe
this._register(this.externalUriOpenerService.registerExternalOpenerProvider(this));
}
public async provideExternalOpeners(href: string | URI): Promise<ExternalOpenerSet | undefined> {
public async provideExternalOpeners(href: string | URI): Promise<readonly ExternalOpenerEntry[]> {
const targetUri = typeof href === 'string' ? URI.parse(href) : href;
// Currently we only allow openers for http and https urls
if (targetUri.scheme !== Schemas.http && targetUri.scheme !== Schemas.https) {
return undefined;
return [];
}
await this.extensionService.activateByEvent(`onUriOpen:${targetUri.scheme}`);
@@ -46,41 +49,38 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe
// If there are no handlers there is no point in making a round trip
const hasHandler = Array.from(this.registeredOpeners.values()).some(x => x.schemes.has(targetUri.scheme));
if (!hasHandler) {
return undefined;
return [];
}
const { openers, cacheId } = await this.proxy.$getOpenersForUri(targetUri, CancellationToken.None);
const openerHandles = await this.proxy.$getOpenersForUri(targetUri, CancellationToken.None);
if (openers.length === 0) {
this.proxy.$releaseOpener(cacheId);
return undefined;
} else {
return {
openers: openers.map(opener => this.openerForCommand(cacheId, opener)),
dispose: () => {
this.proxy.$releaseOpener(cacheId);
}
};
}
return openerHandles.map(handle => this.openerForCommand(handle, targetUri));
}
private openerForCommand(
cacheId: number,
opener: ExtHostUriOpener
): ExternalOpenerEntry {
private openerForCommand(openerHandle: number, sourceUri: URI): ExternalOpenerEntry {
const metadata = this.registeredOpeners.get(openerHandle)!;
return {
id: opener.extensionId.value,
label: opener.title,
id: metadata.extensionId.value,
label: metadata.label,
openExternal: async (href) => {
const targetUri = URI.parse(href);
await this.proxy.$openUri([cacheId, opener.commandId], targetUri);
const resolveUri = URI.parse(href);
await this.proxy.$openUri(openerHandle, { resolveUri, sourceUri }, CancellationToken.None);
return true;
},
};
}
async $registerUriOpener(handle: number, schemes: readonly string[]): Promise<void> {
this.registeredOpeners.set(handle, { schemes: new Set(schemes) });
async $registerUriOpener(
handle: number,
schemes: readonly string[],
extensionId: ExtensionIdentifier,
label: string,
): Promise<void> {
this.registeredOpeners.set(handle, {
schemes: new Set(schemes),
label,
extensionId,
});
}
async $unregisterUriOpener(handle: number): Promise<void> {