/*--------------------------------------------------------------------------------------------- * 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(); private readonly _proxy: MainThreadWorkspaceShape; private _workspace: Workspace2; readonly onDidChangeWorkspace: Event = 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); } 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(added), removed: Object.freeze(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 { 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 { return this._proxy.$saveAll(includeUntitled); } appyEdit(edit: vscode.WorkspaceEdit): TPromise { 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, newText: edit.newText, newEol: EndOfLine.from(edit.newEol), range: edit.range && fromRange(edit.range) }); } } return this._proxy.$applyWorkspaceEdit(resourceEdits); } }