Merge from vscode e3c4990c67c40213af168300d1cfeb71d680f877 (#16569)

This commit is contained in:
Cory Rivera
2021-08-25 16:28:29 -07:00
committed by GitHub
parent ab1112bfb3
commit cb7b7da0a4
1752 changed files with 59525 additions and 33878 deletions

View File

@@ -56,8 +56,7 @@ export interface IOpenedWindow {
readonly dirty: boolean;
}
export interface IOpenEmptyWindowOptions extends IBaseOpenWindowsOptions {
}
export interface IOpenEmptyWindowOptions extends IBaseOpenWindowsOptions { }
export type IWindowOpenable = IWorkspaceToOpen | IFolderToOpen | IFileToOpen;
@@ -233,6 +232,31 @@ export interface IOSConfiguration {
readonly hostname: string;
}
export interface IPartsSplash {
baseTheme: string;
colorInfo: {
background: string;
foreground: string | undefined;
editorBackground: string | undefined;
titleBarBackground: string | undefined;
activityBarBackground: string | undefined;
sideBarBackground: string | undefined;
statusBarBackground: string | undefined;
statusBarNoFolderBackground: string | undefined;
windowBorder: string | undefined;
}
layoutInfo: {
sideBarSide: string;
editorPartMinWidth: number;
titleBarHeight: number;
activityBarWidth: number;
sideBarWidth: number;
statusBarHeight: number;
windowBorder: boolean;
windowBorderRadius: string | undefined;
} | undefined
}
export interface INativeWindowConfiguration extends IWindowConfiguration, NativeParsedArgs, ISandboxConfiguration {
mainPid: number;
@@ -245,7 +269,7 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native
tmpDir: string;
userDataDir: string;
partsSplashPath: string;
partsSplash?: IPartsSplash;
workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier;

View File

@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import { getMarks, mark } from 'vs/base/common/performance';
import { Emitter } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, Event, RenderProcessGoneDetails, WebFrameMain } from 'electron';
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, Event, WebFrameMain } from 'electron';
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';
@@ -186,7 +186,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
[`--vscode-window-config=${this.configObjectUrl.resource.toString()}`],
v8CacheOptions: browserCodeLoadingCacheStrategy,
enableWebSQL: false,
enableRemoteModule: false,
spellcheck: false,
nativeWindowOpen: true,
webviewTag: true,
@@ -207,9 +206,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
};
if (browserCodeLoadingCacheStrategy) {
this.logService.info(`window#ctor: using vscode-file:// protocol and V8 cache options: ${browserCodeLoadingCacheStrategy}`);
this.logService.info(`window: using vscode-file:// protocol and V8 cache options: ${browserCodeLoadingCacheStrategy}`);
} else {
this.logService.trace(`window#ctor: vscode-file:// protocol is explicitly disabled`);
this.logService.info(`window: vscode-file:// protocol is explicitly disabled`);
}
// Apply icon to window
@@ -420,7 +419,16 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// Crashes & Unresponsive & Failed to load
this._win.on('unresponsive', () => this.onWindowError(WindowError.UNRESPONSIVE));
this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details));
this._win.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this.onWindowError(WindowError.LOAD, errorDescription));
this._win.webContents.on('did-fail-load', (event, exitCode, reason) => this.onWindowError(WindowError.LOAD, { reason, exitCode }));
// Prevent windows/iframes from blocking the unload
// through DOM events. We have our own logic for
// unloading a window that should not be confused
// with the DOM way.
// (https://github.com/microsoft/vscode/issues/122736)
this._win.webContents.on('will-prevent-unload', event => {
event.preventDefault();
});
// Window close
this._win.on('closed', () => {
@@ -430,7 +438,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
});
// Block all SVG requests from unsupported origins
const supportedSvgSchemes = new Set([Schemas.file, Schemas.vscodeFileResource, Schemas.vscodeRemoteResource, 'devtools']); // TODO: handle webview origin
const supportedSvgSchemes = new Set([Schemas.file, Schemas.vscodeFileResource, Schemas.vscodeRemoteResource, 'devtools']); // TODO@mjbvz: handle webview origin
// But allow them if the are made from inside an webview
const isSafeFrame = (requestFrame: WebFrameMain | undefined): boolean => {
@@ -442,13 +450,16 @@ export class CodeWindow extends Disposable implements ICodeWindow {
return false;
};
const isRequestFromSafeContext = (details: Electron.OnBeforeRequestListenerDetails | Electron.OnHeadersReceivedListenerDetails): boolean => {
return details.resourceType === 'xhr' || isSafeFrame(details.frame);
};
this._win.webContents.session.webRequest.onBeforeRequest((details, callback) => {
const uri = URI.parse(details.url);
if (uri.path.endsWith('.svg')) {
const isSafeResourceUrl = supportedSvgSchemes.has(uri.scheme) || uri.path.includes(Schemas.vscodeRemoteResource);
if (!isSafeResourceUrl) {
const isSafeContext = isSafeFrame(details.frame);
return callback({ cancel: !isSafeContext });
return callback({ cancel: !isRequestFromSafeContext(details) });
}
}
@@ -474,8 +485,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// remote extension schemes have the following format
// http://127.0.0.1:<port>/vscode-remote-resource?path=
if (!uri.path.includes(Schemas.vscodeRemoteResource) && contentTypes.some(contentType => contentType.toLowerCase().includes('image/svg'))) {
const isSafeContext = isSafeFrame(details.frame);
return callback({ cancel: !isSafeContext });
return callback({ cancel: !isRequestFromSafeContext(details) });
}
}
@@ -541,19 +551,19 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
private async onWindowError(error: WindowError.UNRESPONSIVE): Promise<void>;
private async onWindowError(error: WindowError.CRASHED, details: RenderProcessGoneDetails): Promise<void>;
private async onWindowError(error: WindowError.LOAD, details: string): Promise<void>;
private async onWindowError(type: WindowError, details?: string | RenderProcessGoneDetails): Promise<void> {
private async onWindowError(error: WindowError.CRASHED, details: { reason: string, exitCode: number }): Promise<void>;
private async onWindowError(error: WindowError.LOAD, details: { reason: string, exitCode: number }): Promise<void>;
private async onWindowError(type: WindowError, details?: { reason: string, exitCode: number }): Promise<void> {
switch (type) {
case WindowError.CRASHED:
this.logService.error(`CodeWindow: renderer process crashed (detail: ${typeof details === 'string' ? details : details?.reason})`);
this.logService.error(`CodeWindow: renderer process crashed (reason: ${details?.reason || '<unknown>'}, code: ${details?.exitCode || '<unknown>'})`);
break;
case WindowError.UNRESPONSIVE:
this.logService.error('CodeWindow: detected unresponsive');
break;
case WindowError.LOAD:
this.logService.error(`CodeWindow: failed to load workbench window: ${typeof details === 'string' ? details : details?.reason}`);
this.logService.error(`CodeWindow: failed to load workbench window (reason: ${details?.reason || '<unknown>'}, code: ${details?.exitCode || '<unknown>'})`);
break;
}
@@ -569,12 +579,14 @@ export class CodeWindow extends Disposable implements ICodeWindow {
type WindowErrorClassification = {
type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
reason: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
code: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
};
type WindowErrorEvent = {
type: WindowError;
reason: string | undefined;
code: number | undefined;
};
this.telemetryService.publicLog2<WindowErrorEvent, WindowErrorClassification>('windowerror', { type, reason: typeof details !== 'string' ? details?.reason : undefined });
this.telemetryService.publicLog2<WindowErrorEvent, WindowErrorClassification>('windowerror', { type, reason: details?.reason, code: details?.exitCode });
// Unresponsive
if (type === WindowError.UNRESPONSIVE) {
@@ -613,10 +625,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// Crashed
else if (type === WindowError.CRASHED) {
let message: string;
if (typeof details === 'string' || !details) {
if (!details) {
message = localize('appCrashed', "The window has crashed");
} else {
message = localize('appCrashedDetails', "The window has crashed (reason: '{0}')", details.reason);
message = localize('appCrashedDetails', "The window has crashed (reason: '{0}', code: '{1}')", details.reason, details.exitCode ?? '<unknown>');
}
const result = await this.dialogMainService.showMessageBox({
@@ -641,8 +653,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
private destroyWindow(): void {
this._onDidDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event
this._win.destroy(); // make sure to destroy the window as it has crashed
this._onDidDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event
this._win.destroy(); // make sure to destroy the window as it has crashed
}
private onDidDeleteUntitledWorkspace(workspace: IWorkspaceIdentifier): void {
@@ -779,6 +791,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// Update window related properties
configuration.fullscreen = this.isFullScreen;
configuration.maximized = this._win.isMaximized();
configuration.partsSplash = this.themeMainService.getWindowSplash();
// Update with latest perf marks
mark('code/willOpenNewWindow');

View File

@@ -8,7 +8,7 @@ import { IWorkspaceIdentifier, IResolvedWorkspace, isWorkspaceIdentifier, isSing
import { extUriBiasedIgnorePathCase } from 'vs/base/common/resources';
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
export function findWindowOnFile(windows: ICodeWindow[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): ICodeWindow | undefined {
export function findWindowOnFile(windows: ICodeWindow[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | undefined): ICodeWindow | undefined {
// First check for windows with workspaces that have a parent folder of the provided path opened
for (const window of windows) {

View File

@@ -14,7 +14,7 @@ import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { IStateService } from 'vs/platform/state/node/state';
import { IStateMainService } from 'vs/platform/state/electron-main/state';
import { CodeWindow } from 'vs/platform/windows/electron-main/window';
import { app, BrowserWindow, MessageBoxOptions, nativeTheme, WebContents } from 'electron';
import { ILifecycleMainService, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
@@ -139,13 +139,13 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
private readonly _onDidChangeWindowsCount = this._register(new Emitter<IWindowsCountChangedEvent>());
readonly onDidChangeWindowsCount = this._onDidChangeWindowsCount.event;
private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateService, this.lifecycleMainService, this.logService, this.configurationService));
private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateMainService, this.lifecycleMainService, this.logService, this.configurationService));
constructor(
private readonly machineId: string,
private readonly initialUserEnv: IProcessEnvironment,
@ILogService private readonly logService: ILogService,
@IStateService private readonly stateService: IStateService,
@IStateMainService private readonly stateMainService: IStateMainService,
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@IBackupMainService private readonly backupMainService: IBackupMainService,
@@ -409,7 +409,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
let windowToUseForFiles: ICodeWindow | undefined = undefined;
if (fileToCheck?.fileUri && !openFilesInNewWindow) {
if (openConfig.context === OpenContext.DESKTOP || openConfig.context === OpenContext.CLI || openConfig.context === OpenContext.DOCK) {
windowToUseForFiles = findWindowOnFile(windows, fileToCheck.fileUri, workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesManagementMainService.resolveLocalWorkspaceSync(workspace.configPath) : null);
windowToUseForFiles = findWindowOnFile(windows, fileToCheck.fileUri, workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesManagementMainService.resolveLocalWorkspaceSync(workspace.configPath) : undefined);
}
if (!windowToUseForFiles) {
@@ -856,6 +856,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
if (isFileToOpen(openable)) {
options = { ...options, forceOpenWorkspaceAsFile: true };
}
return this.doResolveFilePath(uri.fsPath, options);
}
@@ -1168,8 +1169,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
appRoot: this.environmentMainService.appRoot,
execPath: process.execPath,
nodeCachedDataDir: this.environmentMainService.nodeCachedDataDir,
partsSplashPath: join(this.environmentMainService.userDataPath, 'rapid_render.json'),
codeCachePath: this.environmentMainService.codeCachePath,
// If we know the backup folder upfront (for empty windows to restore), we can set it
// directly here which helps for restoring UI state associated with that window.
// For all other cases we first call into registerEmptyWindowBackupSync() to set it before

View File

@@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/node/state';
import { IStateMainService } from 'vs/platform/state/electron-main/state';
import { INativeWindowConfiguration, IWindowSettings } from 'vs/platform/windows/common/windows';
import { defaultWindowState, ICodeWindow, IWindowsMainService, IWindowState as IWindowUIState, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
@@ -53,7 +53,7 @@ export class WindowsStateHandler extends Disposable {
private static readonly windowsStateStorageKey = 'windowsState';
get state() { return this._state; }
private readonly _state = restoreWindowsState(this.stateService.getItem<ISerializedWindowsState>(WindowsStateHandler.windowsStateStorageKey));
private readonly _state = restoreWindowsState(this.stateMainService.getItem<ISerializedWindowsState>(WindowsStateHandler.windowsStateStorageKey));
private lastClosedState: IWindowState | undefined = undefined;
@@ -61,7 +61,7 @@ export class WindowsStateHandler extends Disposable {
constructor(
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@IStateService private readonly stateService: IStateService,
@IStateMainService private readonly stateMainService: IStateMainService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@ILogService private readonly logService: ILogService,
@IConfigurationService private readonly configurationService: IConfigurationService
@@ -177,7 +177,7 @@ export class WindowsStateHandler extends Disposable {
// Persist
const state = getWindowsStateStoreData(currentWindowsState);
this.stateService.setItem(WindowsStateHandler.windowsStateStorageKey, state);
this.stateMainService.setItem(WindowsStateHandler.windowsStateStorageKey, state);
if (this.shuttingDown) {
this.logService.trace('[WindowsStateHandler] onBeforeShutdown', state);
@@ -232,9 +232,11 @@ export class WindowsStateHandler extends Disposable {
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
// Window state is not from a previous session: only allow fullscreen if we inherit it or user wants fullscreen
// or to address a Electron issue on macOS (https://github.com/microsoft/vscode/issues/125122)
let allowFullscreen: boolean;
if (state.hasDefaultState) {
allowFullscreen = !!(windowConfig?.newWindowDimensions && ['fullscreen', 'inherit', 'offset'].indexOf(windowConfig.newWindowDimensions) >= 0);
const configAllowsFullScreen = !!(windowConfig?.newWindowDimensions && ['fullscreen', 'inherit', 'offset'].indexOf(windowConfig.newWindowDimensions) >= 0);
allowFullscreen = configAllowsFullScreen || (isMacintosh && windowConfig?.nativeFullScreen !== false);
}
// Window state is from a previous session: only allow fullscreen when we got updated or user wants to restore
@@ -337,14 +339,22 @@ export class WindowsStateHandler extends Disposable {
// Compute x/y based on display bounds
// Note: important to use Math.round() because Electron does not seem to be too happy about
// display coordinates that are not absolute numbers.
let state = defaultWindowState();
let state: INewWindowState = defaultWindowState();
state.x = Math.round(displayToUse.bounds.x + (displayToUse.bounds.width / 2) - (state.width! / 2));
state.y = Math.round(displayToUse.bounds.y + (displayToUse.bounds.height / 2) - (state.height! / 2));
// Check for newWindowDimensions setting and adjust accordingly
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
let ensureNoOverlap = true;
if (windowConfig?.newWindowDimensions) {
// TODO@electron macOS: if the current window is fullscreen and native fullscreen
// is not disabled, always open a new window in fullscreen. This is a workaround
// for regression https://github.com/microsoft/vscode/issues/125122
if (isMacintosh && windowConfig?.nativeFullScreen !== false && lastActive?.isFullScreen) {
state.mode = WindowMode.Fullscreen;
}
// Adjust according to `newWindowDimensions` user setting
else if (windowConfig?.newWindowDimensions) {
if (windowConfig.newWindowDimensions === 'maximized') {
state.mode = WindowMode.Maximized;
ensureNoOverlap = false;
@@ -367,7 +377,7 @@ export class WindowsStateHandler extends Disposable {
state = this.ensureNoOverlap(state);
}
(state as INewWindowState).hasDefaultState = true; // flag as default state
state.hasDefaultState = true; // flag as default state
return state;
}

View File

@@ -28,7 +28,7 @@ suite('WindowsFinder', () => {
};
const testWorkspaceFolders = toWorkspaceFolders([{ path: join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath, extUriBiasedIgnorePathCase);
const localWorkspaceResolver = (workspace: any) => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : null; };
const localWorkspaceResolver = (workspace: any) => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : undefined; };
function createTestCodeWindow(options: { lastFocusTime: number, openedFolderUri?: URI, openedWorkspace?: IWorkspaceIdentifier }): ICodeWindow {
return new class implements ICodeWindow {

View File

@@ -0,0 +1,201 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { tmpdir } from 'os';
import { join } from 'vs/base/common/path';
import { restoreWindowsState, getWindowsStateStoreData, IWindowsState, IWindowState } from 'vs/platform/windows/electron-main/windowsStateHandler';
import { IWindowState as IWindowUIState, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
suite('Windows State Storing', () => {
function getUIState(): IWindowUIState {
return {
x: 0,
y: 10,
width: 100,
height: 200,
mode: 0
};
}
function toWorkspace(uri: URI): IWorkspaceIdentifier {
return {
id: '1234',
configPath: uri
};
}
function assertEqualURI(u1: URI | undefined, u2: URI | undefined, message?: string): void {
assert.strictEqual(u1 && u1.toString(), u2 && u2.toString(), message);
}
function assertEqualWorkspace(w1: IWorkspaceIdentifier | undefined, w2: IWorkspaceIdentifier | undefined, message?: string): void {
if (!w1 || !w2) {
assert.strictEqual(w1, w2, message);
return;
}
assert.strictEqual(w1.id, w2.id, message);
assertEqualURI(w1.configPath, w2.configPath, message);
}
function assertEqualWindowState(expected: IWindowState | undefined, actual: IWindowState | undefined, message?: string) {
if (!expected || !actual) {
assert.deepStrictEqual(expected, actual, message);
return;
}
assert.strictEqual(expected.backupPath, actual.backupPath, message);
assertEqualURI(expected.folderUri, actual.folderUri, message);
assert.strictEqual(expected.remoteAuthority, actual.remoteAuthority, message);
assertEqualWorkspace(expected.workspace, actual.workspace, message);
assert.deepStrictEqual(expected.uiState, actual.uiState, message);
}
function assertEqualWindowsState(expected: IWindowsState, actual: IWindowsState, message?: string) {
assertEqualWindowState(expected.lastPluginDevelopmentHostWindow, actual.lastPluginDevelopmentHostWindow, message);
assertEqualWindowState(expected.lastActiveWindow, actual.lastActiveWindow, message);
assert.strictEqual(expected.openedWindows.length, actual.openedWindows.length, message);
for (let i = 0; i < expected.openedWindows.length; i++) {
assertEqualWindowState(expected.openedWindows[i], actual.openedWindows[i], message);
}
}
function assertRestoring(state: IWindowsState, message?: string) {
const stored = getWindowsStateStoreData(state);
const restored = restoreWindowsState(stored);
assertEqualWindowsState(state, restored, message);
}
const testBackupPath1 = join(tmpdir(), 'windowStateTest', 'backupFolder1');
const testBackupPath2 = join(tmpdir(), 'windowStateTest', 'backupFolder2');
const testWSPath = URI.file(join(tmpdir(), 'windowStateTest', 'test.code-workspace'));
const testFolderURI = URI.file(join(tmpdir(), 'windowStateTest', 'testFolder'));
const testRemoteFolderURI = URI.parse('foo://bar/c/d');
test('storing and restoring', () => {
let windowState: IWindowsState;
windowState = {
openedWindows: []
};
assertRestoring(windowState, 'no windows');
windowState = {
openedWindows: [{ backupPath: testBackupPath1, uiState: getUIState() }]
};
assertRestoring(windowState, 'empty workspace');
windowState = {
openedWindows: [{ backupPath: testBackupPath1, uiState: getUIState(), workspace: toWorkspace(testWSPath) }]
};
assertRestoring(windowState, 'workspace');
windowState = {
openedWindows: [{ backupPath: testBackupPath2, uiState: getUIState(), folderUri: testFolderURI }]
};
assertRestoring(windowState, 'folder');
windowState = {
openedWindows: [{ backupPath: testBackupPath1, uiState: getUIState(), folderUri: testFolderURI }, { backupPath: testBackupPath1, uiState: getUIState(), folderUri: testRemoteFolderURI, remoteAuthority: 'bar' }]
};
assertRestoring(windowState, 'multiple windows');
windowState = {
lastActiveWindow: { backupPath: testBackupPath2, uiState: getUIState(), folderUri: testFolderURI },
openedWindows: []
};
assertRestoring(windowState, 'lastActiveWindow');
windowState = {
lastPluginDevelopmentHostWindow: { backupPath: testBackupPath2, uiState: getUIState(), folderUri: testFolderURI },
openedWindows: []
};
assertRestoring(windowState, 'lastPluginDevelopmentHostWindow');
});
test('open 1_32', () => {
const v1_32_workspace = `{
"openedWindows": [],
"lastActiveWindow": {
"workspaceIdentifier": {
"id": "53b714b46ef1a2d4346568b4f591028c",
"configURIPath": "file:///home/user/workspaces/testing/custom.code-workspace"
},
"backupPath": "/home/user/.config/code-oss-dev/Backups/53b714b46ef1a2d4346568b4f591028c",
"uiState": {
"mode": 0,
"x": 0,
"y": 27,
"width": 2560,
"height": 1364
}
}
}`;
let windowsState = restoreWindowsState(JSON.parse(v1_32_workspace));
let expected: IWindowsState = {
openedWindows: [],
lastActiveWindow: {
backupPath: '/home/user/.config/code-oss-dev/Backups/53b714b46ef1a2d4346568b4f591028c',
uiState: { mode: WindowMode.Maximized, x: 0, y: 27, width: 2560, height: 1364 },
workspace: { id: '53b714b46ef1a2d4346568b4f591028c', configPath: URI.parse('file:///home/user/workspaces/testing/custom.code-workspace') }
}
};
assertEqualWindowsState(expected, windowsState, 'v1_32_workspace');
const v1_32_folder = `{
"openedWindows": [],
"lastActiveWindow": {
"folder": "file:///home/user/workspaces/testing/folding",
"backupPath": "/home/user/.config/code-oss-dev/Backups/1daac1621c6c06f9e916ac8062e5a1b5",
"uiState": {
"mode": 1,
"x": 625,
"y": 263,
"width": 1718,
"height": 953
}
}
}`;
windowsState = restoreWindowsState(JSON.parse(v1_32_folder));
expected = {
openedWindows: [],
lastActiveWindow: {
backupPath: '/home/user/.config/code-oss-dev/Backups/1daac1621c6c06f9e916ac8062e5a1b5',
uiState: { mode: WindowMode.Normal, x: 625, y: 263, width: 1718, height: 953 },
folderUri: URI.parse('file:///home/user/workspaces/testing/folding')
}
};
assertEqualWindowsState(expected, windowsState, 'v1_32_folder');
const v1_32_empty_window = ` {
"openedWindows": [
],
"lastActiveWindow": {
"backupPath": "/home/user/.config/code-oss-dev/Backups/1549539668998",
"uiState": {
"mode": 1,
"x": 768,
"y": 336,
"width": 1024,
"height": 768
}
}
}`;
windowsState = restoreWindowsState(JSON.parse(v1_32_empty_window));
expected = {
openedWindows: [],
lastActiveWindow: {
backupPath: '/home/user/.config/code-oss-dev/Backups/1549539668998',
uiState: { mode: WindowMode.Normal, x: 768, y: 336, width: 1024, height: 768 }
}
};
assertEqualWindowsState(expected, windowsState, 'v1_32_empty_window');
});
});