Skip to content

Commit d5026ed

Browse files
author
Benjamin Pasero
committed
1 parent df0dd2e commit d5026ed

12 files changed

Lines changed: 63 additions & 84 deletions

File tree

src/vs/editor/browser/services/openerService.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ import { localize } from 'vs/nls';
1919
import { IProductService } from 'vs/platform/product/common/product';
2020
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
2121
import Severity from 'vs/base/common/severity';
22+
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
2223

2324
export class OpenerService implements IOpenerService {
2425

25-
_serviceBrand: any;
26+
_serviceBrand!: ServiceIdentifier<any>;
2627

2728
private readonly _opener = new LinkedList<IOpener>();
2829

@@ -41,7 +42,7 @@ export class OpenerService implements IOpenerService {
4142
return { dispose: remove };
4243
}
4344

44-
async open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean> {
45+
async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
4546
// no scheme ?!?
4647
if (!resource.scheme) {
4748
return Promise.resolve(false);
@@ -57,13 +58,13 @@ export class OpenerService implements IOpenerService {
5758
return this._doOpen(resource, options);
5859
}
5960

60-
private _doOpen(resource: URI, options?: { openToSide?: boolean }): Promise<boolean> {
61+
private _doOpen(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
6162

6263
const { scheme, authority, path, query, fragment } = resource;
6364

64-
if (equalsIgnoreCase(scheme, Schemas.mailto)) {
65+
if (equalsIgnoreCase(scheme, Schemas.mailto) || (options && options.openExternal)) {
6566
// open default mail application
66-
return this.openExternal(resource);
67+
return this._doOpenExternal(resource);
6768
}
6869

6970
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) {
@@ -78,7 +79,7 @@ export class OpenerService implements IOpenerService {
7879
const domainToOpen = `${scheme}://${authority}`;
7980

8081
if (isDomainTrusted(domainToOpen, trustedDomains)) {
81-
return this.openExternal(resource);
82+
return this._doOpenExternal(resource);
8283
} else {
8384
return this._dialogService.show(
8485
Severity.Info,
@@ -97,11 +98,11 @@ export class OpenerService implements IOpenerService {
9798
cancelId: 1
9899
}).then((choice) => {
99100
if (choice === 0) {
100-
return this.openExternal(resource);
101+
return this._doOpenExternal(resource);
101102
} else if (choice === 2) {
102103
return this._commandService.executeCommand('workbench.action.configureTrustedDomains', domainToOpen).then((pickedDomains: string[]) => {
103104
if (pickedDomains.indexOf(domainToOpen) !== -1) {
104-
return this.openExternal(resource);
105+
return this._doOpenExternal(resource);
105106
}
106107
return Promise.resolve(false);
107108
});
@@ -152,7 +153,7 @@ export class OpenerService implements IOpenerService {
152153
}
153154
}
154155

155-
openExternal(resource: URI): Promise<boolean> {
156+
private _doOpenExternal(resource: URI): Promise<boolean> {
156157
dom.windowOpenNoOpener(encodeURI(resource.toString(true)));
157158

158159
return Promise.resolve(true);

src/vs/platform/opener/common/opener.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const IOpenerService = createDecorator<IOpenerService>('openerService');
1111

1212
export interface IOpener {
1313
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
14+
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
1415
}
1516

1617
export interface IOpenerService {
@@ -29,18 +30,11 @@ export interface IOpenerService {
2930
* @return A promise that resolves when the opening is done.
3031
*/
3132
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
32-
33-
/**
34-
* Opens a URL externally.
35-
*
36-
* @param url A resource to open externally.
37-
*/
38-
openExternal(resource: URI): Promise<boolean>;
33+
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
3934
}
4035

4136
export const NullOpenerService: IOpenerService = Object.freeze({
4237
_serviceBrand: undefined,
4338
registerOpener() { return { dispose() { } }; },
4439
open() { return Promise.resolve(false); },
45-
openExternal() { return Promise.resolve(false); }
4640
});

src/vs/platform/url/electron-browser/urlService.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@ export class RelayURLService extends URLService implements IURLHandler {
2727
openerService.registerOpener(this);
2828
}
2929

30-
async open(uri: URI): Promise<boolean> {
31-
if (uri.scheme !== product.urlProtocol) {
30+
async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
31+
if (options && options.openExternal) {
3232
return false;
3333
}
3434

35-
return await this.urlService.open(uri);
35+
if (resource.scheme !== product.urlProtocol) {
36+
return false;
37+
}
38+
39+
return await this.urlService.open(resource);
3640
}
3741

3842
handleURL(uri: URI): Promise<boolean> {

src/vs/workbench/api/browser/mainThreadWindow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
5959
}
6060
}
6161

62-
return this.openerService.openExternal(uri);
62+
return this.openerService.open(uri, { openExternal: true });
6363
}
6464

6565
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {

src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
3838
BinaryFileEditor.ID,
3939
{
4040
openInternal: (input, options) => this.openInternal(input, options),
41-
openExternal: resource => this.openerService.openExternal(resource)
41+
openExternal: resource => this.openerService.open(resource, { openExternal: true })
4242
},
4343
telemetryService,
4444
themeService,

src/vs/workbench/electron-browser/window.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ import { IPreferencesService } from '../services/preferences/common/preferences'
5454
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
5555
import { IMenubarService, IMenubarData, IMenubarMenu, IMenubarKeybinding, IMenubarMenuItemSubmenu, IMenubarMenuItemAction, MenubarMenuItem } from 'vs/platform/menubar/node/menubar';
5656
import { withNullAsUndefined } from 'vs/base/common/types';
57+
import { IOpenerService } from 'vs/platform/opener/common/opener';
58+
import { Schemas } from 'vs/base/common/network';
5759

5860
const TextInputActions: IAction[] = [
5961
new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))),
@@ -101,7 +103,8 @@ export class ElectronWindow extends Disposable {
101103
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
102104
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
103105
@ITextFileService private readonly textFileService: ITextFileService,
104-
@IInstantiationService private readonly instantiationService: IInstantiationService
106+
@IInstantiationService private readonly instantiationService: IInstantiationService,
107+
@IOpenerService private readonly openerService: IOpenerService
105108
) {
106109
super();
107110

@@ -312,13 +315,8 @@ export class ElectronWindow extends Disposable {
312315
this._register(this.instantiationService.createInstance(NativeMenubarControl));
313316
}
314317

315-
// Handle window.open() calls
316-
const $this = this;
317-
window.open = function (url: string, target: string, features: string, replace: boolean): Window | null {
318-
$this.windowsService.openExternal(url);
319-
320-
return null;
321-
};
318+
// Handle open calls
319+
this.setupOpenHandlers();
322320

323321
// Emit event when vscode is ready
324322
this.lifecycleService.when(LifecyclePhase.Ready).then(() => ipc.send('vscode:workbenchReady', this.windowService.windowId));
@@ -356,6 +354,35 @@ export class ElectronWindow extends Disposable {
356354
}
357355
}
358356

357+
private setupOpenHandlers(): void {
358+
359+
// Handle window.open() calls
360+
const $this = this;
361+
window.open = function (url: string, target: string, features: string, replace: boolean): Window | null {
362+
$this.windowsService.openExternal(url);
363+
364+
return null;
365+
};
366+
367+
// Handle external open calls
368+
this.openerService.registerOpener({
369+
async open(resource: URI, options?: { openToSide?: boolean; openExternal?: boolean; } | undefined): Promise<boolean> {
370+
if (!options || !options.openExternal) {
371+
return false; // only override behaviour for external open()
372+
}
373+
374+
const success = await $this.windowsService.openExternal(encodeURI(resource.toString(true)));
375+
if (!success && resource.scheme === Schemas.file) {
376+
await $this.windowsService.showItemInFolder(resource);
377+
378+
return true;
379+
}
380+
381+
return success;
382+
}
383+
});
384+
}
385+
359386
private updateTouchbarMenu(): void {
360387
if (!isMacintosh) {
361388
return; // macOS only
@@ -741,4 +768,4 @@ class NativeMenubarControl extends MenubarControl {
741768

742769
return undefined;
743770
}
744-
}
771+
}

src/vs/workbench/services/files/common/workspaceWatcher.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class WorkspaceWatcher extends Disposable {
7979
localize('netVersionError', "The Microsoft .NET Framework 4.5 is required. Please follow the link to install it."),
8080
[{
8181
label: localize('installNet', "Download .NET Framework 4.5"),
82-
run: () => this.openerService.openExternal(URI.parse('https://go.microsoft.com/fwlink/?LinkId=786533'))
82+
run: () => this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?LinkId=786533'))
8383
}],
8484
{
8585
sticky: true,
@@ -95,7 +95,7 @@ export class WorkspaceWatcher extends Disposable {
9595
localize('enospcError', "Unable to watch for file changes in this large workspace. Please follow the instructions link to resolve this issue."),
9696
[{
9797
label: localize('learnMore', "Instructions"),
98-
run: () => this.openerService.openExternal(URI.parse('https://go.microsoft.com/fwlink/?linkid=867693'))
98+
run: () => this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=867693'))
9999
}],
100100
{
101101
sticky: true,

src/vs/workbench/services/integrity/node/integrityService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export class IntegrityServiceImpl implements IIntegrityService {
9393
[
9494
{
9595
label: nls.localize('integrity.moreInformation', "More Information"),
96-
run: () => this.openerService.openExternal(URI.parse(product.checksumFailMoreInfoUrl))
96+
run: () => this.openerService.open(URI.parse(product.checksumFailMoreInfoUrl))
9797
},
9898
{
9999
label: nls.localize('integrity.dontShowAgain', "Don't Show Again"),

src/vs/workbench/services/opener/electron-browser/openerService.ts

Lines changed: 0 additions & 46 deletions
This file was deleted.

src/vs/workbench/workbench.common.main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ import { IMenuService } from 'vs/platform/actions/common/actions';
9696
import { MenuService } from 'vs/platform/actions/common/menuService';
9797
import { IDownloadService } from 'vs/platform/download/common/download';
9898
import { DownloadService } from 'vs/platform/download/common/downloadService';
99+
import { OpenerService } from 'vs/editor/browser/services/openerService';
100+
import { IOpenerService } from 'vs/platform/opener/common/opener';
99101

100102
registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
101103
registerSingleton(IContextViewService, ContextViewService, true);
@@ -108,6 +110,7 @@ registerSingleton(IModelService, ModelServiceImpl, true);
108110
registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService);
109111
registerSingleton(IMenuService, MenuService, true);
110112
registerSingleton(IDownloadService, DownloadService, true);
113+
registerSingleton(IOpenerService, OpenerService, true);
111114

112115
//#endregion
113116

0 commit comments

Comments
 (0)