Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/browserView/electron-browser/browserView.contribution.ts
5241 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { localize } from '../../../../nls.js';
7
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
8
import { Registry } from '../../../../platform/registry/common/platform.js';
9
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
10
import { EditorExtensions, IEditorFactoryRegistry } from '../../../common/editor.js';
11
import { BrowserEditor } from './browserEditor.js';
12
import { BrowserEditorInput, BrowserEditorSerializer } from './browserEditorInput.js';
13
import { BrowserViewUri } from '../../../../platform/browserView/common/browserViewUri.js';
14
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
15
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
16
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from '../../../../platform/configuration/common/configurationRegistry.js';
17
import { workbenchConfigurationNodeBase } from '../../../common/configuration.js';
18
import { IEditorResolverService, RegisteredEditorPriority } from '../../../services/editor/common/editorResolverService.js';
19
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';
20
import { Schemas } from '../../../../base/common/network.js';
21
import { IBrowserViewWorkbenchService } from '../common/browserView.js';
22
import { BrowserViewWorkbenchService } from './browserViewWorkbenchService.js';
23
import { BrowserViewStorageScope } from '../../../../platform/browserView/common/browserView.js';
24
import { IOpenerService, IOpener, OpenInternalOptions, OpenExternalOptions } from '../../../../platform/opener/common/opener.js';
25
import { isLocalhostAuthority } from '../../../../platform/url/common/trustedDomains.js';
26
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
27
import { IEditorService } from '../../../services/editor/common/editorService.js';
28
import { Disposable } from '../../../../base/common/lifecycle.js';
29
import { URI } from '../../../../base/common/uri.js';
30
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
31
import { logBrowserOpen } from './browserViewTelemetry.js';
32
33
// Register actions
34
import './browserViewActions.js';
35
36
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
37
EditorPaneDescriptor.create(
38
BrowserEditor,
39
BrowserEditor.ID,
40
localize('browser.editorLabel', "Browser")
41
),
42
[
43
new SyncDescriptor(BrowserEditorInput)
44
]
45
);
46
47
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(
48
BrowserEditorInput.ID,
49
BrowserEditorSerializer
50
);
51
52
class BrowserEditorResolverContribution implements IWorkbenchContribution {
53
static readonly ID = 'workbench.contrib.browserEditorResolver';
54
55
constructor(
56
@IEditorResolverService editorResolverService: IEditorResolverService,
57
@IInstantiationService instantiationService: IInstantiationService
58
) {
59
editorResolverService.registerEditor(
60
`${Schemas.vscodeBrowser}:/**`,
61
{
62
id: BrowserEditorInput.ID,
63
label: localize('browser.editorLabel', "Browser"),
64
priority: RegisteredEditorPriority.exclusive
65
},
66
{
67
canSupportResource: resource => resource.scheme === Schemas.vscodeBrowser,
68
singlePerResource: true
69
},
70
{
71
createEditorInput: ({ resource, options }) => {
72
const parsed = BrowserViewUri.parse(resource);
73
if (!parsed) {
74
throw new Error(`Invalid browser view resource: ${resource.toString()}`);
75
}
76
77
const browserInput = instantiationService.createInstance(BrowserEditorInput, {
78
id: parsed.id,
79
url: parsed.url
80
});
81
82
// Start resolving the input right away. This will create the browser view.
83
// This allows browser views to be loaded in the background.
84
void browserInput.resolve();
85
86
return {
87
editor: browserInput,
88
options: {
89
...options,
90
pinned: !!parsed.url // pin if navigated
91
}
92
};
93
}
94
}
95
);
96
}
97
}
98
99
registerWorkbenchContribution2(BrowserEditorResolverContribution.ID, BrowserEditorResolverContribution, WorkbenchPhase.BlockStartup);
100
101
/**
102
* Opens localhost URLs in the Integrated Browser when the setting is enabled.
103
*/
104
class LocalhostLinkOpenerContribution extends Disposable implements IWorkbenchContribution, IOpener {
105
static readonly ID = 'workbench.contrib.localhostLinkOpener';
106
107
constructor(
108
@IOpenerService openerService: IOpenerService,
109
@IConfigurationService private readonly configurationService: IConfigurationService,
110
@IEditorService private readonly editorService: IEditorService,
111
@ITelemetryService private readonly telemetryService: ITelemetryService
112
) {
113
super();
114
115
this._register(openerService.registerOpener(this));
116
}
117
118
async open(resource: URI | string, _options?: OpenInternalOptions | OpenExternalOptions): Promise<boolean> {
119
if (!this.configurationService.getValue<boolean>('workbench.browser.openLocalhostLinks')) {
120
return false;
121
}
122
123
const url = typeof resource === 'string' ? resource : resource.toString(true);
124
try {
125
const parsed = new URL(url);
126
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
127
return false;
128
}
129
if (!isLocalhostAuthority(parsed.host)) {
130
return false;
131
}
132
} catch {
133
return false;
134
}
135
136
logBrowserOpen(this.telemetryService, 'localhostLinkOpener');
137
138
const browserUri = BrowserViewUri.forUrl(url);
139
await this.editorService.openEditor({ resource: browserUri, options: { pinned: true } });
140
return true;
141
}
142
}
143
144
registerWorkbenchContribution2(LocalhostLinkOpenerContribution.ID, LocalhostLinkOpenerContribution, WorkbenchPhase.BlockStartup);
145
146
registerSingleton(IBrowserViewWorkbenchService, BrowserViewWorkbenchService, InstantiationType.Delayed);
147
148
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({
149
...workbenchConfigurationNodeBase,
150
properties: {
151
'workbench.browser.openLocalhostLinks': {
152
type: 'boolean',
153
default: false,
154
markdownDescription: localize(
155
{ comment: ['This is the description for a setting.'], key: 'browser.openLocalhostLinks' },
156
'When enabled, localhost links from the terminal, chat, and other sources will open in the Integrated Browser instead of the system browser.'
157
)
158
},
159
'workbench.browser.dataStorage': {
160
type: 'string',
161
enum: [
162
BrowserViewStorageScope.Global,
163
BrowserViewStorageScope.Workspace,
164
BrowserViewStorageScope.Ephemeral
165
],
166
markdownEnumDescriptions: [
167
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'browser.dataStorage.global' }, 'All browser views share a single persistent session across all workspaces.'),
168
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'browser.dataStorage.workspace' }, 'Browser views within the same workspace share a persistent session. If no workspace is opened, `ephemeral` storage is used.'),
169
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'browser.dataStorage.ephemeral' }, 'Each browser view has its own session that is cleaned up when closed.')
170
],
171
restricted: true,
172
default: BrowserViewStorageScope.Global,
173
markdownDescription: localize(
174
{ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'browser.dataStorage' },
175
'Controls how browser data (cookies, cache, storage) is shared between browser views.\n\n**Note**: In untrusted workspaces, this setting is ignored and `ephemeral` storage is always used.'
176
),
177
scope: ConfigurationScope.WINDOW,
178
order: 100
179
}
180
}
181
});
182
183