Path: blob/main/src/vs/sessions/electron-browser/sessions.ts
13389 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45/* eslint-disable no-restricted-globals */67(async function () {89// Add a perf entry right from the top10performance.mark('code/didStartRenderer');1112type ISandboxConfiguration = import('../../base/parts/sandbox/common/sandboxTypes.js').ISandboxConfiguration;13type ILoadResult<M, T extends ISandboxConfiguration> = import('../../platform/window/electron-browser/window.js').ILoadResult<M, T>;14type ILoadOptions<T extends ISandboxConfiguration> = import('../../platform/window/electron-browser/window.js').ILoadOptions<T>;15type INativeWindowConfiguration = import('../../platform/window/common/window.js').INativeWindowConfiguration;16type IMainWindowSandboxGlobals = import('../../base/parts/sandbox/electron-browser/globals.js').IMainWindowSandboxGlobals;17type IDesktopMain = import('./sessions.main.js').IDesktopMain;1819const preloadGlobals = (window as unknown as { vscode: IMainWindowSandboxGlobals }).vscode; // defined by preload.ts20const safeProcess = preloadGlobals.process;2122//#region Splash Screen2324function showSplash(configuration: INativeWindowConfiguration) {25performance.mark('code/willShowPartsSplash');2627let data = configuration.partsSplash;28if (data) {29if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) {30if ((configuration.colorScheme.dark && data.baseTheme !== 'hc-black') || (!configuration.colorScheme.dark && data.baseTheme !== 'hc-light')) {31data = undefined; // high contrast mode has been turned by the OS -> ignore stored colors and layouts32}33} else if (configuration.autoDetectColorScheme) {34if ((configuration.colorScheme.dark && data.baseTheme !== 'vs-dark') || (!configuration.colorScheme.dark && data.baseTheme !== 'vs')) {35data = undefined; // OS color scheme is tracked and has changed36}37}38}3940// minimal color configuration (works with or without persisted data)41let baseTheme = 'vs-dark';42let shellBackground = '#1E1E1E';43let shellForeground = '#CCCCCC';44if (data) {45baseTheme = data.baseTheme;46shellBackground = data.baseTheme === 'vs'47? (data.colorInfo.background ?? data.colorInfo.editorBackground)48: (data.colorInfo.editorBackground ?? data.colorInfo.background);49shellForeground = data.colorInfo.foreground ?? shellForeground;50} else if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) {51if (configuration.colorScheme.dark) {52baseTheme = 'hc-black';53shellBackground = '#000000';54shellForeground = '#FFFFFF';55} else {56baseTheme = 'hc-light';57shellBackground = '#FFFFFF';58shellForeground = '#000000';59}60} else if (configuration.autoDetectColorScheme) {61if (configuration.colorScheme.dark) {62baseTheme = 'vs-dark';63shellBackground = '#1E1E1E';64shellForeground = '#CCCCCC';65} else {66baseTheme = 'vs';67shellBackground = '#F3F3F3';68shellForeground = '#000000';69}70}7172// Apply base colors73const style = document.createElement('style');74style.className = 'initialShellColors';75window.document.head.appendChild(style);76style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`;7778// Set zoom level from splash data if available79if (typeof data?.zoomLevel === 'number' && typeof preloadGlobals?.webFrame?.setZoomLevel === 'function') {80preloadGlobals.webFrame.setZoomLevel(data.zoomLevel);81}8283const splash = document.createElement('div');84splash.id = 'monaco-parts-splash';85splash.className = baseTheme ?? 'vs-dark';8687window.document.body.appendChild(splash);8889performance.mark('code/didShowPartsSplash');90}9192//#endregion9394//#region Window Helpers9596async function load<M, T extends ISandboxConfiguration>(options: ILoadOptions<T>): Promise<ILoadResult<M, T>> {9798// Window Configuration from Preload Script99const configuration = await resolveWindowConfiguration<T>();100101// Signal before import()102options?.beforeImport?.(configuration);103104// Developer settings105const { enableDeveloperKeybindings, removeDeveloperKeybindingsAfterLoad, developerDeveloperKeybindingsDisposable, forceDisableShowDevtoolsOnError } = setupDeveloperKeybindings(configuration, options);106107// NLS108setupNLS<T>(configuration);109110// Compute base URL and set as global111const baseUrl = new URL(`${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out/`);112globalThis._VSCODE_FILE_ROOT = baseUrl.toString();113114// Dev only: CSS import map tricks115setupCSSImportMaps<T>(configuration, baseUrl);116117// ESM Import - load the sessions workbench main module118try {119let workbenchUrl: string;120if (!!safeProcess.env['VSCODE_DEV'] && globalThis._VSCODE_USE_RELATIVE_IMPORTS) {121workbenchUrl = './sessions.desktop.main.js'; // for dev purposes only122} else {123workbenchUrl = new URL(`vs/sessions/sessions.desktop.main.js`, baseUrl).href;124}125126const result = await import(workbenchUrl);127if (developerDeveloperKeybindingsDisposable && removeDeveloperKeybindingsAfterLoad) {128developerDeveloperKeybindingsDisposable();129}130131return { result, configuration };132} catch (error) {133onUnexpectedError(error, enableDeveloperKeybindings && !forceDisableShowDevtoolsOnError);134135throw error;136}137}138139async function resolveWindowConfiguration<T extends ISandboxConfiguration>() {140const timeout = setTimeout(() => { console.error(`[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`); }, 10000);141performance.mark('code/willWaitForWindowConfig');142143const configuration = await preloadGlobals.context.resolveConfiguration() as T;144performance.mark('code/didWaitForWindowConfig');145146clearTimeout(timeout);147148return configuration;149}150151function setupDeveloperKeybindings<T extends ISandboxConfiguration>(configuration: T, options: ILoadOptions<T>) {152const {153forceEnableDeveloperKeybindings,154disallowReloadKeybinding,155removeDeveloperKeybindingsAfterLoad,156forceDisableShowDevtoolsOnError157} = typeof options?.configureDeveloperSettings === 'function' ? options.configureDeveloperSettings(configuration) : {158forceEnableDeveloperKeybindings: false,159disallowReloadKeybinding: false,160removeDeveloperKeybindingsAfterLoad: false,161forceDisableShowDevtoolsOnError: false162};163164const isDev = !!safeProcess.env['VSCODE_DEV'];165const enableDeveloperKeybindings = Boolean(isDev || forceEnableDeveloperKeybindings);166let developerDeveloperKeybindingsDisposable: Function | undefined = undefined;167if (enableDeveloperKeybindings) {168developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding);169}170171return {172enableDeveloperKeybindings,173removeDeveloperKeybindingsAfterLoad,174developerDeveloperKeybindingsDisposable,175forceDisableShowDevtoolsOnError176};177}178179function registerDeveloperKeybindings(disallowReloadKeybinding: boolean | undefined): Function {180const ipcRenderer = preloadGlobals.ipcRenderer;181182const extractKey =183function (e: KeyboardEvent) {184return [185e.ctrlKey ? 'ctrl-' : '',186e.metaKey ? 'meta-' : '',187e.altKey ? 'alt-' : '',188e.shiftKey ? 'shift-' : '',189e.keyCode190].join('');191};192193// Devtools & reload support194const TOGGLE_DEV_TOOLS_KB = (safeProcess.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I195const TOGGLE_DEV_TOOLS_KB_ALT = '123'; // F12196const RELOAD_KB = (safeProcess.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R197198let listener: ((e: KeyboardEvent) => void) | undefined = function (e) {199const key = extractKey(e);200if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) {201ipcRenderer.send('vscode:toggleDevTools');202} else if (key === RELOAD_KB && !disallowReloadKeybinding) {203ipcRenderer.send('vscode:reloadWindow');204}205};206207window.addEventListener('keydown', listener);208209return function () {210if (listener) {211window.removeEventListener('keydown', listener);212listener = undefined;213}214};215}216217function setupNLS<T extends ISandboxConfiguration>(configuration: T): void {218globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages;219globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language;220221let language = configuration.nls.language || 'en';222if (language === 'zh-tw') {223language = 'zh-Hant';224} else if (language === 'zh-cn') {225language = 'zh-Hans';226}227228window.document.documentElement.setAttribute('lang', language);229}230231function onUnexpectedError(error: string | Error, showDevtoolsOnError: boolean): void {232if (showDevtoolsOnError) {233const ipcRenderer = preloadGlobals.ipcRenderer;234ipcRenderer.send('vscode:openDevTools');235}236237console.error(`[uncaught exception]: ${error}`);238239if (error && typeof error !== 'string' && error.stack) {240console.error(error.stack);241}242}243244function fileUriFromPath(path: string, config: { isWindows?: boolean; scheme?: string; fallbackAuthority?: string }): string {245246// Since we are building a URI, we normalize any backslash247// to slashes and we ensure that the path begins with a '/'.248let pathName = path.replace(/\\/g, '/');249if (pathName.length > 0 && pathName.charAt(0) !== '/') {250pathName = `/${pathName}`;251}252253let uri: string;254255// Windows: in order to support UNC paths (which start with '//')256// that have their own authority, we do not use the provided authority257// but rather preserve it.258if (config.isWindows && pathName.startsWith('//')) {259uri = encodeURI(`${config.scheme || 'file'}:${pathName}`);260}261262// Otherwise we optionally add the provided authority if specified263else {264uri = encodeURI(`${config.scheme || 'file'}://${config.fallbackAuthority || ''}${pathName}`);265}266267return uri.replace(/#/g, '%23');268}269270function setupCSSImportMaps<T extends ISandboxConfiguration>(configuration: T, baseUrl: URL) {271272// DEV ---------------------------------------------------------------------------------------273// DEV: This is for development and enables loading CSS via import-statements via import-maps.274// DEV: For each CSS modules that we have we defined an entry in the import map that maps to275// DEV: a blob URL that loads the CSS via a dynamic @import-rule.276// DEV ---------------------------------------------------------------------------------------277278if (globalThis._VSCODE_DISABLE_CSS_IMPORT_MAP) {279return; // disabled in certain development setups280}281282if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) {283performance.mark('code/willAddCssLoader');284285globalThis._VSCODE_CSS_LOAD = function (url) {286const link = document.createElement('link');287link.setAttribute('rel', 'stylesheet');288link.setAttribute('type', 'text/css');289link.setAttribute('href', url);290291window.document.head.appendChild(link);292};293294const importMap: { imports: Record<string, string> } = { imports: {} };295for (const cssModule of configuration.cssModules) {296const cssUrl = new URL(cssModule, baseUrl).href;297const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`;298const blob = new Blob([jsSrc], { type: 'application/javascript' });299importMap.imports[cssUrl] = URL.createObjectURL(blob);300}301302const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, });303const importMapSrc = JSON.stringify(importMap, undefined, 2);304const importMapScript = document.createElement('script');305importMapScript.type = 'importmap';306importMapScript.setAttribute('nonce', '0c6a828f1297');307// @ts-expect-error308importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc;309window.document.head.appendChild(importMapScript);310311performance.mark('code/didAddCssLoader');312}313}314315//#endregion316317const { result, configuration } = await load<IDesktopMain, INativeWindowConfiguration>(318{319configureDeveloperSettings: function (windowConfig) {320return {321// disable automated devtools opening on error when running extension tests322// as this can lead to nondeterministic test execution (devtools steals focus)323forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string' || windowConfig['enable-smoke-test-driver'] === true,324// enable devtools keybindings in extension development window325forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0,326removeDeveloperKeybindingsAfterLoad: true327};328},329beforeImport: function (windowConfig) {330331// Show our splash as early as possible332showSplash(windowConfig);333334// Code windows have a `vscodeWindowId` property to identify them335Object.defineProperty(window, 'vscodeWindowId', {336get: () => windowConfig.windowId337});338339// It looks like browsers only lazily enable340// the <canvas> element when needed. Since we341// leverage canvas elements in our code in many342// locations, we try to help the browser to343// initialize canvas when it is idle, right344// before we wait for the scripts to be loaded.345window.requestIdleCallback(() => {346const canvas = document.createElement('canvas');347const context = canvas.getContext('2d');348context?.clearRect(0, 0, canvas.width, canvas.height);349canvas.remove();350}, { timeout: 50 });351352// Track import() perf353performance.mark('code/willLoadWorkbenchMain');354}355}356);357358// Mark start of workbench359performance.mark('code/didLoadWorkbenchMain');360361// Load workbench362result.main(configuration);363}());364365366