Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/electron-browser/sessions.ts
13389 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
/* eslint-disable no-restricted-globals */
7
8
(async function () {
9
10
// Add a perf entry right from the top
11
performance.mark('code/didStartRenderer');
12
13
type ISandboxConfiguration = import('../../base/parts/sandbox/common/sandboxTypes.js').ISandboxConfiguration;
14
type ILoadResult<M, T extends ISandboxConfiguration> = import('../../platform/window/electron-browser/window.js').ILoadResult<M, T>;
15
type ILoadOptions<T extends ISandboxConfiguration> = import('../../platform/window/electron-browser/window.js').ILoadOptions<T>;
16
type INativeWindowConfiguration = import('../../platform/window/common/window.js').INativeWindowConfiguration;
17
type IMainWindowSandboxGlobals = import('../../base/parts/sandbox/electron-browser/globals.js').IMainWindowSandboxGlobals;
18
type IDesktopMain = import('./sessions.main.js').IDesktopMain;
19
20
const preloadGlobals = (window as unknown as { vscode: IMainWindowSandboxGlobals }).vscode; // defined by preload.ts
21
const safeProcess = preloadGlobals.process;
22
23
//#region Splash Screen
24
25
function showSplash(configuration: INativeWindowConfiguration) {
26
performance.mark('code/willShowPartsSplash');
27
28
let data = configuration.partsSplash;
29
if (data) {
30
if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) {
31
if ((configuration.colorScheme.dark && data.baseTheme !== 'hc-black') || (!configuration.colorScheme.dark && data.baseTheme !== 'hc-light')) {
32
data = undefined; // high contrast mode has been turned by the OS -> ignore stored colors and layouts
33
}
34
} else if (configuration.autoDetectColorScheme) {
35
if ((configuration.colorScheme.dark && data.baseTheme !== 'vs-dark') || (!configuration.colorScheme.dark && data.baseTheme !== 'vs')) {
36
data = undefined; // OS color scheme is tracked and has changed
37
}
38
}
39
}
40
41
// minimal color configuration (works with or without persisted data)
42
let baseTheme = 'vs-dark';
43
let shellBackground = '#1E1E1E';
44
let shellForeground = '#CCCCCC';
45
if (data) {
46
baseTheme = data.baseTheme;
47
shellBackground = data.baseTheme === 'vs'
48
? (data.colorInfo.background ?? data.colorInfo.editorBackground)
49
: (data.colorInfo.editorBackground ?? data.colorInfo.background);
50
shellForeground = data.colorInfo.foreground ?? shellForeground;
51
} else if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) {
52
if (configuration.colorScheme.dark) {
53
baseTheme = 'hc-black';
54
shellBackground = '#000000';
55
shellForeground = '#FFFFFF';
56
} else {
57
baseTheme = 'hc-light';
58
shellBackground = '#FFFFFF';
59
shellForeground = '#000000';
60
}
61
} else if (configuration.autoDetectColorScheme) {
62
if (configuration.colorScheme.dark) {
63
baseTheme = 'vs-dark';
64
shellBackground = '#1E1E1E';
65
shellForeground = '#CCCCCC';
66
} else {
67
baseTheme = 'vs';
68
shellBackground = '#F3F3F3';
69
shellForeground = '#000000';
70
}
71
}
72
73
// Apply base colors
74
const style = document.createElement('style');
75
style.className = 'initialShellColors';
76
window.document.head.appendChild(style);
77
style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`;
78
79
// Set zoom level from splash data if available
80
if (typeof data?.zoomLevel === 'number' && typeof preloadGlobals?.webFrame?.setZoomLevel === 'function') {
81
preloadGlobals.webFrame.setZoomLevel(data.zoomLevel);
82
}
83
84
const splash = document.createElement('div');
85
splash.id = 'monaco-parts-splash';
86
splash.className = baseTheme ?? 'vs-dark';
87
88
window.document.body.appendChild(splash);
89
90
performance.mark('code/didShowPartsSplash');
91
}
92
93
//#endregion
94
95
//#region Window Helpers
96
97
async function load<M, T extends ISandboxConfiguration>(options: ILoadOptions<T>): Promise<ILoadResult<M, T>> {
98
99
// Window Configuration from Preload Script
100
const configuration = await resolveWindowConfiguration<T>();
101
102
// Signal before import()
103
options?.beforeImport?.(configuration);
104
105
// Developer settings
106
const { enableDeveloperKeybindings, removeDeveloperKeybindingsAfterLoad, developerDeveloperKeybindingsDisposable, forceDisableShowDevtoolsOnError } = setupDeveloperKeybindings(configuration, options);
107
108
// NLS
109
setupNLS<T>(configuration);
110
111
// Compute base URL and set as global
112
const baseUrl = new URL(`${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out/`);
113
globalThis._VSCODE_FILE_ROOT = baseUrl.toString();
114
115
// Dev only: CSS import map tricks
116
setupCSSImportMaps<T>(configuration, baseUrl);
117
118
// ESM Import - load the sessions workbench main module
119
try {
120
let workbenchUrl: string;
121
if (!!safeProcess.env['VSCODE_DEV'] && globalThis._VSCODE_USE_RELATIVE_IMPORTS) {
122
workbenchUrl = './sessions.desktop.main.js'; // for dev purposes only
123
} else {
124
workbenchUrl = new URL(`vs/sessions/sessions.desktop.main.js`, baseUrl).href;
125
}
126
127
const result = await import(workbenchUrl);
128
if (developerDeveloperKeybindingsDisposable && removeDeveloperKeybindingsAfterLoad) {
129
developerDeveloperKeybindingsDisposable();
130
}
131
132
return { result, configuration };
133
} catch (error) {
134
onUnexpectedError(error, enableDeveloperKeybindings && !forceDisableShowDevtoolsOnError);
135
136
throw error;
137
}
138
}
139
140
async function resolveWindowConfiguration<T extends ISandboxConfiguration>() {
141
const timeout = setTimeout(() => { console.error(`[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`); }, 10000);
142
performance.mark('code/willWaitForWindowConfig');
143
144
const configuration = await preloadGlobals.context.resolveConfiguration() as T;
145
performance.mark('code/didWaitForWindowConfig');
146
147
clearTimeout(timeout);
148
149
return configuration;
150
}
151
152
function setupDeveloperKeybindings<T extends ISandboxConfiguration>(configuration: T, options: ILoadOptions<T>) {
153
const {
154
forceEnableDeveloperKeybindings,
155
disallowReloadKeybinding,
156
removeDeveloperKeybindingsAfterLoad,
157
forceDisableShowDevtoolsOnError
158
} = typeof options?.configureDeveloperSettings === 'function' ? options.configureDeveloperSettings(configuration) : {
159
forceEnableDeveloperKeybindings: false,
160
disallowReloadKeybinding: false,
161
removeDeveloperKeybindingsAfterLoad: false,
162
forceDisableShowDevtoolsOnError: false
163
};
164
165
const isDev = !!safeProcess.env['VSCODE_DEV'];
166
const enableDeveloperKeybindings = Boolean(isDev || forceEnableDeveloperKeybindings);
167
let developerDeveloperKeybindingsDisposable: Function | undefined = undefined;
168
if (enableDeveloperKeybindings) {
169
developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding);
170
}
171
172
return {
173
enableDeveloperKeybindings,
174
removeDeveloperKeybindingsAfterLoad,
175
developerDeveloperKeybindingsDisposable,
176
forceDisableShowDevtoolsOnError
177
};
178
}
179
180
function registerDeveloperKeybindings(disallowReloadKeybinding: boolean | undefined): Function {
181
const ipcRenderer = preloadGlobals.ipcRenderer;
182
183
const extractKey =
184
function (e: KeyboardEvent) {
185
return [
186
e.ctrlKey ? 'ctrl-' : '',
187
e.metaKey ? 'meta-' : '',
188
e.altKey ? 'alt-' : '',
189
e.shiftKey ? 'shift-' : '',
190
e.keyCode
191
].join('');
192
};
193
194
// Devtools & reload support
195
const TOGGLE_DEV_TOOLS_KB = (safeProcess.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
196
const TOGGLE_DEV_TOOLS_KB_ALT = '123'; // F12
197
const RELOAD_KB = (safeProcess.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
198
199
let listener: ((e: KeyboardEvent) => void) | undefined = function (e) {
200
const key = extractKey(e);
201
if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) {
202
ipcRenderer.send('vscode:toggleDevTools');
203
} else if (key === RELOAD_KB && !disallowReloadKeybinding) {
204
ipcRenderer.send('vscode:reloadWindow');
205
}
206
};
207
208
window.addEventListener('keydown', listener);
209
210
return function () {
211
if (listener) {
212
window.removeEventListener('keydown', listener);
213
listener = undefined;
214
}
215
};
216
}
217
218
function setupNLS<T extends ISandboxConfiguration>(configuration: T): void {
219
globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages;
220
globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language;
221
222
let language = configuration.nls.language || 'en';
223
if (language === 'zh-tw') {
224
language = 'zh-Hant';
225
} else if (language === 'zh-cn') {
226
language = 'zh-Hans';
227
}
228
229
window.document.documentElement.setAttribute('lang', language);
230
}
231
232
function onUnexpectedError(error: string | Error, showDevtoolsOnError: boolean): void {
233
if (showDevtoolsOnError) {
234
const ipcRenderer = preloadGlobals.ipcRenderer;
235
ipcRenderer.send('vscode:openDevTools');
236
}
237
238
console.error(`[uncaught exception]: ${error}`);
239
240
if (error && typeof error !== 'string' && error.stack) {
241
console.error(error.stack);
242
}
243
}
244
245
function fileUriFromPath(path: string, config: { isWindows?: boolean; scheme?: string; fallbackAuthority?: string }): string {
246
247
// Since we are building a URI, we normalize any backslash
248
// to slashes and we ensure that the path begins with a '/'.
249
let pathName = path.replace(/\\/g, '/');
250
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
251
pathName = `/${pathName}`;
252
}
253
254
let uri: string;
255
256
// Windows: in order to support UNC paths (which start with '//')
257
// that have their own authority, we do not use the provided authority
258
// but rather preserve it.
259
if (config.isWindows && pathName.startsWith('//')) {
260
uri = encodeURI(`${config.scheme || 'file'}:${pathName}`);
261
}
262
263
// Otherwise we optionally add the provided authority if specified
264
else {
265
uri = encodeURI(`${config.scheme || 'file'}://${config.fallbackAuthority || ''}${pathName}`);
266
}
267
268
return uri.replace(/#/g, '%23');
269
}
270
271
function setupCSSImportMaps<T extends ISandboxConfiguration>(configuration: T, baseUrl: URL) {
272
273
// DEV ---------------------------------------------------------------------------------------
274
// DEV: This is for development and enables loading CSS via import-statements via import-maps.
275
// DEV: For each CSS modules that we have we defined an entry in the import map that maps to
276
// DEV: a blob URL that loads the CSS via a dynamic @import-rule.
277
// DEV ---------------------------------------------------------------------------------------
278
279
if (globalThis._VSCODE_DISABLE_CSS_IMPORT_MAP) {
280
return; // disabled in certain development setups
281
}
282
283
if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) {
284
performance.mark('code/willAddCssLoader');
285
286
globalThis._VSCODE_CSS_LOAD = function (url) {
287
const link = document.createElement('link');
288
link.setAttribute('rel', 'stylesheet');
289
link.setAttribute('type', 'text/css');
290
link.setAttribute('href', url);
291
292
window.document.head.appendChild(link);
293
};
294
295
const importMap: { imports: Record<string, string> } = { imports: {} };
296
for (const cssModule of configuration.cssModules) {
297
const cssUrl = new URL(cssModule, baseUrl).href;
298
const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`;
299
const blob = new Blob([jsSrc], { type: 'application/javascript' });
300
importMap.imports[cssUrl] = URL.createObjectURL(blob);
301
}
302
303
const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, });
304
const importMapSrc = JSON.stringify(importMap, undefined, 2);
305
const importMapScript = document.createElement('script');
306
importMapScript.type = 'importmap';
307
importMapScript.setAttribute('nonce', '0c6a828f1297');
308
// @ts-expect-error
309
importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc;
310
window.document.head.appendChild(importMapScript);
311
312
performance.mark('code/didAddCssLoader');
313
}
314
}
315
316
//#endregion
317
318
const { result, configuration } = await load<IDesktopMain, INativeWindowConfiguration>(
319
{
320
configureDeveloperSettings: function (windowConfig) {
321
return {
322
// disable automated devtools opening on error when running extension tests
323
// as this can lead to nondeterministic test execution (devtools steals focus)
324
forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string' || windowConfig['enable-smoke-test-driver'] === true,
325
// enable devtools keybindings in extension development window
326
forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0,
327
removeDeveloperKeybindingsAfterLoad: true
328
};
329
},
330
beforeImport: function (windowConfig) {
331
332
// Show our splash as early as possible
333
showSplash(windowConfig);
334
335
// Code windows have a `vscodeWindowId` property to identify them
336
Object.defineProperty(window, 'vscodeWindowId', {
337
get: () => windowConfig.windowId
338
});
339
340
// It looks like browsers only lazily enable
341
// the <canvas> element when needed. Since we
342
// leverage canvas elements in our code in many
343
// locations, we try to help the browser to
344
// initialize canvas when it is idle, right
345
// before we wait for the scripts to be loaded.
346
window.requestIdleCallback(() => {
347
const canvas = document.createElement('canvas');
348
const context = canvas.getContext('2d');
349
context?.clearRect(0, 0, canvas.width, canvas.height);
350
canvas.remove();
351
}, { timeout: 50 });
352
353
// Track import() perf
354
performance.mark('code/willLoadWorkbenchMain');
355
}
356
}
357
);
358
359
// Mark start of workbench
360
performance.mark('code/didLoadWorkbenchMain');
361
362
// Load workbench
363
result.main(configuration);
364
}());
365
366