chore(vscode): update to 1.54.2

This commit is contained in:
Joe Previte
2021-03-11 10:27:10 -07:00
1459 changed files with 53404 additions and 51004 deletions

View File

@@ -45,7 +45,7 @@ export interface IWorkspacesService {
getWorkspaceIdentifier(workspacePath: URI): Promise<IWorkspaceIdentifier>;
// Workspaces History
readonly onRecentlyOpenedChange: Event<void>;
readonly onDidChangeRecentlyOpened: Event<void>;
addRecentlyOpened(recents: IRecent[]): Promise<void>;
removeRecentlyOpened(workspaces: URI[]): Promise<void>;
clearRecentlyOpened(): Promise<void>;
@@ -116,6 +116,10 @@ export interface ISingleFolderWorkspaceIdentifier extends IBaseWorkspaceIdentifi
uri: URI;
}
export interface ISerializedSingleFolderWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
uri: UriComponents;
}
export function isSingleFolderWorkspaceIdentifier(obj: unknown): obj is ISingleFolderWorkspaceIdentifier {
const singleFolderIdentifier = obj as ISingleFolderWorkspaceIdentifier | undefined;
@@ -133,6 +137,10 @@ export interface IWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
configPath: URI;
}
export interface ISerializedWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
configPath: UriComponents;
}
export function toWorkspaceIdentifier(workspace: IWorkspace): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined {
// Multi root
@@ -161,13 +169,28 @@ export function isWorkspaceIdentifier(obj: unknown): obj is IWorkspaceIdentifier
return typeof workspaceIdentifier?.id === 'string' && URI.isUri(workspaceIdentifier.configPath);
}
export function reviveIdentifier(identifier: { id: string, uri?: UriComponents, configPath?: UriComponents } | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined {
if (identifier?.uri) {
return { id: identifier.id, uri: URI.revive(identifier.uri) };
export function reviveIdentifier(identifier: undefined): undefined;
export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier): IWorkspaceIdentifier;
export function reviveIdentifier(identifier: ISerializedSingleFolderWorkspaceIdentifier): ISingleFolderWorkspaceIdentifier;
export function reviveIdentifier(identifier: IEmptyWorkspaceIdentifier): IEmptyWorkspaceIdentifier;
export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined;
export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined {
// Single Folder
const singleFolderIdentifierCandidate = identifier as ISerializedSingleFolderWorkspaceIdentifier | undefined;
if (singleFolderIdentifierCandidate?.uri) {
return { id: singleFolderIdentifierCandidate.id, uri: URI.revive(singleFolderIdentifierCandidate.uri) };
}
if (identifier?.configPath) {
return { id: identifier.id, configPath: URI.revive(identifier.configPath) };
// Multi folder
const workspaceIdentifierCandidate = identifier as ISerializedWorkspaceIdentifier | undefined;
if (workspaceIdentifierCandidate?.configPath) {
return { id: workspaceIdentifierCandidate.id, configPath: URI.revive(workspaceIdentifierCandidate.configPath) };
}
// Empty
if (identifier?.id) {
return { id: identifier.id };
}
return undefined;
@@ -177,9 +200,9 @@ export function isUntitledWorkspace(path: URI, environmentService: IEnvironmentS
return extUriBiasedIgnorePathCase.isEqualOrParent(path, environmentService.untitledWorkspacesHome);
}
export interface IEmptyWorkspaceInitializationPayload extends IBaseWorkspaceIdentifier { }
export interface IEmptyWorkspaceIdentifier extends IBaseWorkspaceIdentifier { }
export type IWorkspaceInitializationPayload = IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceInitializationPayload;
export type IWorkspaceInitializationPayload = IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier;
//#endregion

View File

@@ -8,13 +8,13 @@ import { coalesce } from 'vs/base/common/arrays';
import { IStateService } from 'vs/platform/state/node/state';
import { app, JumpListCategory, JumpListItem } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { getBaseLabel, getPathLabel, splitName } from 'vs/base/common/labels';
import { normalizeDriveLetter, splitName } from 'vs/base/common/labels';
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
import { isWindows, isMacintosh } from 'vs/base/common/platform';
import { IWorkspaceIdentifier, IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile, toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData, WORKSPACE_EXTENSION, isWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
import { ThrottledDelayer } from 'vs/base/common/async';
import { dirname, originalFSPath, basename, extUriBiasedIgnorePathCase } from 'vs/base/common/resources';
import { originalFSPath, basename, extUriBiasedIgnorePathCase } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
@@ -30,7 +30,7 @@ export interface IWorkspacesHistoryMainService {
readonly _serviceBrand: undefined;
readonly onRecentlyOpenedChange: CommonEvent<void>;
readonly onDidChangeRecentlyOpened: CommonEvent<void>;
addRecentlyOpened(recents: IRecent[]): void;
getRecentlyOpened(include?: ICodeWindow): IRecentlyOpened;
@@ -57,8 +57,8 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
declare readonly _serviceBrand: undefined;
private readonly _onRecentlyOpenedChange = this._register(new Emitter<void>());
readonly onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
private readonly _onDidChangeRecentlyOpened = this._register(new Emitter<void>());
readonly onDidChangeRecentlyOpened: CommonEvent<void> = this._onDidChangeRecentlyOpened.event;
private readonly macOSRecentDocumentsUpdater = this._register(new ThrottledDelayer<void>(800));
@@ -66,7 +66,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
@IStateService private readonly stateService: IStateService,
@ILogService private readonly logService: ILogService,
@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService,
@IEnvironmentMainService private readonly environmentService: IEnvironmentMainService,
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService
) {
super();
@@ -80,7 +80,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList());
// Add to history when entering workspace
this._register(this.workspacesManagementMainService.onWorkspaceEntered(event => this.addRecentlyOpened([{ workspace: event.workspace }])));
this._register(this.workspacesManagementMainService.onDidEnterWorkspace(event => this.addRecentlyOpened([{ workspace: event.workspace }])));
}
private handleWindowsJumpList(): void {
@@ -89,7 +89,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
}
this.updateWindowsJumpList();
this._register(this.onRecentlyOpenedChange(() => this.updateWindowsJumpList()));
this._register(this.onDidChangeRecentlyOpened(() => this.updateWindowsJumpList()));
}
addRecentlyOpened(recentToAdd: IRecent[]): void {
@@ -139,7 +139,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
}
this.saveRecentlyOpened({ workspaces, files });
this._onRecentlyOpenedChange.fire();
this._onDidChangeRecentlyOpened.fire();
// Schedule update to recent documents on macOS dock
if (isMacintosh) {
@@ -165,7 +165,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
if (workspaces.length !== mru.workspaces.length || files.length !== mru.files.length) {
this.saveRecentlyOpened({ files, workspaces });
this._onRecentlyOpenedChange.fire();
this._onDidChangeRecentlyOpened.fire();
// Schedule update to recent documents on macOS dock
if (isMacintosh) {
@@ -238,7 +238,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
app.clearRecentDocuments();
// Event
this._onRecentlyOpenedChange.fire();
this._onDidChangeRecentlyOpened.fire();
}
getRecentlyOpened(include?: ICodeWindow): IRecentlyOpened {
@@ -350,16 +350,13 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
let hasWorkspaces = false;
const items: JumpListItem[] = coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => {
const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri;
const title = recent.label ? splitName(recent.label).name : this.getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome);
let description;
const { title, description } = this.getWindowsJumpListLabel(workspace, recent.label);
let args;
if (URI.isUri(workspace)) {
description = localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService));
args = `--folder-uri "${workspace.toString()}"`;
} else {
hasWorkspaces = true;
description = localize('workspaceDesc', "{0} {1}", getBaseLabel(workspace.configPath), getPathLabel(dirname(workspace.configPath), this.environmentService));
args = `--file-uri "${workspace.configPath.toString()}"`;
}
@@ -395,16 +392,18 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
}
}
private getSimpleWorkspaceLabel(workspace: IWorkspaceIdentifier | URI, workspaceHome: URI): string {
private getWindowsJumpListLabel(workspace: IWorkspaceIdentifier | URI, recentLabel: string | undefined): { title: string; description: string } {
if (recentLabel) {
return { title: splitName(recentLabel).name, description: recentLabel };
}
// Single Folder
if (URI.isUri(workspace)) {
return basename(workspace);
return { title: basename(workspace), description: renderJumpListPathDescription(workspace) };
}
// Workspace: Untitled
if (extUriBiasedIgnorePathCase.isEqualOrParent(workspace.configPath, workspaceHome)) {
return localize('untitledWorkspace', "Untitled (Workspace)");
if (extUriBiasedIgnorePathCase.isEqualOrParent(workspace.configPath, this.environmentMainService.userHome)) {
return { title: localize('untitledWorkspace', "Untitled (Workspace)"), description: '' };
}
// Workspace: normal
@@ -413,10 +412,14 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
filename = filename.substr(0, filename.length - WORKSPACE_EXTENSION.length - 1);
}
return localize('workspaceName', "{0} (Workspace)", filename);
return { title: localize('workspaceName', "{0} (Workspace)", filename), description: renderJumpListPathDescription(workspace.configPath) };
}
}
function renderJumpListPathDescription(uri: URI) {
return uri.scheme === 'file' ? normalizeDriveLetter(uri.fsPath) : uri.toString();
}
function location(recent: IRecent): URI {
if (isRecentFolder(recent)) {
return recent.folderUri;

View File

@@ -50,7 +50,7 @@ export class WorkspacesMainService implements AddFirstParameterToFunctions<IWork
//#region Workspaces History
readonly onRecentlyOpenedChange = this.workspacesHistoryMainService.onRecentlyOpenedChange;
readonly onDidChangeRecentlyOpened = this.workspacesHistoryMainService.onDidChangeRecentlyOpened;
async getRecentlyOpened(windowId: number): Promise<IRecentlyOpened> {
return this.workspacesHistoryMainService.getRecentlyOpened(this.windowsMainService.getWindowById(windowId));

View File

@@ -6,8 +6,8 @@
import { toWorkspaceFolders, IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder, IEnterWorkspaceResult, isUntitledWorkspace, isWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { join, dirname } from 'vs/base/common/path';
import { mkdirp, writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs';
import { readFileSync, existsSync, mkdirSync, statSync, Stats } from 'fs';
import { writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs';
import { promises, readFileSync, existsSync, mkdirSync, statSync, Stats } from 'fs';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { Event, Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
@@ -38,8 +38,8 @@ export interface IWorkspacesManagementMainService {
readonly _serviceBrand: undefined;
readonly onUntitledWorkspaceDeleted: Event<IWorkspaceIdentifier>;
readonly onWorkspaceEntered: Event<IWorkspaceEnteredEvent>;
readonly onDidDeleteUntitledWorkspace: Event<IWorkspaceIdentifier>;
readonly onDidEnterWorkspace: Event<IWorkspaceEnteredEvent>;
enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise<IEnterWorkspaceResult | null>;
@@ -65,16 +65,16 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
declare readonly _serviceBrand: undefined;
private readonly untitledWorkspacesHome = this.environmentService.untitledWorkspacesHome; // local URI that contains all untitled workspaces
private readonly untitledWorkspacesHome = this.environmentMainService.untitledWorkspacesHome; // local URI that contains all untitled workspaces
private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter<IWorkspaceIdentifier>());
readonly onUntitledWorkspaceDeleted: Event<IWorkspaceIdentifier> = this._onUntitledWorkspaceDeleted.event;
private readonly _onDidDeleteUntitledWorkspace = this._register(new Emitter<IWorkspaceIdentifier>());
readonly onDidDeleteUntitledWorkspace: Event<IWorkspaceIdentifier> = this._onDidDeleteUntitledWorkspace.event;
private readonly _onWorkspaceEntered = this._register(new Emitter<IWorkspaceEnteredEvent>());
readonly onWorkspaceEntered: Event<IWorkspaceEnteredEvent> = this._onWorkspaceEntered.event;
private readonly _onDidEnterWorkspace = this._register(new Emitter<IWorkspaceEnteredEvent>());
readonly onDidEnterWorkspace: Event<IWorkspaceEnteredEvent> = this._onDidEnterWorkspace.event;
constructor(
@IEnvironmentMainService private readonly environmentService: IEnvironmentMainService,
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
@ILogService private readonly logService: ILogService,
@IBackupMainService private readonly backupMainService: IBackupMainService,
@IDialogMainService private readonly dialogMainService: IDialogMainService
@@ -86,6 +86,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
if (!this.isWorkspacePath(uri)) {
return null; // does not look like a valid workspace config file
}
if (uri.scheme !== Schemas.file) {
return null;
}
@@ -101,7 +102,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
}
private isWorkspacePath(uri: URI): boolean {
return isUntitledWorkspace(uri, this.environmentService) || hasWorkspaceFileExtension(uri);
return isUntitledWorkspace(uri, this.environmentMainService) || hasWorkspaceFileExtension(uri);
}
private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null {
@@ -140,7 +141,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders, remoteAuthority);
const configPath = workspace.configPath.fsPath;
await mkdirp(dirname(configPath));
await promises.mkdir(dirname(configPath), { recursive: true });
await writeFile(configPath, JSON.stringify(storedWorkspace, null, '\t'));
return workspace;
@@ -186,7 +187,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
}
isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean {
return isUntitledWorkspace(workspace.configPath, this.environmentService);
return isUntitledWorkspace(workspace.configPath, this.environmentMainService);
}
deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void {
@@ -198,7 +199,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
this.doDeleteUntitledWorkspaceSync(workspace);
// Event
this._onUntitledWorkspaceDeleted.fire(workspace);
this._onDidDeleteUntitledWorkspace.fire(workspace);
}
async deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise<void> {
@@ -213,7 +214,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
rimrafSync(dirname(configPath));
// Mark Workspace Storage to be deleted
const workspaceStoragePath = join(this.environmentService.workspaceStorageHome.fsPath, workspace.id);
const workspaceStoragePath = join(this.environmentMainService.workspaceStorageHome.fsPath, workspace.id);
if (existsSync(workspaceStoragePath)) {
writeFileSync(join(workspaceStoragePath, 'obsolete'), '');
}
@@ -260,7 +261,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
}
// Emit as event
this._onWorkspaceEntered.fire({ window, workspace: result.workspace });
this._onDidEnterWorkspace.fire({ window, workspace: result.workspace });
return result;
}

View File

@@ -5,9 +5,25 @@
import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
import { hasWorkspaceFileExtension, toWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { hasWorkspaceFileExtension, toWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, ISerializedWorkspaceIdentifier, reviveIdentifier, ISerializedSingleFolderWorkspaceIdentifier, IEmptyWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
suite('Workspaces', () => {
test('reviveIdentifier', () => {
let serializedWorkspaceIdentifier: ISerializedWorkspaceIdentifier = { id: 'id', configPath: URI.file('foo').toJSON() };
assert.strictEqual(isWorkspaceIdentifier(reviveIdentifier(serializedWorkspaceIdentifier)), true);
let serializedSingleFolderWorkspaceIdentifier: ISerializedSingleFolderWorkspaceIdentifier = { id: 'id', uri: URI.file('foo').toJSON() };
assert.strictEqual(isSingleFolderWorkspaceIdentifier(reviveIdentifier(serializedSingleFolderWorkspaceIdentifier)), true);
let serializedEmptyWorkspaceIdentifier: IEmptyWorkspaceIdentifier = { id: 'id' };
assert.strictEqual(reviveIdentifier(serializedEmptyWorkspaceIdentifier).id, serializedEmptyWorkspaceIdentifier.id);
assert.strictEqual(isWorkspaceIdentifier(serializedEmptyWorkspaceIdentifier), false);
assert.strictEqual(isSingleFolderWorkspaceIdentifier(serializedEmptyWorkspaceIdentifier), false);
assert.strictEqual(reviveIdentifier(undefined), undefined);
});
test('hasWorkspaceFileExtension', () => {
assert.strictEqual(hasWorkspaceFileExtension('something'), false);
assert.strictEqual(hasWorkspaceFileExtension('something.code-workspace'), true);

View File

@@ -4,65 +4,66 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as os from 'os';
import * as path from 'vs/base/common/path';
import { tmpdir } from 'os';
import { join } from 'vs/base/common/path';
import { IWorkspaceIdentifier, IRecentlyOpened, isRecentFolder, IRecentFolder, IRecentWorkspace, toStoreData, restoreRecentlyOpened } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
import { NullLogService } from 'vs/platform/log/common/log';
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 assertEqualRecentlyOpened(actual: IRecentlyOpened, expected: IRecentlyOpened, message?: string) {
assert.strictEqual(actual.files.length, expected.files.length, message);
for (let i = 0; i < actual.files.length; i++) {
assertEqualURI(actual.files[i].fileUri, expected.files[i].fileUri, message);
assert.strictEqual(actual.files[i].label, expected.files[i].label);
}
assert.strictEqual(actual.workspaces.length, expected.workspaces.length, message);
for (let i = 0; i < actual.workspaces.length; i++) {
let expectedRecent = expected.workspaces[i];
let actualRecent = actual.workspaces[i];
if (isRecentFolder(actualRecent)) {
assertEqualURI(actualRecent.folderUri, (<IRecentFolder>expectedRecent).folderUri, message);
} else {
assertEqualWorkspace(actualRecent.workspace, (<IRecentWorkspace>expectedRecent).workspace, message);
}
assert.strictEqual(actualRecent.label, expectedRecent.label);
}
}
function assertRestoring(state: IRecentlyOpened, message?: string) {
const stored = toStoreData(state);
const restored = restoreRecentlyOpened(stored, new NullLogService());
assertEqualRecentlyOpened(state, restored, message);
}
const testWSPath = URI.file(path.join(os.tmpdir(), 'windowStateTest', 'test.code-workspace'));
const testFileURI = URI.file(path.join(os.tmpdir(), 'windowStateTest', 'testFile.txt'));
const testFolderURI = URI.file(path.join(os.tmpdir(), 'windowStateTest', 'testFolder'));
const testRemoteFolderURI = URI.parse('foo://bar/c/e');
const testRemoteFileURI = URI.parse('foo://bar/c/d.txt');
const testRemoteWSURI = URI.parse('foo://bar/c/test.code-workspace');
suite('History Storage', () => {
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 assertEqualRecentlyOpened(actual: IRecentlyOpened, expected: IRecentlyOpened, message?: string) {
assert.strictEqual(actual.files.length, expected.files.length, message);
for (let i = 0; i < actual.files.length; i++) {
assertEqualURI(actual.files[i].fileUri, expected.files[i].fileUri, message);
assert.strictEqual(actual.files[i].label, expected.files[i].label);
}
assert.strictEqual(actual.workspaces.length, expected.workspaces.length, message);
for (let i = 0; i < actual.workspaces.length; i++) {
let expectedRecent = expected.workspaces[i];
let actualRecent = actual.workspaces[i];
if (isRecentFolder(actualRecent)) {
assertEqualURI(actualRecent.folderUri, (<IRecentFolder>expectedRecent).folderUri, message);
} else {
assertEqualWorkspace(actualRecent.workspace, (<IRecentWorkspace>expectedRecent).workspace, message);
}
assert.strictEqual(actualRecent.label, expectedRecent.label);
}
}
function assertRestoring(state: IRecentlyOpened, message?: string) {
const stored = toStoreData(state);
const restored = restoreRecentlyOpened(stored, new NullLogService());
assertEqualRecentlyOpened(state, restored, message);
}
const testWSPath = URI.file(join(tmpdir(), 'windowStateTest', 'test.code-workspace'));
const testFileURI = URI.file(join(tmpdir(), 'windowStateTest', 'testFile.txt'));
const testFolderURI = URI.file(join(tmpdir(), 'windowStateTest', 'testFolder'));
const testRemoteFolderURI = URI.parse('foo://bar/c/e');
const testRemoteFileURI = URI.parse('foo://bar/c/d.txt');
const testRemoteWSURI = URI.parse('foo://bar/c/test.code-workspace');
test('storing and restoring', () => {
let ro: IRecentlyOpened;
ro = {

View File

@@ -17,104 +17,53 @@ import { URI } from 'vs/base/common/uri';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { isWindows } from 'vs/base/common/platform';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { dirname, extUriBiasedIgnorePathCase, joinPath } from 'vs/base/common/resources';
import { extUriBiasedIgnorePathCase } from 'vs/base/common/resources';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
import { IBackupMainService, IWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup';
import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
export class TestDialogMainService implements IDialogMainService {
declare readonly _serviceBrand: undefined;
pickFileFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> {
throw new Error('Method not implemented.');
}
pickFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> {
throw new Error('Method not implemented.');
}
pickFile(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> {
throw new Error('Method not implemented.');
}
pickWorkspace(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> {
throw new Error('Method not implemented.');
}
showMessageBox(options: Electron.MessageBoxOptions, window?: Electron.BrowserWindow | undefined): Promise<Electron.MessageBoxReturnValue> {
throw new Error('Method not implemented.');
}
showSaveDialog(options: Electron.SaveDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<Electron.SaveDialogReturnValue> {
throw new Error('Method not implemented.');
}
showOpenDialog(options: Electron.OpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<Electron.OpenDialogReturnValue> {
throw new Error('Method not implemented.');
}
}
export class TestBackupMainService implements IBackupMainService {
declare readonly _serviceBrand: undefined;
isHotExitEnabled(): boolean {
throw new Error('Method not implemented.');
}
getWorkspaceBackups(): IWorkspaceBackupInfo[] {
throw new Error('Method not implemented.');
}
getFolderBackupPaths(): URI[] {
throw new Error('Method not implemented.');
}
getEmptyWindowBackupPaths(): IEmptyWindowBackupInfo[] {
throw new Error('Method not implemented.');
}
registerWorkspaceBackupSync(workspace: IWorkspaceBackupInfo, migrateFrom?: string | undefined): string {
throw new Error('Method not implemented.');
}
registerFolderBackupSync(folderUri: URI): string {
throw new Error('Method not implemented.');
}
registerEmptyWindowBackupSync(backupFolder?: string | undefined, remoteAuthority?: string | undefined): string {
throw new Error('Method not implemented.');
}
unregisterWorkspaceBackupSync(workspace: IWorkspaceIdentifier): void {
throw new Error('Method not implemented.');
}
unregisterFolderBackupSync(folderUri: URI): void {
throw new Error('Method not implemented.');
}
unregisterEmptyWindowBackupSync(backupFolder: string): void {
throw new Error('Method not implemented.');
}
async getDirtyWorkspaces(): Promise<(IWorkspaceIdentifier | URI)[]> {
return [];
}
}
suite('WorkspacesManagementMainService', () => {
class TestDialogMainService implements IDialogMainService {
declare readonly _serviceBrand: undefined;
pickFileFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> { throw new Error('Method not implemented.'); }
pickFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> { throw new Error('Method not implemented.'); }
pickFile(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> { throw new Error('Method not implemented.'); }
pickWorkspace(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<string[] | undefined> { throw new Error('Method not implemented.'); }
showMessageBox(options: Electron.MessageBoxOptions, window?: Electron.BrowserWindow | undefined): Promise<Electron.MessageBoxReturnValue> { throw new Error('Method not implemented.'); }
showSaveDialog(options: Electron.SaveDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<Electron.SaveDialogReturnValue> { throw new Error('Method not implemented.'); }
showOpenDialog(options: Electron.OpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise<Electron.OpenDialogReturnValue> { throw new Error('Method not implemented.'); }
}
class TestBackupMainService implements IBackupMainService {
declare readonly _serviceBrand: undefined;
isHotExitEnabled(): boolean { throw new Error('Method not implemented.'); }
getWorkspaceBackups(): IWorkspaceBackupInfo[] { throw new Error('Method not implemented.'); }
getFolderBackupPaths(): URI[] { throw new Error('Method not implemented.'); }
getEmptyWindowBackupPaths(): IEmptyWindowBackupInfo[] { throw new Error('Method not implemented.'); }
registerWorkspaceBackupSync(workspace: IWorkspaceBackupInfo, migrateFrom?: string | undefined): string { throw new Error('Method not implemented.'); }
registerFolderBackupSync(folderUri: URI): string { throw new Error('Method not implemented.'); }
registerEmptyWindowBackupSync(backupFolder?: string | undefined, remoteAuthority?: string | undefined): string { throw new Error('Method not implemented.'); }
unregisterWorkspaceBackupSync(workspace: IWorkspaceIdentifier): void { throw new Error('Method not implemented.'); }
unregisterFolderBackupSync(folderUri: URI): void { throw new Error('Method not implemented.'); }
unregisterEmptyWindowBackupSync(backupFolder: string): void { throw new Error('Method not implemented.'); }
async getDirtyWorkspaces(): Promise<(IWorkspaceIdentifier | URI)[]> { return []; }
}
function createUntitledWorkspace(folders: string[], names?: string[]) {
return service.createUntitledWorkspace(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : undefined } as IWorkspaceFolderCreationData)));
}
function createWorkspace(workspaceConfigPath: string, folders: (string | URI)[], names?: string[]): void {
const ws: IStoredWorkspace = {
folders: []
};
for (let i = 0; i < folders.length; i++) {
const f = folders[i];
const s: IStoredWorkspaceFolder = f instanceof URI ? { uri: f.toString() } : { path: f };
@@ -123,6 +72,7 @@ suite('WorkspacesManagementMainService', () => {
}
ws.folders.push(s);
}
fs.writeFileSync(workspaceConfigPath, JSON.stringify(ws));
}
@@ -132,28 +82,35 @@ suite('WorkspacesManagementMainService', () => {
let testDir: string;
let untitledWorkspacesHomePath: string;
let environmentService: EnvironmentMainService;
let environmentMainService: EnvironmentMainService;
let service: WorkspacesManagementMainService;
const cwd = process.cwd();
const tmpDir = os.tmpdir();
setup(async () => {
testDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesmanagementmainservice');
testDir = getRandomTestPath(tmpDir, 'vsctests', 'workspacesmanagementmainservice');
untitledWorkspacesHomePath = path.join(testDir, 'Workspaces');
environmentService = new class TestEnvironmentService extends EnvironmentMainService {
environmentMainService = new class TestEnvironmentService extends EnvironmentMainService {
constructor() {
super(parseArgs(process.argv, OPTIONS));
}
get untitledWorkspacesHome(): URI {
return URI.file(untitledWorkspacesHomePath);
}
};
service = new WorkspacesManagementMainService(environmentService, new NullLogService(), new TestBackupMainService(), new TestDialogMainService());
service = new WorkspacesManagementMainService(environmentMainService, new NullLogService(), new TestBackupMainService(), new TestDialogMainService());
return pfs.mkdirp(untitledWorkspacesHomePath);
return fs.promises.mkdir(untitledWorkspacesHomePath, { recursive: true });
});
teardown(() => {
service.dispose();
return pfs.rimraf(testDir);
});
@@ -171,29 +128,29 @@ suite('WorkspacesManagementMainService', () => {
}
test('createWorkspace (folders)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath.fsPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = (JSON.parse(fs.readFileSync(workspace.configPath.fsPath).toString()) as IStoredWorkspace);
assert.strictEqual(ws.folders.length, 2);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, cwd);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, tmpDir);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[0]).name);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[1]).name);
});
test('createWorkspace (folders with name)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()], ['currentworkingdirectory', 'tempdir']);
const workspace = await createUntitledWorkspace([cwd, tmpDir], ['currentworkingdirectory', 'tempdir']);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath.fsPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = (JSON.parse(fs.readFileSync(workspace.configPath.fsPath).toString()) as IStoredWorkspace);
assert.strictEqual(ws.folders.length, 2);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, cwd);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, tmpDir);
assert.strictEqual((<IRawFileWorkspaceFolder>ws.folders[0]).name, 'currentworkingdirectory');
assert.strictEqual((<IRawFileWorkspaceFolder>ws.folders[1]).name, 'tempdir');
});
@@ -217,30 +174,30 @@ suite('WorkspacesManagementMainService', () => {
});
test('createWorkspaceSync (folders)', () => {
const workspace = createUntitledWorkspaceSync([process.cwd(), os.tmpdir()]);
const workspace = createUntitledWorkspaceSync([cwd, tmpDir]);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath.fsPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath.fsPath).toString()) as IStoredWorkspace;
assert.strictEqual(ws.folders.length, 2);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, cwd);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, tmpDir);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[0]).name);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[1]).name);
});
test('createWorkspaceSync (folders with names)', () => {
const workspace = createUntitledWorkspaceSync([process.cwd(), os.tmpdir()], ['currentworkingdirectory', 'tempdir']);
const workspace = createUntitledWorkspaceSync([cwd, tmpDir], ['currentworkingdirectory', 'tempdir']);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath.fsPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath.fsPath).toString()) as IStoredWorkspace;
assert.strictEqual(ws.folders.length, 2);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[0]).path, cwd);
assertPathEquals((<IRawFileWorkspaceFolder>ws.folders[1]).path, tmpDir);
assert.strictEqual((<IRawFileWorkspaceFolder>ws.folders[0]).name, 'currentworkingdirectory');
assert.strictEqual((<IRawFileWorkspaceFolder>ws.folders[1]).name, 'tempdir');
@@ -265,7 +222,7 @@ suite('WorkspacesManagementMainService', () => {
});
test('resolveWorkspaceSync', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
assert.ok(service.resolveLocalWorkspaceSync(workspace.configPath));
// make it a valid workspace path
@@ -284,7 +241,7 @@ suite('WorkspacesManagementMainService', () => {
});
test('resolveWorkspaceSync (support relative paths)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] }));
const resolved = service.resolveLocalWorkspaceSync(workspace.configPath);
@@ -292,7 +249,7 @@ suite('WorkspacesManagementMainService', () => {
});
test('resolveWorkspaceSync (support relative paths #2)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] }));
const resolved = service.resolveLocalWorkspaceSync(workspace.configPath);
@@ -300,7 +257,7 @@ suite('WorkspacesManagementMainService', () => {
});
test('resolveWorkspaceSync (support relative paths #3)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] }));
const resolved = service.resolveLocalWorkspaceSync(workspace.configPath);
@@ -308,7 +265,7 @@ suite('WorkspacesManagementMainService', () => {
});
test('resolveWorkspaceSync (support invalid JSON via fault tolerant parsing)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
fs.writeFileSync(workspace.configPath.fsPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma
const resolved = service.resolveLocalWorkspaceSync(workspace.configPath);
@@ -316,8 +273,7 @@ suite('WorkspacesManagementMainService', () => {
});
test('rewriteWorkspaceFileForNewLocation', async () => {
const folder1 = process.cwd(); // absolute path because outside of tmpDir
const tmpDir = os.tmpdir();
const folder1 = cwd; // absolute path because outside of tmpDir
const tmpInsideDir = path.join(tmpDir, 'inside');
const firstConfigPath = path.join(tmpDir, 'myworkspace0.code-workspace');
@@ -364,8 +320,8 @@ suite('WorkspacesManagementMainService', () => {
});
test('rewriteWorkspaceFileForNewLocation (preserves comments)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]);
const workspaceConfigPath = URI.file(path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`));
const workspace = await createUntitledWorkspace([cwd, tmpDir, path.join(tmpDir, 'somefolder')]);
const workspaceConfigPath = URI.file(path.join(tmpDir, `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`));
let origContent = fs.readFileSync(workspace.configPath.fsPath).toString();
origContent = `// this is a comment\n${origContent}`;
@@ -376,8 +332,8 @@ suite('WorkspacesManagementMainService', () => {
});
test('rewriteWorkspaceFileForNewLocation (preserves forward slashes)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]);
const workspaceConfigPath = URI.file(path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`));
const workspace = await createUntitledWorkspace([cwd, tmpDir, path.join(tmpDir, 'somefolder')]);
const workspaceConfigPath = URI.file(path.join(tmpDir, `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`));
let origContent = fs.readFileSync(workspace.configPath.fsPath).toString();
origContent = origContent.replace(/[\\]/g, '/'); // convert backslash to slash
@@ -389,7 +345,7 @@ suite('WorkspacesManagementMainService', () => {
});
(!isWindows ? test.skip : test)('rewriteWorkspaceFileForNewLocation (unc paths)', async () => {
const workspaceLocation = path.join(os.tmpdir(), 'wsloc');
const workspaceLocation = path.join(tmpDir, 'wsloc');
const folder1Location = 'x:\\foo';
const folder2Location = '\\\\server\\share2\\some\\path';
const folder3Location = path.join(workspaceLocation, 'inner', 'more');
@@ -407,14 +363,14 @@ suite('WorkspacesManagementMainService', () => {
});
test('deleteUntitledWorkspaceSync (untitled)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
assert.ok(fs.existsSync(workspace.configPath.fsPath));
service.deleteUntitledWorkspaceSync(workspace);
assert.ok(!fs.existsSync(workspace.configPath.fsPath));
});
test('deleteUntitledWorkspaceSync (saved)', async () => {
const workspace = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const workspace = await createUntitledWorkspace([cwd, tmpDir]);
service.deleteUntitledWorkspaceSync(workspace);
});
@@ -422,31 +378,15 @@ suite('WorkspacesManagementMainService', () => {
let untitled = service.getUntitledWorkspacesSync();
assert.strictEqual(untitled.length, 0);
const untitledOne = await createUntitledWorkspace([process.cwd(), os.tmpdir()]);
const untitledOne = await createUntitledWorkspace([cwd, tmpDir]);
assert.ok(fs.existsSync(untitledOne.configPath.fsPath));
untitled = service.getUntitledWorkspacesSync();
assert.strictEqual(1, untitled.length);
assert.strictEqual(untitledOne.id, untitled[0].workspace.id);
const untitledTwo = await createUntitledWorkspace([os.tmpdir(), process.cwd()]);
assert.ok(fs.existsSync(untitledTwo.configPath.fsPath));
assert.ok(fs.existsSync(untitledOne.configPath.fsPath), `Unexpected workspaces count of 1 (expected 2): ${untitledOne.configPath.fsPath} does not exist anymore?`);
const untitledHome = dirname(dirname(untitledTwo.configPath));
const beforeGettingUntitledWorkspaces = fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'));
untitled = service.getUntitledWorkspacesSync();
assert.ok(fs.existsSync(untitledOne.configPath.fsPath), `Unexpected workspaces count of 1 (expected 2): ${untitledOne.configPath.fsPath} does not exist anymore?`);
if (untitled.length === 1) {
assert.fail(`Unexpected workspaces count of 1 (expected 2), all workspaces:\n ${fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'))}, before getUntitledWorkspacesSync: ${beforeGettingUntitledWorkspaces}`);
}
assert.strictEqual(2, untitled.length);
service.deleteUntitledWorkspaceSync(untitledOne);
untitled = service.getUntitledWorkspacesSync();
assert.strictEqual(1, untitled.length);
service.deleteUntitledWorkspaceSync(untitledTwo);
untitled = service.getUntitledWorkspacesSync();
assert.strictEqual(0, untitled.length);
});