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

@@ -8,15 +8,14 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { toDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import type * as vscode from 'vscode';
import { Cache } from './cache';
import { ChainedCacheId, ExtHostUriOpener, ExtHostUriOpenersShape, IMainContext, MainContext, MainThreadUriOpenersShape } from './extHost.protocol';
import { ExtHostUriOpenersShape, IMainContext, MainContext, MainThreadUriOpenersShape } from './extHost.protocol';
interface OpenerEntry {
readonly extension: ExtensionIdentifier;
readonly schemes: ReadonlySet<string>;
readonly opener: vscode.ExternalUriOpener;
readonly metadata: vscode.ExternalUriOpenerMetadata;
}
export class ExtHostUriOpeners implements ExtHostUriOpenersShape {
@@ -24,23 +23,20 @@ export class ExtHostUriOpeners implements ExtHostUriOpenersShape {
private static HandlePool = 0;
private readonly _proxy: MainThreadUriOpenersShape;
private readonly _commands: ExtHostCommands;
private readonly _cache = new Cache<{ command: vscode.Command }>('CodeAction');
private readonly _openers = new Map<number, OpenerEntry>();
constructor(
mainContext: IMainContext,
commands: ExtHostCommands,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadUriOpeners);
this._commands = commands;
}
registerUriOpener(
extensionId: ExtensionIdentifier,
schemes: readonly string[],
opener: vscode.ExternalUriOpener,
metadata: vscode.ExternalUriOpenerMetadata,
): vscode.Disposable {
const handle = ExtHostUriOpeners.HandlePool++;
@@ -48,8 +44,9 @@ export class ExtHostUriOpeners implements ExtHostUriOpenersShape {
opener,
extension: extensionId,
schemes: new Set(schemes),
metadata
});
this._proxy.$registerUriOpener(handle, schemes, extensionId);
this._proxy.$registerUriOpener(handle, schemes, extensionId, metadata.label);
return toDisposable(() => {
this._openers.delete(handle);
@@ -57,47 +54,35 @@ export class ExtHostUriOpeners implements ExtHostUriOpenersShape {
});
}
async $getOpenersForUri(uriComponents: UriComponents, token: CancellationToken): Promise<{ cacheId: number, openers: Array<ExtHostUriOpener> }> {
async $getOpenersForUri(uriComponents: UriComponents, token: CancellationToken): Promise<readonly number[]> {
const uri = URI.revive(uriComponents);
const promises = Array.from(this._openers.values()).map(async ({ schemes, opener, extension }): Promise<{ command: vscode.Command, extension: ExtensionIdentifier } | undefined> => {
const promises = Array.from(this._openers.entries()).map(async ([handle, { schemes, opener, }]): Promise<number | undefined> => {
if (!schemes.has(uri.scheme)) {
return undefined;
}
try {
const result = await opener.openExternalUri(uri, {}, token);
if (result) {
return {
command: result,
extension
};
if (await opener.canOpenExternalUri(uri, token)) {
return handle;
}
} catch (e) {
console.log(e);
// noop
}
return undefined;
});
const commands = coalesce(await Promise.all(promises));
const cacheId = this._cache.add(commands);
return {
cacheId,
openers: commands.map((entry, i) => ({ title: entry.command.title, commandId: i, extensionId: entry.extension })),
};
return (await Promise.all(promises)).filter(handle => typeof handle === 'number') as number[];
}
async $openUri(id: ChainedCacheId, uri: UriComponents): Promise<void> {
const entry = this._cache.get(id[0], id[1]);
async $openUri(handle: number, context: { resolveUri: UriComponents, sourceUri: UriComponents }, token: CancellationToken): Promise<void> {
const entry = this._openers.get(handle);
if (!entry) {
return;
throw new Error(`Unknown opener handle: '${handle}'`);
}
return this._commands.executeCommand(entry.command.command, URI.revive(uri), ...(entry.command.arguments || []));
}
$releaseOpener(cacheId: number): void {
this._cache.delete(cacheId);
return entry.opener.openExternalUri(URI.revive(context.resolveUri), {
sourceUri: URI.revive(context.sourceUri)
}, token);
}
}