diff --git a/packages/plugin-ext/src/api/plugin-api.ts b/packages/plugin-ext/src/api/plugin-api.ts index 7eed430390744..245b4767d84f4 100644 --- a/packages/plugin-ext/src/api/plugin-api.ts +++ b/packages/plugin-ext/src/api/plugin-api.ts @@ -102,6 +102,10 @@ export interface WindowStateExt { $onWindowStateChanged(focus: boolean): void; } +export interface WorkspaceExt { + $onWorkspaceFoldersChanged(event: theia.WorkspaceFoldersChangeEvent): void; +} + export enum EditorPosition { ONE = 0, TWO = 1, @@ -423,6 +427,7 @@ export const MAIN_RPC_CONTEXT = { COMMAND_REGISTRY_EXT: createProxyIdentifier('CommandRegistryExt'), QUICK_OPEN_EXT: createProxyIdentifier('QuickOpenExt'), WINDOW_STATE_EXT: createProxyIdentifier('WindowStateExt'), + WORKSPACE_EXT: createProxyIdentifier('WorkspaceExt'), TEXT_EDITORS_EXT: createProxyIdentifier('TextEditorsExt'), EDITORS_AND_DOCUMENTS_EXT: createProxyIdentifier('EditorsAndDocumentsExt'), DOCUMENTS_EXT: createProxyIdentifier('DocumentsExt'), diff --git a/packages/plugin-ext/src/main/browser/main-context.ts b/packages/plugin-ext/src/main/browser/main-context.ts index e6bfd461d5f97..0cbacd4b4bc4c 100644 --- a/packages/plugin-ext/src/main/browser/main-context.ts +++ b/packages/plugin-ext/src/main/browser/main-context.ts @@ -4,6 +4,7 @@ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ + import { interfaces } from 'inversify'; import { CommandRegistryMainImpl } from './command-registry-main'; import { PreferenceRegistryMainImpl } from './preference-registry-main'; @@ -12,10 +13,12 @@ import { RPCProtocol } from '../../api/rpc-protocol'; import { PLUGIN_RPC_CONTEXT } from '../../api/plugin-api'; import { MessageRegistryMainImpl } from './message-registry-main'; import { WindowStateMain } from './window-state-main'; +import { WorkspaceMain } from './workspace-main'; import { StatusBarMessageRegistryMainImpl } from './status-bar-message-registry-main'; import { EnvMainImpl } from './env-main'; import { EditorsAndDocumentsMain } from './editors-and-documents-main'; -import {OutputChannelRegistryMainImpl} from "./output-channel-registry-main"; +import { OutputChannelRegistryMainImpl } from "./output-channel-registry-main"; +import { WorkspaceService } from '@theia/workspace/lib/browser'; export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container): void { const commandRegistryMain = new CommandRegistryMainImpl(rpc, container); @@ -34,6 +37,12 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container // @ts-ignore const windowStateMain = new WindowStateMain(rpc); + const workspaceService: WorkspaceService = container.get(WorkspaceService); + + // tslint:disable-next-line:no-unused-variable + // @ts-ignore + const workspaceMain = new WorkspaceMain(rpc, workspaceService); + /* tslint:disable */ new EditorsAndDocumentsMain(rpc, container); /* tslint:enable */ diff --git a/packages/plugin-ext/src/main/browser/workspace-main.ts b/packages/plugin-ext/src/main/browser/workspace-main.ts new file mode 100644 index 0000000000000..5662e4949fb8a --- /dev/null +++ b/packages/plugin-ext/src/main/browser/workspace-main.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { WorkspaceExt, MAIN_RPC_CONTEXT } from "../../api/plugin-api"; +import { RPCProtocol } from "../../api/rpc-protocol"; +import { WorkspaceService } from "@theia/workspace/lib/browser"; +import Uri from 'vscode-uri'; +import { WorkspaceFoldersChangeEvent, WorkspaceFolder } from "@theia/plugin"; +import { Path } from "@theia/core/lib/common/path"; + +export class WorkspaceMain { + + private proxy: WorkspaceExt; + + private workspaceRoot: Uri | undefined; + + constructor(rpc: RPCProtocol, workspaceService: WorkspaceService) { + this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.WORKSPACE_EXT); + + workspaceService.root.then((root) => { + if (root) { + this.workspaceRoot = Uri.parse(root.uri); + const workspacePath = new Path(this.workspaceRoot.path); + + const folder: WorkspaceFolder = { + uri: this.workspaceRoot, + name: workspacePath.base, + index: 0 + } as WorkspaceFolder; + + this.proxy.$onWorkspaceFoldersChanged({ + added: [folder], + removed: [] + } as WorkspaceFoldersChangeEvent); + } else { + this.proxy.$onWorkspaceFoldersChanged({ + added: [], + removed: [] + } as WorkspaceFoldersChangeEvent); + } + }); + } + +} diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts index 77a8135edbd3d..d932598f527d7 100644 --- a/packages/plugin-ext/src/plugin/plugin-context.ts +++ b/packages/plugin-ext/src/plugin/plugin-context.ts @@ -15,6 +15,7 @@ import { getPluginId } from '../common/plugin-protocol'; import { MessageRegistryExt } from './message-registry'; import { StatusBarMessageRegistryExt } from './status-bar-message-registry'; import { WindowStateExtImpl } from './window-state'; +import { WorkspaceExtImpl } from './workspace'; import { EnvExtImpl } from './env'; import { QueryParameters } from '../common/env'; import { @@ -52,6 +53,7 @@ export function createAPI(rpc: RPCProtocol): typeof theia { const editorsAndDocuments = rpc.set(MAIN_RPC_CONTEXT.EDITORS_AND_DOCUMENTS_EXT, new EditorsAndDocumentsExtImpl(rpc)); const editors = rpc.set(MAIN_RPC_CONTEXT.TEXT_EDITORS_EXT, new TextEditorsExtImpl(rpc, editorsAndDocuments)); const documents = rpc.set(MAIN_RPC_CONTEXT.DOCUMENTS_EXT, new DocumentsExtImpl(rpc, editorsAndDocuments)); + const workspaceExt = rpc.set(MAIN_RPC_CONTEXT.WORKSPACE_EXT, new WorkspaceExtImpl(rpc)); const statusBarMessageRegistryExt = new StatusBarMessageRegistryExt(rpc); const envExt = rpc.set(MAIN_RPC_CONTEXT.ENV_EXT, new EnvExtImpl(rpc)); const preferenceRegistryExt = rpc.set(MAIN_RPC_CONTEXT.PREFERENCE_REGISTRY_EXT, new PreferenceRegistryExtImpl(rpc)); @@ -152,6 +154,18 @@ export function createAPI(rpc: RPCProtocol): typeof theia { }; const workspace: typeof theia.workspace = { + get rootPath(): string | undefined { + return workspaceExt.rootPath; + }, + get workspaceFolders(): theia.WorkspaceFolder[] | undefined { + return workspaceExt.workspaceFolders; + }, + get name(): string | undefined { + return workspaceExt.name; + }, + onDidChangeWorkspaceFolders(listener, thisArg?, disposables?): theia.Disposable { + return workspaceExt.onDidChangeWorkspaceFolders(listener, thisArg, disposables); + }, get textDocuments() { return documents.getAllDocumentData().map(data => data.document); }, @@ -231,7 +245,6 @@ export function createAPI(rpc: RPCProtocol): typeof theia { OverviewRulerLane, ConfigurationTarget, }; - } // tslint:disable-next-line:no-any diff --git a/packages/plugin-ext/src/plugin/workspace.ts b/packages/plugin-ext/src/plugin/workspace.ts new file mode 100644 index 0000000000000..4fa6cd8ae379d --- /dev/null +++ b/packages/plugin-ext/src/plugin/workspace.ts @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { WorkspaceFolder, WorkspaceFoldersChangeEvent } from "@theia/plugin"; +import { Event, Emitter } from "@theia/core/lib/common/event"; +import { WorkspaceExt } from "../api/plugin-api"; +import { RPCProtocol } from "../api/rpc-protocol"; +import { Path } from "@theia/core/lib/common/path"; + +export class WorkspaceExtImpl implements WorkspaceExt { + + private workspaceFoldersChangedEmitter = new Emitter(); + public readonly onDidChangeWorkspaceFolders: Event = this.workspaceFoldersChangedEmitter.event; + + private folders: WorkspaceFolder[] | undefined; + + constructor(rpc: RPCProtocol) { + } + + get workspaceFolders(): WorkspaceFolder[] | undefined { + return this.folders; + } + + get rootPath(): string | undefined { + if (this.workspaceFolders) { + return this.workspaceFolders[0].uri.path; + } + + return undefined; + } + + get name(): string | undefined { + if (this.workspaceFolders) { + return new Path(this.workspaceFolders[0].uri.path).base; + } + + return undefined; + } + + $onWorkspaceFoldersChanged(event: WorkspaceFoldersChangeEvent): void { + this.folders = event.added; + this.workspaceFoldersChangedEmitter.fire(event); + } + +} diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 8902157325a57..935c874dd443d 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -2091,6 +2091,46 @@ declare module '@theia/plugin' { affectsConfiguration(section: string, resource?: Uri): boolean; } + /** + * An event describing a change to the set of [workspace folders](#workspace.workspaceFolders). + */ + export interface WorkspaceFoldersChangeEvent { + /** + * Added workspace folders. + */ + readonly added: WorkspaceFolder[]; + + /** + * Removed workspace folders. + */ + readonly removed: WorkspaceFolder[]; + } + + /** + * A workspace folder is one of potentially many roots opened by the editor. All workspace folders + * are equal which means there is no notion of an active or master workspace folder. + */ + export interface WorkspaceFolder { + /** + * The associated uri for this workspace folder. + * + * *Note:* The [Uri](#Uri)-type was intentionally chosen such that future releases of the editor can support + * workspace folders that are not stored on the local disk, e.g. `ftp://server/workspaces/foo`. + */ + readonly uri: Uri; + + /** + * The name of this workspace folder. Defaults to + * the basename of its [uri-path](#Uri.path) + */ + readonly name: string; + + /** + * The ordinal number of this workspace folder. + */ + readonly index: number; + } + /** * Namespace for dealing with the current workspace. A workspace is the representation * of the folder that has been opened. There is no workspace when just a file but not a @@ -2101,6 +2141,37 @@ declare module '@theia/plugin' { * the editor-process so that they should be always used instead of nodejs-equivalents. */ export namespace workspace { + /** + * ~~The folder that is open in the editor. `undefined` when no folder + * has been opened.~~ + * + * @deprecated Use [`workspaceFolders`](#workspace.workspaceFolders) instead. + * + * @readonly + */ + export let rootPath: string | undefined; + + /** + * List of workspace folders or `undefined` when no folder is open. + * *Note* that the first entry corresponds to the value of `rootPath`. + * + * @readonly + */ + export let workspaceFolders: WorkspaceFolder[] | undefined; + + /** + * The name of the workspace. `undefined` when no folder + * has been opened. + * + * @readonly + */ + export let name: string | undefined; + + /** + * An event that is emitted when a workspace folder is added or removed. + */ + export const onDidChangeWorkspaceFolders: Event; + /** * All text documents currently known to the system. *