Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -14,6 +14,8 @@ import { isLinux } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import Event from 'vs/base/common/event';
import { tildify, getPathLabel } from 'vs/base/common/labels';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
export const IWorkspacesMainService = createDecorator<IWorkspacesMainService>('workspacesMainService');
export const IWorkspacesService = createDecorator<IWorkspacesService>('workspacesService');
@@ -32,21 +34,54 @@ export interface IWorkspaceIdentifier {
configPath: string;
}
export interface IStoredWorkspaceFolder {
export function isStoredWorkspaceFolder(thing: any): thing is IStoredWorkspaceFolder {
return isRawFileWorkspaceFolder(thing) || isRawUriWorkspaceFolder(thing);
}
export function isRawFileWorkspaceFolder(thing: any): thing is IRawFileWorkspaceFolder {
return thing
&& typeof thing === 'object'
&& typeof thing.path === 'string'
&& (!thing.name || typeof thing.name === 'string');
}
export function isRawUriWorkspaceFolder(thing: any): thing is IRawUriWorkspaceFolder {
return thing
&& typeof thing === 'object'
&& typeof thing.uri === 'string'
&& (!thing.name || typeof thing.name === 'string');
}
export interface IRawFileWorkspaceFolder {
path: string;
name?: string;
}
export interface IRawUriWorkspaceFolder {
uri: string;
name?: string;
}
export type IStoredWorkspaceFolder = IRawFileWorkspaceFolder | IRawUriWorkspaceFolder;
export interface IResolvedWorkspace extends IWorkspaceIdentifier {
folders: IWorkspaceFolder[];
}
export interface IStoredWorkspace {
folders: IStoredWorkspaceFolder[];
}
export interface IResolvedWorkspace extends IWorkspaceIdentifier, IStoredWorkspace { }
export interface IWorkspaceSavedEvent {
workspace: IWorkspaceIdentifier;
oldConfigPath: string;
}
export interface IWorkspaceFolderCreationData {
uri: URI;
name?: string;
}
export interface IWorkspacesMainService extends IWorkspacesService {
_serviceBrand: any;
@@ -54,7 +89,8 @@ export interface IWorkspacesMainService extends IWorkspacesService {
onUntitledWorkspaceDeleted: Event<IWorkspaceIdentifier>;
saveWorkspace(workspace: IWorkspaceIdentifier, target: string): TPromise<IWorkspaceIdentifier>;
createWorkspaceSync(folders?: string[]): IWorkspaceIdentifier;
createWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier;
resolveWorkspace(path: string): TPromise<IResolvedWorkspace>;
resolveWorkspaceSync(path: string): IResolvedWorkspace;
@@ -71,7 +107,7 @@ export interface IWorkspacesMainService extends IWorkspacesService {
export interface IWorkspacesService {
_serviceBrand: any;
createWorkspace(folders?: string[]): TPromise<IWorkspaceIdentifier>;
createWorkspace(folders?: IWorkspaceFolderCreationData[]): TPromise<IWorkspaceIdentifier>;
}
export function getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier), environmentService: IEnvironmentService, options?: { verbose: boolean }): string {
@@ -104,4 +140,4 @@ export function isWorkspaceIdentifier(obj: any): obj is IWorkspaceIdentifier {
const workspaceIdentifier = obj as IWorkspaceIdentifier;
return workspaceIdentifier && typeof workspaceIdentifier.id === 'string' && typeof workspaceIdentifier.configPath === 'string';
}
}

View File

@@ -7,10 +7,11 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IWorkspacesService, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import URI from 'vs/base/common/uri';
export interface IWorkspacesChannel extends IChannel {
call(command: 'createWorkspace', arg: [string[]]): TPromise<string>;
call(command: 'createWorkspace', arg: [IWorkspaceFolderCreationData[]]): TPromise<string>;
call(command: string, arg?: any): TPromise<any>;
}
@@ -18,9 +19,22 @@ export class WorkspacesChannel implements IWorkspacesChannel {
constructor(private service: IWorkspacesService) { }
call(command: string, arg?: any): TPromise<any> {
public call(command: string, arg?: any): TPromise<any> {
switch (command) {
case 'createWorkspace': return this.service.createWorkspace(arg);
case 'createWorkspace': {
const rawFolders: IWorkspaceFolderCreationData[] = arg;
let folders: IWorkspaceFolderCreationData[];
if (Array.isArray(rawFolders)) {
folders = rawFolders.map(rawFolder => {
return {
uri: URI.revive(rawFolder.uri), // convert raw URI back to real URI
name: rawFolder.name
} as IWorkspaceFolderCreationData;
});
}
return this.service.createWorkspace(folders);
};
}
return void 0;
@@ -33,7 +47,7 @@ export class WorkspacesChannelClient implements IWorkspacesService {
constructor(private channel: IWorkspacesChannel) { }
createWorkspace(folders?: string[]): TPromise<IWorkspaceIdentifier> {
public createWorkspace(folders?: IWorkspaceFolderCreationData[]): TPromise<IWorkspaceIdentifier> {
return this.channel.call('createWorkspace', folders);
}
}

View File

@@ -5,27 +5,29 @@
'use strict';
import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import { TPromise } from 'vs/base/common/winjs.base';
import { isParent } from 'vs/platform/files/common/files';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { extname, join, dirname, isAbsolute, resolve, relative } from 'path';
import { extname, join, dirname, isAbsolute, resolve } from 'path';
import { mkdirp, writeFile, readFile } from 'vs/base/node/pfs';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { isLinux } from 'vs/base/common/platform';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
import { delSync, readdirSync } from 'vs/base/node/extfs';
import Event, { Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { isEqual, isEqualOrParent } from 'vs/base/common/paths';
import { isEqual } from 'vs/base/common/paths';
import { coalesce } from 'vs/base/common/arrays';
import { createHash } from 'crypto';
import URI from 'vs/base/common/uri';
import * as json from 'vs/base/common/json';
import * as jsonEdit from 'vs/base/common/jsonEdit';
import { applyEdit } from 'vs/base/common/jsonFormatter';
import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces';
import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
// TODO@Ben migration
export interface ILegacyStoredWorkspace {
id: string;
folders: string[];
export interface IStoredWorkspace {
folders: IStoredWorkspaceFolder[];
}
export class WorkspacesMainService implements IWorkspacesMainService {
@@ -68,7 +70,14 @@ export class WorkspacesMainService implements IWorkspacesMainService {
return null; // does not look like a valid workspace config file
}
return this.doResolveWorkspace(path, readFileSync(path, 'utf8'));
let contents: string;
try {
contents = readFileSync(path, 'utf8');
} catch (error) {
return null; // invalid workspace
}
return this.doResolveWorkspace(path, contents);
}
private isWorkspacePath(path: string): boolean {
@@ -79,17 +88,10 @@ export class WorkspacesMainService implements IWorkspacesMainService {
try {
const workspace = this.doParseStoredWorkspace(path, contents);
// relative paths get resolved against the workspace location
workspace.folders.forEach(folder => {
if (!isAbsolute(folder.path)) {
folder.path = resolve(dirname(path), folder.path);
}
});
return {
id: this.getWorkspaceId(path),
configPath: path,
folders: workspace.folders
folders: toWorkspaceFolders(workspace.folders, URI.file(dirname(path)))
};
} catch (error) {
this.logService.log(error.toString());
@@ -108,20 +110,13 @@ export class WorkspacesMainService implements IWorkspacesMainService {
throw new Error(`${path} cannot be parsed as JSON file (${error}).`);
}
// TODO@Ben migration
const legacyStoredWorkspace = (<any>storedWorkspace) as ILegacyStoredWorkspace;
if (legacyStoredWorkspace.folders.some(folder => typeof folder === 'string')) {
storedWorkspace.folders = legacyStoredWorkspace.folders.map(folder => ({ path: URI.parse(folder).fsPath }));
writeFileSync(path, JSON.stringify(storedWorkspace, null, '\t'));
}
// Filter out folders which do not have a path set
// Filter out folders which do not have a path or uri set
if (Array.isArray(storedWorkspace.folders)) {
storedWorkspace.folders = storedWorkspace.folders.filter(folder => !!folder.path);
storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder));
}
// Validate
if (!Array.isArray(storedWorkspace.folders) || storedWorkspace.folders.length === 0) {
if (!Array.isArray(storedWorkspace.folders)) {
throw new Error(`${path} looks like an invalid workspace file.`);
}
@@ -132,7 +127,7 @@ export class WorkspacesMainService implements IWorkspacesMainService {
return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */);
}
public createWorkspace(folders: string[]): TPromise<IWorkspaceIdentifier> {
public createWorkspace(folders?: IWorkspaceFolderCreationData[]): TPromise<IWorkspaceIdentifier> {
const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(folders);
return mkdirp(configParent).then(() => {
@@ -140,7 +135,7 @@ export class WorkspacesMainService implements IWorkspacesMainService {
});
}
public createWorkspaceSync(folders: string[]): IWorkspaceIdentifier {
public createWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier {
const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(folders);
if (!existsSync(this.workspacesHome)) {
@@ -154,15 +149,32 @@ export class WorkspacesMainService implements IWorkspacesMainService {
return workspace;
}
private createUntitledWorkspace(folders: string[]): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } {
private createUntitledWorkspace(folders: IWorkspaceFolderCreationData[] = []): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } {
const randomId = (Date.now() + Math.round(Math.random() * 1000)).toString();
const untitledWorkspaceConfigFolder = join(this.workspacesHome, randomId);
const untitledWorkspaceConfigPath = join(untitledWorkspaceConfigFolder, UNTITLED_WORKSPACE_NAME);
const storedWorkspace: IStoredWorkspace = {
folders: folders.map(folder => ({
path: folder
}))
folders: folders.map(folder => {
const folderResource = folder.uri;
let storedWorkspace: IStoredWorkspaceFolder;
// File URI
if (folderResource.scheme === 'file') {
storedWorkspace = { path: massageFolderPathForWorkspace(folderResource.fsPath, untitledWorkspaceConfigFolder, []) };
}
// Any URI
else {
storedWorkspace = { uri: folderResource.toString(true) };
}
if (folder.name) {
storedWorkspace.name = folder.name;
}
return storedWorkspace;
})
};
return {
@@ -195,10 +207,11 @@ export class WorkspacesMainService implements IWorkspacesMainService {
}
// Read the contents of the workspace file and resolve it
return readFile(workspace.configPath).then(rawWorkspaceContents => {
return readFile(workspace.configPath).then(raw => {
const rawWorkspaceContents = raw.toString();
let storedWorkspace: IStoredWorkspace;
try {
storedWorkspace = this.doParseStoredWorkspace(workspace.configPath, rawWorkspaceContents.toString());
storedWorkspace = this.doParseStoredWorkspace(workspace.configPath, rawWorkspaceContents);
} catch (error) {
return TPromise.wrapError(error);
}
@@ -210,16 +223,24 @@ export class WorkspacesMainService implements IWorkspacesMainService {
// is a parent of the location of the workspace file itself. Otherwise keep
// using absolute paths.
storedWorkspace.folders.forEach(folder => {
if (!isAbsolute(folder.path)) {
folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location
if (isRawFileWorkspaceFolder(folder)) {
if (!isAbsolute(folder.path)) {
folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location
}
folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders);
}
if (isEqualOrParent(folder.path, targetConfigFolder, !isLinux)) {
folder.path = relative(targetConfigFolder, folder.path) || '.'; // absolute paths get converted to relative ones to workspace location if possible
}
});
return writeFile(targetConfigPath, JSON.stringify(storedWorkspace, null, '\t')).then(() => {
// Preserve as much of the existing workspace as possible by using jsonEdit
// and only changing the folders portion.
let newRawWorkspaceContents = rawWorkspaceContents;
const edits = jsonEdit.setProperty(rawWorkspaceContents, ['folders'], storedWorkspace.folders, { insertSpaces: false, tabSize: 4, eol: (isLinux || isMacintosh) ? '\n' : '\r\n' });
edits.forEach(edit => {
newRawWorkspaceContents = applyEdit(rawWorkspaceContents, edit);
});
return writeFile(targetConfigPath, newRawWorkspaceContents).then(() => {
const savedWorkspaceIdentifier = { id: this.getWorkspaceId(targetConfigPath), configPath: targetConfigPath };
// Event

View File

@@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IStoredWorkspaceFolder, isRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import { isWindows, isLinux } from 'vs/base/common/platform';
import { isAbsolute, relative } from 'path';
import { isEqualOrParent, normalize } from 'vs/base/common/paths';
import { normalizeDriveLetter } from 'vs/base/common/labels';
const SLASH = '/';
/**
* Given the absolute path to a folder, massage it in a way that it fits
* into an existing set of workspace folders of a workspace.
*
* @param absoluteFolderPath the absolute path of a workspace folder
* @param targetConfigFolder the folder where the workspace is living in
* @param existingFolders a set of existing folders of the workspace
*/
export function massageFolderPathForWorkspace(absoluteFolderPath: string, targetConfigFolder: string, existingFolders: IStoredWorkspaceFolder[]): string {
const useSlashesForPath = shouldUseSlashForPath(existingFolders);
// Convert path to relative path if the target config folder
// is a parent of the path.
if (isEqualOrParent(absoluteFolderPath, targetConfigFolder, !isLinux)) {
absoluteFolderPath = relative(targetConfigFolder, absoluteFolderPath) || '.';
}
// Windows gets special treatment:
// - normalize all paths to get nice casing of drive letters
// - convert to slashes if we want to use slashes for paths
if (isWindows) {
if (isAbsolute(absoluteFolderPath)) {
if (useSlashesForPath) {
absoluteFolderPath = normalize(absoluteFolderPath, false /* do not use OS path separator */);
}
absoluteFolderPath = normalizeDriveLetter(absoluteFolderPath);
} else if (useSlashesForPath) {
absoluteFolderPath = absoluteFolderPath.replace(/[\\]/g, SLASH);
}
}
return absoluteFolderPath;
}
function shouldUseSlashForPath(storedFolders: IStoredWorkspaceFolder[]): boolean {
// Determine which path separator to use:
// - macOS/Linux: slash
// - Windows: use slash if already used in that file
let useSlashesForPath = !isWindows;
if (isWindows) {
storedFolders.forEach(folder => {
if (isRawFileWorkspaceFolder(folder) && !useSlashesForPath && folder.path.indexOf(SLASH) >= 0) {
useSlashesForPath = true;
}
});
}
return useSlashesForPath;
}

View File

@@ -13,13 +13,14 @@ import extfs = require('vs/base/node/extfs');
import pfs = require('vs/base/node/pfs');
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IWorkspaceFolderCreationData, IRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import { LogMainService } from 'vs/platform/log/common/log';
import URI from 'vs/base/common/uri';
import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices';
suite('WorkspacesMainService', () => {
const parentDir = path.join(os.tmpdir(), 'vsctests', 'service');
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice');
const workspacesHome = path.join(parentDir, 'Workspaces');
class TestEnvironmentService extends EnvironmentService {
@@ -38,6 +39,14 @@ suite('WorkspacesMainService', () => {
}
}
function createWorkspace(folders: string[], names?: string[]) {
return service.createWorkspace(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : void 0 } as IWorkspaceFolderCreationData)));
}
function createWorkspaceSync(folders: string[], names?: string[]) {
return service.createWorkspaceSync(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : void 0 } as IWorkspaceFolderCreationData)));
}
const environmentService = new TestEnvironmentService(parseArgs(process.argv), process.execPath);
const logService = new LogMainService(environmentService);
@@ -59,34 +68,104 @@ suite('WorkspacesMainService', () => {
});
test('createWorkspace (folders)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 2); //
assert.equal(ws.folders[0].path, process.cwd());
assert.equal(ws.folders[1].path, os.tmpdir());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[0]).name);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[1]).name);
done();
});
});
test('createWorkspace (folders with name)', done => {
return createWorkspace([process.cwd(), os.tmpdir()], ['currentworkingdirectory', 'tempdir']).then(workspace => {
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 2); //
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).name, 'currentworkingdirectory');
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).name, 'tempdir');
done();
});
});
test('createWorkspace (folders as other resource URIs)', () => {
return service.createWorkspace([{ uri: URI.from({ scheme: 'myScheme', path: process.cwd() }) }, { uri: URI.from({ scheme: 'myScheme', path: os.tmpdir() }) }]).then(workspace => {
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 2);
assert.equal((<IRawUriWorkspaceFolder>ws.folders[0]).uri, URI.from({ scheme: 'myScheme', path: process.cwd() }).toString(true));
assert.equal((<IRawUriWorkspaceFolder>ws.folders[1]).uri, URI.from({ scheme: 'myScheme', path: os.tmpdir() }).toString(true));
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[0]).name);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[1]).name);
});
});
test('createWorkspaceSync (folders)', () => {
const workspace = service.createWorkspaceSync([process.cwd(), os.tmpdir()]);
const workspace = createWorkspaceSync([process.cwd(), os.tmpdir()]);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 2); //
assert.equal(ws.folders[0].path, process.cwd());
assert.equal(ws.folders[1].path, os.tmpdir());
assert.equal(ws.folders.length, 2);
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[0]).name);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[1]).name);
});
test('createWorkspaceSync (folders with names)', () => {
const workspace = createWorkspaceSync([process.cwd(), os.tmpdir()], ['currentworkingdirectory', 'tempdir']);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 2);
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).path, os.tmpdir());
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).name, 'currentworkingdirectory');
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).name, 'tempdir');
});
test('createWorkspaceSync (folders as other resource URIs)', () => {
const workspace = service.createWorkspaceSync([{ uri: URI.from({ scheme: 'myScheme', path: process.cwd() }) }, { uri: URI.from({ scheme: 'myScheme', path: os.tmpdir() }) }]);
assert.ok(workspace);
assert.ok(fs.existsSync(workspace.configPath));
assert.ok(service.isUntitledWorkspace(workspace));
const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 2);
assert.equal((<IRawUriWorkspaceFolder>ws.folders[0]).uri, URI.from({ scheme: 'myScheme', path: process.cwd() }).toString(true));
assert.equal((<IRawUriWorkspaceFolder>ws.folders[1]).uri, URI.from({ scheme: 'myScheme', path: os.tmpdir() }).toString(true));
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[0]).name);
assert.ok(!(<IRawFileWorkspaceFolder>ws.folders[1]).name);
});
test('resolveWorkspaceSync', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
assert.ok(service.resolveWorkspaceSync(workspace.configPath));
// make it a valid workspace path
@@ -108,7 +187,7 @@ suite('WorkspacesMainService', () => {
});
test('resolveWorkspace', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return service.resolveWorkspace(workspace.configPath).then(ws => {
assert.ok(ws);
@@ -134,44 +213,44 @@ suite('WorkspacesMainService', () => {
});
test('resolveWorkspaceSync (support relative paths)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] }));
const resolved = service.resolveWorkspaceSync(workspace.configPath);
assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath);
assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath);
done();
});
});
test('resolveWorkspaceSync (support relative paths #2)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] }));
const resolved = service.resolveWorkspaceSync(workspace.configPath);
assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath);
assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath);
done();
});
});
test('resolveWorkspaceSync (support relative paths #3)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] }));
const resolved = service.resolveWorkspaceSync(workspace.configPath);
assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath);
assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath);
done();
});
});
test('resolveWorkspaceSync (support invalid JSON via fault tolerant parsing)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
fs.writeFileSync(workspace.configPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma
const resolved = service.resolveWorkspaceSync(workspace.configPath);
assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath);
assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath);
done();
});
@@ -188,7 +267,7 @@ suite('WorkspacesMainService', () => {
deletedEvent = e;
});
return service.createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => {
const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => {
@@ -200,9 +279,9 @@ suite('WorkspacesMainService', () => {
const ws = JSON.parse(fs.readFileSync(savedWorkspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 3);
assert.equal(ws.folders[0].path, process.cwd()); // absolute
assert.equal(ws.folders[1].path, '.'); // relative
assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd()); // absolute
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).path, '.'); // relative
assert.equal((<IRawFileWorkspaceFolder>ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative
assert.equal(savedWorkspace, savedEvent.workspace);
assert.equal(workspace.configPath, savedEvent.oldConfigPath);
@@ -220,7 +299,7 @@ suite('WorkspacesMainService', () => {
});
test('saveWorkspace (saved workspace)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => {
const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
const newWorkspaceConfigPath = path.join(os.tmpdir(), `mySavedWorkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
@@ -232,9 +311,61 @@ suite('WorkspacesMainService', () => {
const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace;
assert.equal(ws.folders.length, 3);
assert.equal(ws.folders[0].path, process.cwd()); // absolute path because outside of tmpdir
assert.equal(ws.folders[1].path, '.'); // relative path because inside of tmpdir
assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative
assert.equal((<IRawFileWorkspaceFolder>ws.folders[0]).path, process.cwd()); // absolute path because outside of tmpdir
assert.equal((<IRawFileWorkspaceFolder>ws.folders[1]).path, '.'); // relative path because inside of tmpdir
assert.equal((<IRawFileWorkspaceFolder>ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative
extfs.delSync(workspaceConfigPath);
extfs.delSync(newWorkspaceConfigPath);
done();
});
});
});
});
test('saveWorkspace (saved workspace, preserves comments)', done => {
return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => {
const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
const newWorkspaceConfigPath = path.join(os.tmpdir(), `mySavedWorkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => {
const contents = fs.readFileSync(savedWorkspace.configPath).toString();
fs.writeFileSync(savedWorkspace.configPath, `// this is a comment\n${contents}`);
return service.saveWorkspace(savedWorkspace, newWorkspaceConfigPath).then(newSavedWorkspace => {
assert.ok(newSavedWorkspace.id);
assert.notEqual(newSavedWorkspace.id, workspace.id);
assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath);
const savedContents = fs.readFileSync(newSavedWorkspace.configPath).toString();
assert.equal(0, savedContents.indexOf('// this is a comment'));
extfs.delSync(workspaceConfigPath);
extfs.delSync(newWorkspaceConfigPath);
done();
});
});
});
});
test('saveWorkspace (saved workspace, preserves forward slashes)', done => {
return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => {
const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
const newWorkspaceConfigPath = path.join(os.tmpdir(), `mySavedWorkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => {
const contents = fs.readFileSync(savedWorkspace.configPath).toString();
fs.writeFileSync(savedWorkspace.configPath, contents.replace(/[\\]/g, '/')); // convert backslash to slash
return service.saveWorkspace(savedWorkspace, newWorkspaceConfigPath).then(newSavedWorkspace => {
assert.ok(newSavedWorkspace.id);
assert.notEqual(newSavedWorkspace.id, workspace.id);
assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath);
const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace;
assert.ok(ws.folders.every(f => (<IRawFileWorkspaceFolder>f).path.indexOf('\\') < 0));
extfs.delSync(workspaceConfigPath);
extfs.delSync(newWorkspaceConfigPath);
@@ -246,7 +377,7 @@ suite('WorkspacesMainService', () => {
});
test('deleteUntitledWorkspaceSync (untitled)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
assert.ok(fs.existsSync(workspace.configPath));
service.deleteUntitledWorkspaceSync(workspace);
@@ -258,7 +389,7 @@ suite('WorkspacesMainService', () => {
});
test('deleteUntitledWorkspaceSync (saved)', done => {
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => {
const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`);
return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => {
@@ -277,20 +408,22 @@ suite('WorkspacesMainService', () => {
let untitled = service.getUntitledWorkspacesSync();
assert.equal(0, untitled.length);
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledOne => {
return createWorkspace([process.cwd(), os.tmpdir()]).then(untitledOne => {
untitled = service.getUntitledWorkspacesSync();
assert.equal(1, untitled.length);
assert.equal(untitledOne.id, untitled[0].id);
return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledTwo => {
return createWorkspace([os.tmpdir(), process.cwd()]).then(untitledTwo => {
untitled = service.getUntitledWorkspacesSync();
assert.equal(2, untitled.length);
service.deleteUntitledWorkspaceSync(untitledOne);
service.deleteUntitledWorkspaceSync(untitledTwo);
untitled = service.getUntitledWorkspacesSync();
assert.equal(1, untitled.length);
service.deleteUntitledWorkspaceSync(untitledTwo);
untitled = service.getUntitledWorkspacesSync();
assert.equal(0, untitled.length);
@@ -298,4 +431,4 @@ suite('WorkspacesMainService', () => {
});
});
});
});
});