mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-25 02:58:56 +01:00
190 lines
5.7 KiB
TypeScript
190 lines
5.7 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* 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';
|
|
import Event, { Emitter } from 'vs/base/common/event';
|
|
import { normalize } from 'vs/base/common/paths';
|
|
import { isFalsyOrEmpty, delta } from 'vs/base/common/arrays';
|
|
import { relative, basename } from 'path';
|
|
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
|
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
|
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
|
|
import { TPromise } from 'vs/base/common/winjs.base';
|
|
import { fromRange, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
|
|
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape } from './extHost.protocol';
|
|
import * as vscode from 'vscode';
|
|
import { compare } from "vs/base/common/strings";
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
export class ExtHostWorkspace extends ExtHostWorkspaceShape {
|
|
|
|
private static _requestIdPool = 0;
|
|
|
|
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
|
|
private readonly _proxy: MainThreadWorkspaceShape;
|
|
private _workspace: Workspace2;
|
|
|
|
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
|
|
|
|
constructor(threadService: IThreadService, data: IWorkspaceData) {
|
|
super();
|
|
this._proxy = threadService.get(MainContext.MainThreadWorkspace);
|
|
this._workspace = Workspace2.fromData(data);
|
|
}
|
|
|
|
// --- workspace ---
|
|
|
|
get workspace(): Workspace {
|
|
return this._workspace && this._workspace.workspace;
|
|
}
|
|
|
|
getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
|
if (!this._workspace) {
|
|
return undefined;
|
|
} else {
|
|
return this._workspace.folders.slice(0);
|
|
}
|
|
}
|
|
|
|
getEnclosingWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder {
|
|
if (!this._workspace) {
|
|
return undefined;
|
|
}
|
|
return this._workspace.getRoot(<URI>uri);
|
|
}
|
|
|
|
getPath(): string {
|
|
// this is legacy from the days before having
|
|
// multi-root and we keep it only alive if there
|
|
// is just one workspace folder.
|
|
if (!this._workspace) {
|
|
return undefined;
|
|
}
|
|
const { roots } = this._workspace.workspace;
|
|
if (roots.length === 0) {
|
|
return undefined;
|
|
}
|
|
// if (roots.length === 1) {
|
|
return roots[0].fsPath;
|
|
// }
|
|
// return `undefined` when there no or more than 1
|
|
// root folder.
|
|
// return undefined;
|
|
}
|
|
|
|
getRelativePath(pathOrUri: string | vscode.Uri): string {
|
|
|
|
let path: string;
|
|
if (typeof pathOrUri === 'string') {
|
|
path = pathOrUri;
|
|
} else if (typeof pathOrUri !== 'undefined') {
|
|
path = pathOrUri.fsPath;
|
|
}
|
|
|
|
if (!path) {
|
|
return path;
|
|
}
|
|
|
|
if (!this._workspace || isFalsyOrEmpty(this._workspace.workspace.roots)) {
|
|
return normalize(path);
|
|
}
|
|
|
|
for (const { fsPath } of this._workspace.workspace.roots) {
|
|
let result = relative(fsPath, path);
|
|
if (!result || result.indexOf('..') === 0) {
|
|
continue;
|
|
}
|
|
return normalize(result);
|
|
}
|
|
|
|
return normalize(path);
|
|
}
|
|
|
|
$acceptWorkspaceData(data: IWorkspaceData): void {
|
|
|
|
// 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) : [];
|
|
|
|
this._workspace = Workspace2.fromData(data);
|
|
const newRoots = this._workspace ? this._workspace.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
|
|
|
|
const { added, removed } = delta(oldRoots, newRoots, ExtHostWorkspace._compareWorkspaceFolder);
|
|
this._onDidChangeWorkspace.fire(Object.freeze({
|
|
added: Object.freeze<vscode.WorkspaceFolder[]>(added),
|
|
removed: Object.freeze<vscode.WorkspaceFolder[]>(removed)
|
|
}));
|
|
}
|
|
|
|
private static _compareWorkspaceFolder(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
|
|
return compare(a.uri.toString(), b.uri.toString());
|
|
}
|
|
|
|
// --- search ---
|
|
|
|
findFiles(include: string, exclude: string, maxResults?: number, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
|
|
const requestId = ExtHostWorkspace._requestIdPool++;
|
|
const result = this._proxy.$startSearch(include, exclude, maxResults, requestId);
|
|
if (token) {
|
|
token.onCancellationRequested(() => this._proxy.$cancelSearch(requestId));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
saveAll(includeUntitled?: boolean): Thenable<boolean> {
|
|
return this._proxy.$saveAll(includeUntitled);
|
|
}
|
|
|
|
appyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
|
|
|
|
let resourceEdits: IResourceEdit[] = [];
|
|
|
|
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,
|
|
newEol: EndOfLine.from(edit.newEol),
|
|
range: edit.range && fromRange(edit.range)
|
|
});
|
|
}
|
|
}
|
|
|
|
return this._proxy.$applyWorkspaceEdit(resourceEdits);
|
|
}
|
|
}
|