diff --git a/src/vs/workbench/api/browser/mainThreadUriOpeners.ts b/src/vs/workbench/api/browser/mainThreadUriOpeners.ts index c4c5c42bbb0..e5627d11389 100644 --- a/src/vs/workbench/api/browser/mainThreadUriOpeners.ts +++ b/src/vs/workbench/api/browser/mainThreadUriOpeners.ts @@ -3,15 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Action } from 'vs/base/common/actions'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ExtHostContext, ExtHostUriOpenersShape, IExtHostContext, MainContext, MainThreadUriOpenersShape } from 'vs/workbench/api/common/extHost.protocol'; +import { defaultExternalUriOpenerId } from 'vs/workbench/contrib/externalUriOpener/common/configuration'; import { ContributedExternalUriOpenersStore } from 'vs/workbench/contrib/externalUriOpener/common/contributedOpeners'; import { IExternalOpenerProvider, IExternalUriOpener, IExternalUriOpenerService } from 'vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -35,6 +38,7 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe @IStorageService storageService: IStorageService, @IExternalUriOpenerService externalUriOpenerService: IExternalUriOpenerService, @IExtensionService private readonly extensionService: IExtensionService, + @IOpenerService private readonly openerService: IOpenerService, @INotificationService private readonly notificationService: INotificationService, ) { super(); @@ -73,7 +77,23 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe await this.proxy.$openUri(id, { resolvedUri: uri, sourceUri: ctx.sourceUri }, token); } catch (e) { if (!isPromiseCanceledError(e)) { - this.notificationService.error(localize('openerFailedMessage', "Could not open uri: {0}", e.toString())); + const openDefaultAction = new Action('default', localize('openerFailedUseDefault', "Open using default opener"), undefined, undefined, () => { + return this.openerService.open(uri, { + allowTunneling: false, + allowContributedOpeners: defaultExternalUriOpenerId, + }); + }); + openDefaultAction.tooltip = uri.toString(); + + this.notificationService.notify({ + severity: Severity.Error, + message: localize('openerFailedMessage', 'Could not open uri with \'{0}\': {1}', id, e.toString()), + actions: { + primary: [ + openDefaultAction + ] + } + }); } } return true;