extHostWorkspace.ts 5.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
8
import Event, { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
9
import { normalize } from 'vs/base/common/paths';
J
Johannes Rieken 已提交
10
import { isFalsyOrEmpty, delta } from 'vs/base/common/arrays';
11
import { relative, basename } from 'path';
12
import { Workspace } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
13
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
14
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
J
Johannes Rieken 已提交
15
import { TPromise } from 'vs/base/common/winjs.base';
16
import { fromRange, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
17
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape } from './extHost.protocol';
18
import * as vscode from 'vscode';
J
Johannes Rieken 已提交
19
import { compare } from "vs/base/common/strings";
E
Erich Gamma 已提交
20

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

class Workspace2 {

	static fromData(data: IWorkspaceData) {
		return data ? new Workspace2(data) : null;
	}

	readonly workspace: Workspace;
	readonly folders: vscode.WorkspaceFolder[];

	private constructor(data: IWorkspaceData) {
		this.workspace = new Workspace(data.id, data.name, data.roots);
		this.folders = this.workspace.roots.map((uri, index) => ({ name: basename(uri.fsPath), uri, index }));
	}

	getRoot(uri: URI): vscode.WorkspaceFolder {
		const root = this.workspace.getRoot(uri);
		if (root) {
			for (const folder of this.folders) {
				if (folder.uri.toString() === uri.toString()) {
					return folder;
				}
			}
		}
		return undefined;
	}
}

49
export class ExtHostWorkspace extends ExtHostWorkspaceShape {
E
Erich Gamma 已提交
50

51 52
	private static _requestIdPool = 0;

J
Johannes Rieken 已提交
53
	private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
54
	private readonly _proxy: MainThreadWorkspaceShape;
55
	private _workspace: Workspace2;
E
Erich Gamma 已提交
56

J
Johannes Rieken 已提交
57
	readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
J
Johannes Rieken 已提交
58

59
	constructor(threadService: IThreadService, data: IWorkspaceData) {
60
		super();
61
		this._proxy = threadService.get(MainContext.MainThreadWorkspace);
62
		this._workspace = Workspace2.fromData(data);
E
Erich Gamma 已提交
63 64
	}

65 66
	// --- workspace ---

J
Johannes Rieken 已提交
67
	get workspace(): Workspace {
68
		return this._workspace && this._workspace.workspace;
J
Johannes Rieken 已提交
69 70
	}

71
	getWorkspaceFolders(): vscode.WorkspaceFolder[] {
72 73 74
		if (!this._workspace) {
			return undefined;
		} else {
75 76 77 78 79 80 81
			return this._workspace.folders.slice(0);
		}
	}

	getEnclosingWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder {
		if (!this._workspace) {
			return undefined;
82
		}
83
		return this._workspace.getRoot(<URI>uri);
84 85
	}

E
Erich Gamma 已提交
86
	getPath(): string {
J
Johannes Rieken 已提交
87 88 89
		// this is legacy from the days before having
		// multi-root and we keep it only alive if there
		// is just one workspace folder.
90 91 92
		if (!this._workspace) {
			return undefined;
		}
93
		const { roots } = this._workspace.workspace;
94 95
		if (roots.length === 0) {
			return undefined;
96
		}
97 98 99
		// if (roots.length === 1) {
		return roots[0].fsPath;
		// }
100 101
		// return `undefined` when there no or more than 1
		// root folder.
102
		// return undefined;
E
Erich Gamma 已提交
103 104
	}

J
Joao Moreno 已提交
105
	getRelativePath(pathOrUri: string | vscode.Uri): string {
E
Erich Gamma 已提交
106 107 108 109

		let path: string;
		if (typeof pathOrUri === 'string') {
			path = pathOrUri;
110
		} else if (typeof pathOrUri !== 'undefined') {
E
Erich Gamma 已提交
111 112 113
			path = pathOrUri.fsPath;
		}

114 115 116 117
		if (!path) {
			return path;
		}

118
		if (!this._workspace || isFalsyOrEmpty(this._workspace.workspace.roots)) {
J
Johannes Rieken 已提交
119
			return normalize(path);
E
Erich Gamma 已提交
120 121
		}

122
		for (const { fsPath } of this._workspace.workspace.roots) {
123 124 125 126 127
			let result = relative(fsPath, path);
			if (!result || result.indexOf('..') === 0) {
				continue;
			}
			return normalize(result);
128 129
		}

130
		return normalize(path);
E
Erich Gamma 已提交
131 132
	}

133
	$acceptWorkspaceData(data: IWorkspaceData): void {
J
Johannes Rieken 已提交
134

135 136 137 138
		// keep old workspace folder, build new workspace, and
		// capture new workspace folders. Compute delta between
		// them send that as event
		const oldRoots = this._workspace ? this._workspace.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
J
Johannes Rieken 已提交
139

140 141
		this._workspace = Workspace2.fromData(data);
		const newRoots = this._workspace ? this._workspace.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
J
Johannes Rieken 已提交
142

143
		const { added, removed } = delta(oldRoots, newRoots, ExtHostWorkspace._compareWorkspaceFolder);
J
Johannes Rieken 已提交
144
		this._onDidChangeWorkspace.fire(Object.freeze({
145 146
			added: Object.freeze<vscode.WorkspaceFolder[]>(added),
			removed: Object.freeze<vscode.WorkspaceFolder[]>(removed)
J
Johannes Rieken 已提交
147 148 149
		}));
	}

150 151
	private static _compareWorkspaceFolder(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
		return compare(a.uri.toString(), b.uri.toString());
152 153 154 155
	}

	// --- search ---

J
Joao Moreno 已提交
156
	findFiles(include: string, exclude: string, maxResults?: number, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
157 158 159 160 161 162
		const requestId = ExtHostWorkspace._requestIdPool++;
		const result = this._proxy.$startSearch(include, exclude, maxResults, requestId);
		if (token) {
			token.onCancellationRequested(() => this._proxy.$cancelSearch(requestId));
		}
		return result;
E
Erich Gamma 已提交
163 164 165
	}

	saveAll(includeUntitled?: boolean): Thenable<boolean> {
166
		return this._proxy.$saveAll(includeUntitled);
E
Erich Gamma 已提交
167 168 169 170
	}

	appyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {

171
		let resourceEdits: IResourceEdit[] = [];
E
Erich Gamma 已提交
172 173 174 175 176 177 178 179 180

		let entries = edit.entries();
		for (let entry of entries) {
			let [uri, edits] = entry;

			for (let edit of edits) {
				resourceEdits.push({
					resource: <URI>uri,
					newText: edit.newText,
181 182
					newEol: EndOfLine.from(edit.newEol),
					range: edit.range && fromRange(edit.range)
E
Erich Gamma 已提交
183 184 185 186
				});
			}
		}

187
		return this._proxy.$applyWorkspaceEdit(resourceEdits);
E
Erich Gamma 已提交
188 189
	}
}