diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index c42f82fdb26dea91248a5c0d53894f3b971a02db..8a122c18fc5da8c2e76f14ca234b83893571dcaa 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -13,7 +13,7 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IOpener, IOpenerService, IValidator } from 'vs/platform/opener/common/opener'; +import { IOpener, IOpenerService, IValidator, IExternalUriResolver } from 'vs/platform/opener/common/opener'; export class OpenerService extends Disposable implements IOpenerService { @@ -21,6 +21,7 @@ export class OpenerService extends Disposable implements IOpenerService { private readonly _openers = new LinkedList(); private readonly _validators = new LinkedList(); + private readonly _resolvers = new LinkedList(); constructor( @ICodeEditorService private readonly _editorService: ICodeEditorService, @@ -39,6 +40,11 @@ export class OpenerService extends Disposable implements IOpenerService { return { dispose: remove }; } + registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable { + const remove = this._resolvers.push(resolver); + return { dispose: remove }; + } + async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise { // no scheme ?!? if (!resource.scheme) { @@ -118,7 +124,11 @@ export class OpenerService extends Disposable implements IOpenerService { } } - private _doOpenExternal(resource: URI): Promise { + private async _doOpenExternal(resource: URI): Promise { + for (const resolver of this._resolvers.toArray()) { + resource = await resolver.resolveExternalUri(resource); + } + dom.windowOpenNoOpener(encodeURI(resource.toString(true))); return Promise.resolve(true); diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 8563f3fa2af386595e7976939b8eea6da0810382..0c9a243a952c60eb17819337cb5fd57e483d7c82 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -5,7 +5,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; export const IOpenerService = createDecorator('openerService'); @@ -18,6 +18,10 @@ export interface IValidator { shouldOpen(resource: URI): Promise; } +export interface IExternalUriResolver { + resolveExternalUri(resource: URI): Promise; +} + export interface IOpenerService { _serviceBrand: undefined; @@ -29,10 +33,15 @@ export interface IOpenerService { /** * Register a participant that can validate if the URI resource be opened. - * validators are run before openers. + * Validators are run before openers. */ registerValidator(validator: IValidator): IDisposable; + /** + * Register a participant that can resolve an external URI resource to be opened. + */ + registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable; + /** * Opens a resource, like a webaddress, a document uri, or executes command. * @@ -45,7 +54,8 @@ export interface IOpenerService { export const NullOpenerService: IOpenerService = Object.freeze({ _serviceBrand: undefined, - registerOpener() { return { dispose() { } }; }, - registerValidator() { return { dispose() { } }; }, + registerOpener() { return Disposable.None; }, + registerValidator() { return Disposable.None; }, + registerExternalUriResolver() { return Disposable.None; }, open() { return Promise.resolve(false); }, }); diff --git a/src/vs/workbench/contrib/url/common/externalUriResolver.ts b/src/vs/workbench/contrib/url/common/externalUriResolver.ts new file mode 100644 index 0000000000000000000000000000000000000000..454d76644b6231f3c976029122a8b68806262a93 --- /dev/null +++ b/src/vs/workbench/contrib/url/common/externalUriResolver.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +export class ExternalUriResolverContribution extends Disposable implements IWorkbenchContribution { + constructor( + @IOpenerService _openerService: IOpenerService, + @IWorkbenchEnvironmentService _workbenchEnvironmentService: IWorkbenchEnvironmentService, + ) { + super(); + + if (_workbenchEnvironmentService.options && _workbenchEnvironmentService.options.resolveExternalUri) { + this._register(_openerService.registerExternalUriResolver({ + resolveExternalUri: async (resource) => { + return _workbenchEnvironmentService.options!.resolveExternalUri!(resource); + } + })); + } + } +} diff --git a/src/vs/workbench/contrib/url/common/url.contribution.ts b/src/vs/workbench/contrib/url/common/url.contribution.ts index f51bd6d3f03b5678883f4ad9a31d58470d0c5853..e299262de0573f1a0df496c4b5db1589e66344aa 100644 --- a/src/vs/workbench/contrib/url/common/url.contribution.ts +++ b/src/vs/workbench/contrib/url/common/url.contribution.ts @@ -14,9 +14,10 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IURLService } from 'vs/platform/url/common/url'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { ExternalUriResolverContribution } from 'vs/workbench/contrib/url/common/externalUriResolver'; import { configureTrustedDomainSettingsCommand } from 'vs/workbench/contrib/url/common/trustedDomains'; -import { OpenerValidatorContributions } from 'vs/workbench/contrib/url/common/trustedDomainsValidator'; import { TrustedDomainsFileSystemProvider } from 'vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider'; +import { OpenerValidatorContributions } from 'vs/workbench/contrib/url/common/trustedDomainsValidator'; export class OpenUrlAction extends Action { static readonly ID = 'workbench.action.url.openUrl'; @@ -65,3 +66,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi TrustedDomainsFileSystemProvider, LifecyclePhase.Ready ); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( + ExternalUriResolverContribution, + LifecyclePhase.Ready +); diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index cd4351d60167c3e7e8f6bd3d3c0315356bfef773..38bb092333d12bd40b4b40e9242ba84ac3d563d9 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -90,6 +90,11 @@ interface IWorkbenchConstructionOptions { * Experimental: Support for update reporting. */ updateProvider?: IUpdateProvider; + + /** + * Experimental: Resolves an external uri before it is opened. + */ + readonly resolveExternalUri?: (uri: URI) => Promise; } /**