diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 92ef1a7504628afa2851e4b954a369749562be55..42c242bb579b33a8682b449f7ab4b4afc5b092e9 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -24,7 +24,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IStateService } from 'vs/platform/state/node/state'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IURLService } from 'vs/platform/url/common/url'; +import { IOpenURLOptions, IURLService } from 'vs/platform/url/common/url'; import { URLHandlerChannelClient, URLHandlerRouter } from 'vs/platform/url/common/urlIpc'; import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -73,7 +73,6 @@ import { INativeHostMainService, NativeHostMainService } from 'vs/platform/nativ import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService'; import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { withNullAsUndefined } from 'vs/base/common/types'; -import { coalesce } from 'vs/base/common/arrays'; import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels'; import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService'; import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService'; @@ -663,30 +662,32 @@ export class CodeApplication extends Disposable { // Check for initial URLs to handle from protocol link invocations const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = []; - const pendingProtocolLinksToHandle = coalesce([ - + const pendingProtocolLinksToHandle = [ // Windows/Linux: protocol handler invokes CLI with --open-url ...this.environmentService.args['open-url'] ? this.environmentService.args._urls || [] : [], // macOS: open-url events ...((global).getOpenUrls() || []) as string[] - ].map(pendingUrlToHandle => { + ].map(url => { try { - return URI.parse(pendingUrlToHandle); - } catch (error) { - return undefined; + return { uri: URI.parse(url), url }; + } catch { + return null; + } + }).filter((obj): obj is { uri: URI, url: string } => { + if (!obj) { + return false; } - })).filter(pendingUriToHandle => { // If URI should be blocked, filter it out - if (this.shouldBlockURI(pendingUriToHandle)) { + if (this.shouldBlockURI(obj.uri)) { return false; } // Filter out any protocol link that wants to open as window so that // we open the right set of windows on startup and not restore the // previous workspace too. - const windowOpenable = this.getWindowOpenableFromProtocolLink(pendingUriToHandle); + const windowOpenable = this.getWindowOpenableFromProtocolLink(obj.uri); if (windowOpenable) { pendingWindowOpenablesFromProtocolLinks.push(windowOpenable); @@ -700,7 +701,7 @@ export class CodeApplication extends Disposable { const app = this; const environmentService = this.environmentService; urlService.registerHandler({ - async handleURL(uri: URI): Promise { + async handleURL(uri: URI, options?: IOpenURLOptions): Promise { // If URI should be blocked, behave as if it's handled if (app.shouldBlockURI(uri)) { @@ -732,7 +733,7 @@ export class CodeApplication extends Disposable { await window.ready(); - return urlService.open(uri); + return urlService.open(uri, options); } return false; diff --git a/src/vs/platform/launch/electron-main/launchMainService.ts b/src/vs/platform/launch/electron-main/launchMainService.ts index 2e48223e5685c04fa1d4633dbf6acc5ab36bbd21..9b3d656639431532ad10361c6089a4c46ac80272 100644 --- a/src/vs/platform/launch/electron-main/launchMainService.ts +++ b/src/vs/platform/launch/electron-main/launchMainService.ts @@ -35,14 +35,14 @@ export interface IRemoteDiagnosticOptions { includeWorkspaceMetadata?: boolean; } -function parseOpenUrl(args: NativeParsedArgs): URI[] { +function parseOpenUrl(args: NativeParsedArgs): { uri: URI, url: string }[] { if (args['open-url'] && args._urls && args._urls.length > 0) { // --open-url must contain -- followed by the url(s) // process.argv is used over args._ as args._ are resolved to file paths at this point return coalesce(args._urls .map(url => { try { - return URI.parse(url); + return { uri: URI.parse(url), url }; } catch (err) { return null; } @@ -101,8 +101,8 @@ export class LaunchMainService implements ILaunchMainService { // Make sure a window is open, ready to receive the url event whenWindowReady.then(() => { - for (const url of urlsToOpen) { - this.urlService.open(url); + for (const { uri, url } of urlsToOpen) { + this.urlService.open(uri, { originalUrl: url }); } }); } diff --git a/src/vs/platform/url/common/url.ts b/src/vs/platform/url/common/url.ts index 2069fc48e51c5435a56dc1623f4a859dbdaed43e..5202226dd226ff4f556e464345db8698c547cc4d 100644 --- a/src/vs/platform/url/common/url.ts +++ b/src/vs/platform/url/common/url.ts @@ -18,6 +18,8 @@ export interface IOpenURLOptions { * might be shown to the user. */ trusted?: boolean; + + originalUrl?: string; } export interface IURLHandler { diff --git a/src/vs/platform/url/common/urlIpc.ts b/src/vs/platform/url/common/urlIpc.ts index 08d19ffd5be905917ac9574f33c4f25e592894a3..52fad0e241d525c61ce87aacf9e11b4941334234 100644 --- a/src/vs/platform/url/common/urlIpc.ts +++ b/src/vs/platform/url/common/urlIpc.ts @@ -19,7 +19,7 @@ export class URLHandlerChannel implements IServerChannel { call(_: unknown, command: string, arg?: any): Promise { switch (command) { - case 'handleURL': return this.handler.handleURL(URI.revive(arg)); + case 'handleURL': return this.handler.handleURL(URI.revive(arg[0]), arg[1]); } throw new Error(`Call not found: ${command}`); @@ -31,7 +31,7 @@ export class URLHandlerChannelClient implements IURLHandler { constructor(private channel: IChannel) { } handleURL(uri: URI, options?: IOpenURLOptions): Promise { - return this.channel.call('handleURL', uri.toJSON()); + return this.channel.call('handleURL', [uri.toJSON(), options]); } } diff --git a/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts index efc15e0296579972e0379cfa72910b59cc38d8f7..50ca2ea249c0416a47667bf9d66eb3d69256dd15 100644 --- a/src/vs/platform/url/electron-main/electronUrlListener.ts +++ b/src/vs/platform/url/electron-main/electronUrlListener.ts @@ -34,13 +34,13 @@ function uriFromRawUrl(url: string): URI | null { */ export class ElectronURLListener { - private uris: URI[] = []; + private uris: { uri: URI, url: string }[] = []; private retryCount = 0; private flushDisposable: IDisposable = Disposable.None; private disposables = new DisposableStore(); constructor( - initialUrisToHandle: URI[], + initialUrisToHandle: { uri: URI, url: string }[], private readonly urlService: IURLService, windowsMainService: IWindowsMainService, environmentService: IEnvironmentMainService @@ -64,8 +64,15 @@ export class ElectronURLListener { return url; }); - const onOpenUrl = Event.filter(Event.map(onOpenElectronUrl, uriFromRawUrl), (uri): uri is URI => !!uri); - onOpenUrl(this.urlService.open, this.urlService, this.disposables); + this.disposables.add(onOpenElectronUrl(url => { + const uri = uriFromRawUrl(url); + + if (!uri) { + return; + } + + this.urlService.open(uri, { originalUrl: url }); + })); // Send initial links to the window once it has loaded const isWindowReady = windowsMainService.getWindows() @@ -84,13 +91,13 @@ export class ElectronURLListener { return; } - const uris: URI[] = []; + const uris: { uri: URI, url: string }[] = []; - for (const uri of this.uris) { - const handled = await this.urlService.open(uri); + for (const obj of this.uris) { + const handled = await this.urlService.open(obj.uri, { originalUrl: obj.url }); if (!handled) { - uris.push(uri); + uris.push(obj); } } diff --git a/src/vs/workbench/contrib/url/browser/url.contribution.ts b/src/vs/workbench/contrib/url/browser/url.contribution.ts index 949c9980357a83cc436464c6b476595bd09149a2..5d3a01480bd6585efe579f8358de5c07f36769e3 100644 --- a/src/vs/workbench/contrib/url/browser/url.contribution.ts +++ b/src/vs/workbench/contrib/url/browser/url.contribution.ts @@ -37,7 +37,7 @@ class OpenUrlAction extends Action2 { return quickInputService.input({ prompt: localize('urlToOpen', "URL to open") }).then(input => { if (input) { const uri = URI.parse(input); - urlService.open(uri, { trusted: true }); + urlService.open(uri, { originalUrl: input }); } }); }