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

@@ -5,44 +5,36 @@
'use strict';
import URI from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import * as paths from 'vs/base/common/paths';
import { TrieMap } from 'vs/base/common/map';
import * as resources from 'vs/base/common/resources';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { TernarySearchTree } from 'vs/base/common/map';
import Event from 'vs/base/common/event';
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import { coalesce, distinct } from 'vs/base/common/arrays';
import { isLinux } from 'vs/base/common/platform';
import { distinct } from 'vs/base/common/arrays';
export const IWorkspaceContextService = createDecorator<IWorkspaceContextService>('contextService');
export enum WorkbenchState {
EMPTY = 1,
FOLDER,
WORKSPACE
}
export interface IWorkspaceFoldersChangeEvent {
added: IWorkspaceFolder[];
removed: IWorkspaceFolder[];
changed: IWorkspaceFolder[];
}
export interface IWorkspaceContextService {
_serviceBrand: any;
/**
* Returns if the application was opened with a workspace or not.
* An event which fires on workbench state changes.
*/
hasWorkspace(): boolean;
/**
* Returns if the application was opened with a folder.
*/
hasFolderWorkspace(): boolean;
/**
* Returns if the application was opened with a workspace that can have one or more folders.
*/
hasMultiFolderWorkspace(): boolean;
/**
* Provides access to the workspace object the platform is running with. This may be null if the workbench was opened
* without workspace (empty);
*/
getLegacyWorkspace(): ILegacyWorkspace;
/**
* Provides access to the workspace object the platform is running with. This may be null if the workbench was opened
* without workspace (empty);
*/
getWorkspace(): IWorkspace;
onDidChangeWorkbenchState: Event<WorkbenchState>;
/**
* An event which fires on workspace name changes.
@@ -50,39 +42,39 @@ export interface IWorkspaceContextService {
onDidChangeWorkspaceName: Event<void>;
/**
* An event which fires on workspace roots change.
* An event which fires on workspace folders change.
*/
onDidChangeWorkspaceRoots: Event<void>;
onDidChangeWorkspaceFolders: Event<IWorkspaceFoldersChangeEvent>;
/**
* Returns the root for the given resource from the workspace.
* Provides access to the workspace object the platform is running with.
*/
getWorkspace(): IWorkspace;
/**
* Return the state of the workbench.
*
* WorkbenchState.EMPTY - if the workbench was opened with empty window or file
* WorkbenchState.FOLDER - if the workbench was opened with a folder
* WorkbenchState.WORKSPACE - if the workbench was opened with a workspace
*/
getWorkbenchState(): WorkbenchState;
/**
* Returns the folder for the given resource from the workspace.
* Can be null if there is no workspace or the resource is not inside the workspace.
*/
getRoot(resource: URI): URI;
getWorkspaceFolder(resource: URI): IWorkspaceFolder;
/**
* Return `true` if the current workspace has the given identifier otherwise `false`.
*/
isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean;
/**
* Returns if the provided resource is inside the workspace or not.
*/
isInsideWorkspace(resource: URI): boolean;
/**
* Given a workspace relative path, returns the resource with the absolute path.
*/
toResource: (workspaceRelativePath: string) => URI;
}
export interface ILegacyWorkspace {
/**
* the full uri of the workspace. this is a file:// URL to the location
* of the workspace on disk.
*/
resource: URI;
/**
* creation time of the workspace folder if known
*/
ctime?: number;
}
export interface IWorkspace {
@@ -98,9 +90,9 @@ export interface IWorkspace {
readonly name: string;
/**
* Roots in the workspace.
* Folders in the workspace.
*/
readonly roots: URI[];
readonly folders: IWorkspaceFolder[];
/**
* the location of the workspace configuration
@@ -108,59 +100,70 @@ export interface IWorkspace {
readonly configuration?: URI;
}
export class LegacyWorkspace implements ILegacyWorkspace {
private _name: string;
export interface IWorkspaceFolderData {
/**
* The associated URI for this workspace folder.
*/
readonly uri: URI;
constructor(private _resource: URI, private _ctime?: number) {
this._name = paths.basename(this._resource.fsPath) || this._resource.fsPath;
}
/**
* The name of this workspace folder. Defaults to
* the basename its [uri-path](#Uri.path)
*/
readonly name: string;
public get resource(): URI {
return this._resource;
}
/**
* The ordinal number of this workspace folder.
*/
readonly index: number;
}
public get name(): string {
return this._name;
}
export interface IWorkspaceFolder extends IWorkspaceFolderData {
public get ctime(): number {
return this._ctime;
}
public toResource(workspaceRelativePath: string, root?: URI): URI {
if (typeof workspaceRelativePath === 'string') {
return URI.file(paths.join(root ? root.fsPath : this._resource.fsPath, workspaceRelativePath));
}
return null;
}
/**
* Given workspace folder relative path, returns the resource with the absolute path.
*/
toResource: (relativePath: string) => URI;
}
export class Workspace implements IWorkspace {
private _rootsMap: TrieMap<URI> = new TrieMap<URI>();
private _roots: URI[];
private _foldersMap: TernarySearchTree<WorkspaceFolder> = TernarySearchTree.forPaths<WorkspaceFolder>();
private _folders: WorkspaceFolder[];
constructor(
public readonly id: string,
private _name: string,
roots: URI[],
private _configuration: URI = null
private _id: string,
private _name: string = '',
folders: WorkspaceFolder[] = [],
private _configuration: URI = null,
private _ctime?: number
) {
this.roots = roots;
this.folders = folders;
}
private ensureUnique(roots: URI[]): URI[] {
return distinct(roots, root => isLinux ? root.fsPath : root.fsPath.toLowerCase());
public update(workspace: Workspace) {
this._id = workspace.id;
this._name = workspace.name;
this._configuration = workspace.configuration;
this._ctime = workspace.ctime;
this.folders = workspace.folders;
}
public get roots(): URI[] {
return this._roots;
public get folders(): WorkspaceFolder[] {
return this._folders;
}
public set roots(roots: URI[]) {
this._roots = this.ensureUnique(roots);
this.updateRootsMap();
public set folders(folders: WorkspaceFolder[]) {
this._folders = folders;
this.updateFoldersMap();
}
public get id(): string {
return this._id;
}
public get ctime(): number {
return this._ctime;
}
public get name(): string {
@@ -179,22 +182,86 @@ export class Workspace implements IWorkspace {
this._configuration = configuration;
}
public getRoot(resource: URI): URI {
public getFolder(resource: URI): IWorkspaceFolder {
if (!resource) {
return null;
}
return this._rootsMap.findSubstr(resource.fsPath);
return this._foldersMap.findSubstr(resource.toString());
}
private updateRootsMap(): void {
this._rootsMap = new TrieMap<URI>();
for (const root of this.roots) {
this._rootsMap.insert(root.fsPath, root);
private updateFoldersMap(): void {
this._foldersMap = TernarySearchTree.forPaths<WorkspaceFolder>();
for (const folder of this.folders) {
this._foldersMap.set(folder.uri.toString(), folder);
}
}
public toJSON(): IWorkspace {
return { id: this.id, roots: this.roots, name: this.name };
return { id: this.id, folders: this.folders, name: this.name };
}
}
export class WorkspaceFolder implements IWorkspaceFolder {
readonly uri: URI;
readonly name: string;
readonly index: number;
constructor(data: IWorkspaceFolderData,
readonly raw?: IStoredWorkspaceFolder) {
this.uri = data.uri;
this.index = data.index;
this.name = data.name;
}
toResource(relativePath: string): URI {
return this.uri.with({ path: paths.join(this.uri.path, relativePath) });
}
toJSON(): IWorkspaceFolderData {
return { uri: this.uri, name: this.name, index: this.index };
}
}
export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): WorkspaceFolder[] {
let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo);
return ensureUnique(coalesce(workspaceFolders))
.map(({ uri, raw, name }, index) => new WorkspaceFolder({ uri, name: name || resources.basenameOrAuthority(uri), index }, raw));
}
function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] {
return configuredFolders.map((configuredFolder, index) => {
let uri: URI;
if (isRawFileWorkspaceFolder(configuredFolder)) {
uri = toUri(configuredFolder.path, relativeTo);
} else if (isRawUriWorkspaceFolder(configuredFolder)) {
try {
uri = URI.parse(configuredFolder.uri);
} catch (e) {
console.warn(e);
// ignore
}
}
if (!uri) {
return void 0;
}
return new WorkspaceFolder({ uri, name: configuredFolder.name, index }, configuredFolder);
});
}
function toUri(path: string, relativeTo: URI): URI {
if (path) {
if (paths.isAbsolute(path)) {
return URI.file(path);
}
if (relativeTo) {
return relativeTo.with({ path: paths.join(relativeTo.path, path) });
}
}
return null;
}
function ensureUnique(folders: WorkspaceFolder[]): WorkspaceFolder[] {
return distinct(folders, folder => isLinux ? folder.uri.toString() : folder.uri.toString().toLowerCase());
}

View File

@@ -4,15 +4,16 @@
*--------------------------------------------------------------------------------------------*/
import URI from 'vs/base/common/uri';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
import { isWindows } from 'vs/base/common/platform';
const wsUri = URI.file('C:\\testWorkspace');
const wsUri = URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace');
export const TestWorkspace = testWorkspace(wsUri);
export function testWorkspace(resource: URI): Workspace {
return new Workspace(
resource.toString(),
resource.fsPath,
[resource]
toWorkspaceFolders([{ path: resource.fsPath }])
);
}

View File

@@ -6,17 +6,190 @@
'use strict';
import * as assert from 'assert';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { Workspace, toWorkspaceFolders, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
suite('Workspace', () => {
test('Workspace ensures unique roots', () => {
test('getFolder returns the folder with given uri', () => {
const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 });
let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), expected, new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]);
// Unique
let roots = [URI.file('/some/path'), URI.file('/some/path')];
let ws = new Workspace('id', 'name', roots, URI.file('/config'));
const actual = testObject.getFolder(expected.uri);
assert.equal(ws.roots.length, 1);
assert.equal(actual, expected);
});
});
test('getFolder returns the folder if the uri is sub', () => {
const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 });
let testObject = new Workspace('', '', [expected, new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 1 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]);
const actual = testObject.getFolder(URI.file('/src/test/a'));
assert.equal(actual, expected);
});
test('getFolder returns the closest folder if the uri is sub', () => {
const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 });
let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 }), expected]);
const actual = testObject.getFolder(URI.file('/src/test/a'));
assert.equal(actual, expected);
});
test('getFolder returns null if the uri is not sub', () => {
let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 })]);
const actual = testObject.getFolder(URI.file('/src/main/a'));
assert.equal(actual, undefined);
});
test('toWorkspaceFolders with single absolute folder', () => {
const actual = toWorkspaceFolders([{ path: '/src/test' }]);
assert.equal(actual.length, 1);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test');
});
test('toWorkspaceFolders with single relative folder', () => {
const actual = toWorkspaceFolders([{ path: './test' }], URI.file('src'));
assert.equal(actual.length, 1);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, './test');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test');
});
test('toWorkspaceFolders with single absolute folder with name', () => {
const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }]);
assert.equal(actual.length, 1);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'hello');
});
test('toWorkspaceFolders with multiple unique absolute folders', () => {
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3' }, { path: '/src/test1' }]);
assert.equal(actual.length, 3);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test2');
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
assert.equal(actual[1].index, 1);
assert.equal(actual[1].name, 'test3');
assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/src/test1');
assert.equal(actual[2].index, 2);
assert.equal(actual[2].name, 'test1');
});
test('toWorkspaceFolders with multiple unique absolute folders with names', () => {
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: '/src/test1' }]);
assert.equal(actual.length, 3);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test2');
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
assert.equal(actual[1].index, 1);
assert.equal(actual[1].name, 'noName');
assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/src/test1');
assert.equal(actual[2].index, 2);
assert.equal(actual[2].name, 'test1');
});
test('toWorkspaceFolders with multiple unique absolute and relative folders', () => {
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/abc/test3', name: 'noName' }, { path: './test1' }], URI.file('src'));
assert.equal(actual.length, 3);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test2');
assert.equal(actual[1].uri.fsPath, URI.file('/abc/test3').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/abc/test3');
assert.equal(actual[1].index, 1);
assert.equal(actual[1].name, 'noName');
assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, './test1');
assert.equal(actual[2].index, 2);
assert.equal(actual[2].name, 'test1');
});
test('toWorkspaceFolders with multiple absolute folders with duplicates', () => {
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test2', name: 'noName' }, { path: '/src/test1' }]);
assert.equal(actual.length, 2);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test2');
assert.equal(actual[1].uri.fsPath, URI.file('/src/test1').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test1');
assert.equal(actual[1].index, 1);
assert.equal(actual[1].name, 'test1');
});
test('toWorkspaceFolders with multiple absolute and relative folders with duplicates', () => {
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], URI.file('src'));
assert.equal(actual.length, 3);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test2');
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
assert.equal(actual[1].index, 1);
assert.equal(actual[1].name, 'noName');
assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/abc/test1');
assert.equal(actual[2].index, 2);
assert.equal(actual[2].name, 'test1');
});
test('toWorkspaceFolders with multiple absolute and relative folders with invalid paths', () => {
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], URI.file('src'));
assert.equal(actual.length, 3);
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
assert.equal(actual[0].index, 0);
assert.equal(actual[0].name, 'test2');
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, './test3');
assert.equal(actual[1].index, 1);
assert.equal(actual[1].name, 'test3');
assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath);
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/abc/test1');
assert.equal(actual[2].index, 2);
assert.equal(actual[2].name, 'test1');
});
});