debt - provide common method to load renderer with config param

This commit is contained in:
Benjamin Pasero 2021-03-29 11:31:44 +02:00
parent 19f6f31036
commit e5b2742fff
No known key found for this signature in database
GPG key ID: C035C296C8A46619
6 changed files with 118 additions and 123 deletions

View file

@ -80,11 +80,8 @@ class CodeMain {
// default electron error dialog popping up
setUnexpectedErrorHandler(err => console.error(err));
// Resolve command line arguments
const args = this.resolveArgs();
// Create services
const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService, productService] = this.createServices(args);
const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService, productService] = this.createServices();
try {
@ -108,7 +105,7 @@ class CodeMain {
// Create the main IPC server by trying to be the server
// If this throws an error it means we are not the first
// instance of VS Code running and so we would quit.
const mainProcessNodeIpcServer = await this.doStartup(args, logService, environmentService, lifecycleMainService, instantiationService, productService, true);
const mainProcessNodeIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, productService, true);
// Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906)
bufferLogService.logger = new SpdLogLogger('main', join(environmentService.logsPath, 'main.log'), true, bufferLogService.getLevel());
@ -126,7 +123,7 @@ class CodeMain {
}
}
private createServices(args: NativeParsedArgs): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateService, BufferLogService, IProductService] {
private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateService, BufferLogService, IProductService] {
const services = new ServiceCollection();
// Product
@ -134,7 +131,7 @@ class CodeMain {
services.set(IProductService, productService);
// Environment
const environmentMainService = new EnvironmentMainService(args, productService);
const environmentMainService = new EnvironmentMainService(this.resolveArgs(), productService);
const instanceEnvironment = this.patchEnvironment(environmentMainService); // Patch `process.env` with the instance's environment
services.set(IEnvironmentMainService, environmentMainService);
@ -219,7 +216,7 @@ class CodeMain {
return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]);
}
private async doStartup(args: NativeParsedArgs, logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise<NodeIPCServer> {
private async doStartup(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise<NodeIPCServer> {
// Try to setup a server for running. If that succeeds it means
// we are the first instance to startup. Otherwise it is likely
@ -271,7 +268,7 @@ class CodeMain {
throw error;
}
return this.doStartup(args, logService, environmentMainService, lifecycleMainService, instantiationService, productService, false);
return this.doStartup(logService, environmentMainService, lifecycleMainService, instantiationService, productService, false);
}
// Tests from CLI require to be the only instance currently
@ -287,7 +284,7 @@ class CodeMain {
// Skip this if we are running with --wait where it is expected that we wait for a while.
// Also skip when gathering diagnostics (--status) which can take a longer time.
let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined;
if (!args.wait && !args.status) {
if (!environmentMainService.args.wait && !environmentMainService.args.status) {
startupWarningDialogHandle = setTimeout(() => {
this.showStartupWarningDialog(
localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", productService.nameShort),
@ -300,7 +297,7 @@ class CodeMain {
const launchService = ProxyChannel.toService<ILaunchMainService>(client.getChannel('launch'), { disableMarshalling: true });
// Process Info
if (args.status) {
if (environmentMainService.args.status) {
return instantiationService.invokeFunction(async () => {
const diagnosticsService = new DiagnosticsService(NullTelemetryService, productService);
const mainProcessInfo = await launchService.getMainProcessInfo();
@ -319,7 +316,7 @@ class CodeMain {
// Send environment over...
logService.trace('Sending env to running instance...');
await launchService.start(args, process.env as IProcessEnvironment);
await launchService.start(environmentMainService.args, process.env as IProcessEnvironment);
// Cleanup
client.dispose();
@ -333,7 +330,7 @@ class CodeMain {
}
// Print --status usage info
if (args.status) {
if (environmentMainService.args.status) {
logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.');
throw new ExpectedError('Terminating...');

View file

@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import * as os from 'os';
import { arch, release, type } from 'os';
import { IProductService } from 'vs/platform/product/common/productService';
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { ICommonIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/common/issue';
import { BrowserWindow, ipcMain, screen, IpcMainEvent, Display } from 'electron';
import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService';
@ -14,7 +13,7 @@ import { IDiagnosticsService, PerformanceInfo, isRemoteDiagnosticError } from 'v
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
import { IWindowState, toWindowUrl } from 'vs/platform/windows/electron-main/windows';
import { listProcesses } from 'vs/base/node/ps';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
@ -280,7 +279,7 @@ export class IssueMainService implements ICommonIssueService {
};
this._processExplorerWindow.loadURL(
toWindowUrl('vs/code/electron-sandbox/processExplorer/processExplorer.html', windowConfiguration));
toWindowUrl('vs/code/electron-sandbox/processExplorer/processExplorer.html', windowConfiguration, true));
this._processExplorerWindow.on('close', () => this._processExplorerWindow = null);
@ -406,9 +405,9 @@ export class IssueMainService implements ICommonIssueService {
features,
disableExtensions: this.environmentMainService.disableExtensions,
os: {
type: os.type(),
arch: os.arch(),
release: os.release(),
type: type(),
arch: arch(),
release: release(),
},
product: {
nameShort: this.productService.nameShort,
@ -420,22 +419,6 @@ export class IssueMainService implements ICommonIssueService {
}
};
return toWindowUrl('vs/code/electron-sandbox/issue/issueReporter.html', windowConfiguration);
return toWindowUrl('vs/code/electron-sandbox/issue/issueReporter.html', windowConfiguration, true);
}
}
function toWindowUrl<T>(modulePathToHtml: string, windowConfiguration: T): string {
const environment = parseArgs(process.argv, OPTIONS);
const config = Object.assign(environment, windowConfiguration);
for (const keyValue of Object.keys(config)) {
const key = keyValue as keyof typeof config;
if (config[key] === undefined || config[key] === null || config[key] === '') {
delete config[key]; // only send over properties that have a true value
}
}
return FileAccess
.asBrowserUri(modulePathToHtml, require, true)
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
.toString(true);
}

View file

@ -20,7 +20,7 @@ if (isWeb || typeof require === 'undefined' || typeof require.__$__nodeRequire !
// Running out of sources
if (Object.keys(product).length === 0) {
Object.assign(product, {
version: '1.55.0-dev',
version: '1.56.0-dev',
nameShort: isWeb ? 'Code Web - OSS Dev' : 'Code - OSS Dev',
nameLong: isWeb ? 'Code Web - OSS Dev' : 'Code - OSS Dev',
applicationName: 'code-oss',
@ -33,6 +33,7 @@ if (isWeb || typeof require === 'undefined' || typeof require.__$__nodeRequire !
'ms-vscode.vscode-js-profile-flame',
'ms-vscode.vscode-js-profile-table',
'ms-vscode.github-browser',
'ms-vscode.github-richnav',
'ms-vscode.remotehub',
'ms-vscode.remotehub-insiders'
],

View file

@ -16,7 +16,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { connect as connectMessagePort } from 'vs/base/parts/ipc/electron-main/ipc.mp';
import { assertIsDefined } from 'vs/base/common/types';
import { Emitter, Event } from 'vs/base/common/event';
import { WindowError } from 'vs/platform/windows/electron-main/windows';
import { toWindowUrl, WindowError } from 'vs/platform/windows/electron-main/windows';
import { resolveShellEnv } from 'vs/platform/environment/node/shellEnv';
export class SharedProcess extends Disposable implements ISharedProcess {
@ -189,11 +189,7 @@ export class SharedProcess extends Disposable implements ISharedProcess {
};
// Load with config
this.window.loadURL(FileAccess
.asBrowserUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require)
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
.toString(true)
);
this.window.loadURL(toWindowUrl('vs/code/electron-browser/sharedProcess/sharedProcess.html', config));
}
private registerWindowListeners(): void {

View file

@ -13,13 +13,12 @@ import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, R
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { IProductService } from 'vs/platform/product/common/productService';
import { WindowMinimumSize, IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, zoomLevelToZoomFactor, INativeWindowConfiguration } from 'vs/platform/windows/common/windows';
import { Disposable } from 'vs/base/common/lifecycle';
import { browserCodeLoadingCacheStrategy, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { defaultWindowState, ICodeWindow, ILoadEvent, IWindowState, WindowError, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { defaultWindowState, ICodeWindow, ILoadEvent, IWindowState, toWindowUrl, WindowError, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
@ -73,7 +72,9 @@ const enum ReadyState {
export class CodeWindow extends Disposable implements ICodeWindow {
private static readonly MAX_URL_LENGTH = 2 * ByteSize.MB; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32
private static readonly MAX_URL_LENGTH = 2 * ByteSize.MB; // https://source.chromium.org/chromium/chromium/src/+/master:url/url_constants.cc;l=37
//#region Events
private readonly _onWillLoad = this._register(new Emitter<ILoadEvent>());
readonly onWillLoad = this._onWillLoad.event;
@ -87,6 +88,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
private readonly _onDidDestroy = this._register(new Emitter<void>());
readonly onDidDestroy = this._onDidDestroy.event;
//#endregion
private hiddenTitleBarStyle: boolean | undefined;
private showTimeoutHandle: NodeJS.Timeout | undefined;
private windowState: IWindowState;
@ -104,6 +107,34 @@ export class CodeWindow extends Disposable implements ICodeWindow {
private currentHttpProxy: string | undefined = undefined;
private currentNoProxy: string | undefined = undefined;
private _id: number;
get id(): number { return this._id; }
private _win: BrowserWindow;
get win(): BrowserWindow | null { return this._win; }
private _lastFocusTime = -1;
get lastFocusTime(): number { return this._lastFocusTime; }
get backupPath(): string | undefined { return this.currentConfig?.backupPath; }
get openedWorkspace(): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined { return this.currentConfig?.workspace; }
get remoteAuthority(): string | undefined { return this.currentConfig?.remoteAuthority; }
private pendingLoadConfig: INativeWindowConfiguration | undefined;
private currentConfig: INativeWindowConfiguration | undefined;
get config(): INativeWindowConfiguration | undefined { return this.currentConfig; }
get hasHiddenTitleBarStyle(): boolean { return !!this.hiddenTitleBarStyle; }
get isExtensionDevelopmentHost(): boolean { return !!(this.currentConfig?.extensionDevelopmentPath); }
get isExtensionTestHost(): boolean { return !!(this.currentConfig?.extensionTestsPath); }
get isExtensionDevelopmentTestFromCli(): boolean { return this.isExtensionDevelopmentHost && this.isExtensionTestHost && !this.currentConfig?.debugId; }
constructor(
config: IWindowCreationOptions,
@ILogService private readonly logService: ILogService,
@ -132,7 +163,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// in case we are maximized or fullscreen, only show later after the call to maximize/fullscreen (see below)
const isFullscreenOrMaximized = (this.windowState.mode === WindowMode.Maximized || this.windowState.mode === WindowMode.Fullscreen);
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
const windowSettings = this.configurationService.getValue<IWindowSettings | undefined>('window');
const options: BrowserWindowConstructorOptions = {
width: this.windowState.width,
@ -152,7 +183,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
spellcheck: false,
nativeWindowOpen: true,
webviewTag: true,
zoomFactor: zoomLevelToZoomFactor(windowConfig?.zoomLevel),
zoomFactor: zoomLevelToZoomFactor(windowSettings?.zoomLevel),
...this.environmentMainService.sandbox ?
// Sandbox
@ -188,12 +219,12 @@ export class CodeWindow extends Disposable implements ICodeWindow {
if (isMacintosh) {
options.acceptFirstMouse = true; // enabled by default
if (windowConfig?.clickThroughInactive === false) {
if (windowSettings?.clickThroughInactive === false) {
options.acceptFirstMouse = false;
}
}
const useNativeTabs = isMacintosh && windowConfig?.nativeTabs === true;
const useNativeTabs = isMacintosh && windowSettings?.nativeTabs === true;
if (useNativeTabs) {
options.tabbingIdentifier = this.productService.nameShort; // this opts in to sierra tabs
}
@ -271,25 +302,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this.registerListeners();
}
private pendingLoadConfig: INativeWindowConfiguration | undefined;
private currentConfig: INativeWindowConfiguration | undefined;
get config(): INativeWindowConfiguration | undefined { return this.currentConfig; }
private _id: number;
get id(): number { return this._id; }
private _win: BrowserWindow;
get win(): BrowserWindow | null { return this._win; }
get hasHiddenTitleBarStyle(): boolean { return !!this.hiddenTitleBarStyle; }
get isExtensionDevelopmentHost(): boolean { return !!(this.currentConfig?.extensionDevelopmentPath); }
get isExtensionTestHost(): boolean { return !!(this.currentConfig?.extensionTestsPath); }
get isExtensionDevelopmentTestFromCli(): boolean { return this.isExtensionDevelopmentHost && this.isExtensionTestHost && !this.currentConfig?.debugId; }
setRepresentedFilename(filename: string): void {
if (isMacintosh) {
this._win.setRepresentedFilename(filename);
@ -345,15 +357,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this._win.focus();
}
private _lastFocusTime = -1;
get lastFocusTime(): number { return this._lastFocusTime; }
get backupPath(): string | undefined { return this.currentConfig?.backupPath; }
get openedWorkspace(): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined { return this.currentConfig?.workspace; }
get remoteAuthority(): string | undefined { return this.currentConfig?.remoteAuthority; }
private readyState = ReadyState.NONE;
setReady(): void {
@ -680,7 +683,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
}
load(config: INativeWindowConfiguration, { isReload, disableExtensions }: { isReload?: boolean, disableExtensions?: boolean } = Object.create(null)): void {
load(configuration: INativeWindowConfiguration, { isReload, disableExtensions }: { isReload?: boolean, disableExtensions?: boolean } = Object.create(null)): void {
// If this window was loaded before from the command line
// (as indicated by VSCODE_CLI environment), make sure to
@ -688,15 +691,15 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// unless the new configuration context was also a CLI
// (for https://github.com/microsoft/vscode/issues/108571)
const currentUserEnv = (this.currentConfig ?? this.pendingLoadConfig)?.userEnv;
if (currentUserEnv && isLaunchedFromCli(currentUserEnv) && !isLaunchedFromCli(config.userEnv)) {
config.userEnv = { ...currentUserEnv, ...config.userEnv }; // still allow to override certain environment as passed in
if (currentUserEnv && isLaunchedFromCli(currentUserEnv) && !isLaunchedFromCli(configuration.userEnv)) {
configuration.userEnv = { ...currentUserEnv, ...configuration.userEnv }; // still allow to override certain environment as passed in
}
// If named pipe was instantiated for the crashpad_handler process, reuse the same
// pipe for new app instances connecting to the original app instance.
// Ref: https://github.com/microsoft/vscode/issues/115874
if (process.env['CHROME_CRASHPAD_PIPE_NAME']) {
Object.assign(config.userEnv, {
Object.assign(configuration.userEnv, {
CHROME_CRASHPAD_PIPE_NAME: process.env['CHROME_CRASHPAD_PIPE_NAME']
});
}
@ -704,7 +707,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// If this is the first time the window is loaded, we associate the paths
// directly with the window because we assume the loading will just work
if (this.readyState === ReadyState.NONE) {
this.currentConfig = config;
this.currentConfig = configuration;
}
// Otherwise, the window is currently showing a folder and if there is an
@ -712,17 +715,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// because the loading might be vetoed. Instead we associate it later when
// the window load event has fired.
else {
this.pendingLoadConfig = config;
this.pendingLoadConfig = configuration;
this.readyState = ReadyState.NAVIGATING;
}
// Add disable-extensions to the config, but do not preserve it on currentConfig or
// pendingLoadConfig so that it is applied only on this load
const configuration = { ...config };
if (disableExtensions !== undefined) {
configuration['disable-extensions'] = disableExtensions;
}
// Clear Document Edited if needed
if (this.isDocumentEdited()) {
if (!isReload || !this.backupMainService.isHotExitEnabled()) {
@ -741,7 +737,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// Load URL
mark('code/willOpenNewWindow');
this._win.loadURL(this.getUrl(configuration));
this._win.loadURL(this.getUrl(configuration, disableExtensions));
// Make window visible if it did not open in N seconds because this indicates an error
// Only do this when running out of sources and not when running tests
@ -816,64 +812,63 @@ export class CodeWindow extends Disposable implements ICodeWindow {
return configuration.workspace;
}
private getUrl(windowConfiguration: INativeWindowConfiguration): string {
private getUrl(baseConfig: INativeWindowConfiguration, disableExtensions: boolean | undefined): string {
// Config is a combination of native CLI args and window configuration
const configuration: { [key: string]: unknown } = { ...this.environmentMainService.args, ...baseConfig };
// Add disable-extensions to the config, but do not preserve it on currentConfig or
// pendingLoadConfig so that it is applied only on this load
if (disableExtensions !== undefined) {
configuration['disable-extensions'] = disableExtensions;
}
// Set window ID
windowConfiguration.windowId = this._win.id;
windowConfiguration.sessionId = `window:${this._win.id}`;
windowConfiguration.logLevel = this.logService.getLevel();
windowConfiguration.logsPath = this.environmentMainService.logsPath;
configuration.windowId = this._win.id;
configuration.sessionId = `window:${this._win.id}`;
configuration.logLevel = this.logService.getLevel();
configuration.logsPath = this.environmentMainService.logsPath;
// Set zoomlevel
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
const zoomLevel = windowConfig?.zoomLevel;
if (typeof zoomLevel === 'number') {
windowConfiguration.zoomLevel = zoomLevel;
configuration.zoomLevel = zoomLevel;
}
// Set fullscreen state
windowConfiguration.fullscreen = this.isFullScreen;
configuration.fullscreen = this.isFullScreen;
// Set Accessibility Config
windowConfiguration.colorScheme = {
configuration.colorScheme = {
dark: nativeTheme.shouldUseDarkColors,
highContrast: nativeTheme.shouldUseInvertedColorScheme || nativeTheme.shouldUseHighContrastColors
};
windowConfiguration.autoDetectHighContrast = windowConfig?.autoDetectHighContrast ?? true;
windowConfiguration.accessibilitySupport = app.accessibilitySupportEnabled;
configuration.autoDetectHighContrast = windowConfig?.autoDetectHighContrast ?? true;
configuration.accessibilitySupport = app.accessibilitySupportEnabled;
// Title style related
windowConfiguration.maximized = this._win.isMaximized();
configuration.maximized = this._win.isMaximized();
// Dump Perf Counters
windowConfiguration.perfMarks = getMarks();
configuration.perfMarks = getMarks();
// Parts splash
windowConfiguration.partsSplashPath = join(this.environmentMainService.userDataPath, 'rapid_render.json');
configuration.partsSplashPath = join(this.environmentMainService.userDataPath, 'rapid_render.json');
// OS Info
windowConfiguration.os = {
configuration.os = {
release: release()
};
// Config (combination of process.argv and window configuration)
const environment = parseArgs(process.argv, OPTIONS);
const config = Object.assign(environment, windowConfiguration) as unknown as { [key: string]: unknown };
for (const key in config) {
const configValue = config[key];
if (configValue === undefined || configValue === null || configValue === '' || configValue === false) {
delete config[key]; // only send over properties that have a true value
}
}
// In the unlikely event of the URL becoming larger than 2MB, remove parts of
// it that are not under our control. Mainly, the user environment can be very
// large depending on user configuration, so we can only remove it in that case.
let configUrl = this.doGetUrl(config);
let configUrl = this.doGetUrl(configuration);
if (configUrl.length > CodeWindow.MAX_URL_LENGTH) {
this.logService.warn('Application URL exceeds maximum of 2MB and was shortened.');
configUrl = this.doGetUrl({ ...config, userEnv: undefined });
configUrl = this.doGetUrl({ ...configuration, userEnv: undefined });
if (configUrl.length > CodeWindow.MAX_URL_LENGTH) {
this.logService.error('Application URL exceeds maximum of 2MB and cannot be loaded.');
@ -891,10 +886,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
workbench = 'vs/code/electron-browser/workbench/workbench.html';
}
return FileAccess
.asBrowserUri(workbench, require)
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
.toString(true);
return toWindowUrl(workbench, config);
}
serializeWindowState(): IWindowState {

View file

@ -14,6 +14,7 @@ import { URI } from 'vs/base/common/uri';
import { Rectangle, BrowserWindow, WebContents } from 'electron';
import { IDisposable } from 'vs/base/common/lifecycle';
import { CancellationToken } from 'vs/base/common/cancellation';
import { FileAccess } from 'vs/base/common/network';
export const enum OpenContext {
@ -206,3 +207,28 @@ export interface IOpenConfiguration extends IBaseOpenConfiguration {
}
export interface IOpenEmptyConfiguration extends IBaseOpenConfiguration { }
/**
* Utility to produce a window URL that includes the provided configuration
* as query parameter.
*
* @param modulePathToHtml path to the HTML to load
* @param config the configuration for the window
* @returns the url to use for loading
*/
export function toWindowUrl(modulePathToHtml: string, config: object, forceCodeFileUri?: boolean): string {
const configuration: { [key: string]: unknown } = { ...config };
// Remove values from config that are falsy to reduce the size of of the URL we create
for (const key in configuration) {
const value = configuration[key];
if (value === undefined || value === null || value === '' || value === false) {
delete configuration[key];
}
}
return FileAccess
.asBrowserUri(modulePathToHtml, require, forceCodeFileUri)
.with({ query: `config=${encodeURIComponent(JSON.stringify(configuration))}` })
.toString(true);
}