Reworking external opener implementation to allow configured openers to be called directly without a canOpen check

If the user has configured a specific external uri opener, we should always try to use that without first calling `canOpen` to filter down the list of openers.

This change also adds `ExternalUriOpenerEnablement` which allows an opener to mark itself as the preferred opener for a given uri. If only a single preferred opener is returned, it will be used automatically for that uri (although user configuration can override this)
This commit is contained in:
Matt Bierner
2021-01-13 21:40:49 -08:00
parent 5b1e59c636
commit 5d6cba5cbc
15 changed files with 397 additions and 172 deletions

View File

@@ -6,6 +6,7 @@
import { CancellationToken } from 'vs/base/common/cancellation';
import { toDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import type * as vscode from 'vscode';
import { ExtHostUriOpenersShape, IMainContext, MainContext, MainThreadUriOpenersShape } from './extHost.protocol';
@@ -54,35 +55,23 @@ export class ExtHostUriOpeners implements ExtHostUriOpenersShape {
});
}
async $getOpenersForUri(uriComponents: UriComponents, token: CancellationToken): Promise<readonly string[]> {
async $canOpenUri(id: string, uriComponents: UriComponents, token: CancellationToken): Promise<modes.ExternalUriOpenerEnablement> {
const entry = this._openers.get(id);
if (!entry) {
throw new Error(`Unknown opener with id: ${id}`);
}
const uri = URI.revive(uriComponents);
const promises = Array.from(this._openers.entries())
.map(async ([id, { schemes, opener, }]): Promise<string | undefined> => {
if (!schemes.has(uri.scheme)) {
return undefined;
}
try {
if (await opener.canOpenExternalUri(uri, token)) {
return id;
}
} catch (e) {
console.log(e);
// noop
}
return undefined;
});
return (await Promise.all(promises)).filter(handle => typeof handle === 'string') as string[];
const result = await entry.opener.canOpenExternalUri(uri, token);
return result ? result : modes.ExternalUriOpenerEnablement.Disabled;
}
async $openUri(id: string, context: { resolveUri: UriComponents, sourceUri: UriComponents }, token: CancellationToken): Promise<void> {
async $openUri(id: string, context: { resolvedUri: UriComponents, sourceUri: UriComponents }, token: CancellationToken): Promise<void> {
const entry = this._openers.get(id);
if (!entry) {
throw new Error(`Unknown opener id: '${id}'`);
}
return entry.opener.openExternalUri(URI.revive(context.resolveUri), {
return entry.opener.openExternalUri(URI.revive(context.resolvedUri), {
sourceUri: URI.revive(context.sourceUri)
}, token);
}