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

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) {
40
				if (folder.uri.toString() === root.toString()) {
41 42 43 44 45 46 47 48
					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
	}
}