diff --git a/packages/plugin-ext/src/plugin/file-system-ext-impl.ts b/packages/plugin-ext/src/plugin/file-system-ext-impl.ts index 9eb59c06cc12c..b54be1a8dc093 100644 --- a/packages/plugin-ext/src/plugin/file-system-ext-impl.ts +++ b/packages/plugin-ext/src/plugin/file-system-ext-impl.ts @@ -40,8 +40,9 @@ import { State, StateMachine, LinkComputer, Edge } from '../common/link-computer import { commonPrefixLength } from '@theia/core/lib/common/strings'; import { CharCode } from '@theia/core/lib/common/char-code'; import { BinaryBuffer } from '@theia/core/lib/common/buffer'; -import { Emitter } from '@theia/core/shared/vscode-languageserver-protocol'; import { MarkdownString } from '../common/plugin-api-rpc-model'; +import { Emitter } from '@theia/core/lib/common'; +import { createAPIObject } from './plugin-context'; type IDisposable = vscode.Disposable; @@ -137,8 +138,11 @@ export class FsLinkProvider { } class ConsumerFileSystem implements vscode.FileSystem { + apiObject: vscode.FileSystem; - constructor(private _proxy: FileSystemMain, private _capabilities: Map) { } + constructor(private _proxy: FileSystemMain, private _capabilities: Map) { + this.apiObject = createAPIObject(this); + } stat(uri: vscode.Uri): Promise { return this._proxy.$stat(uri).catch(ConsumerFileSystem._handleError); @@ -210,7 +214,7 @@ export class FileSystemExtImpl implements FileSystemExt { private _handlePool: number = 0; - readonly fileSystem: vscode.FileSystem; + readonly fileSystem: ConsumerFileSystem; constructor(rpc: RPCProtocol) { this._proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.FILE_SYSTEM_MAIN); diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts index 8a36492244edc..3029f268f6921 100644 --- a/packages/plugin-ext/src/plugin/plugin-context.ts +++ b/packages/plugin-ext/src/plugin/plugin-context.ts @@ -278,6 +278,21 @@ import { NotebookEditorsExtImpl } from './notebook/notebook-editors'; import { TestingExtImpl } from './tests'; import { UriExtImpl } from './uri-ext'; +export function createAPIObject(rawObject: T): T { + return new Proxy(rawObject, { + get(target, p, receiver) { + const isOwnProperty = !!Object.getOwnPropertyDescriptor(target, p); + const val = Reflect.get(target, p); + if (!isOwnProperty && typeof val === 'function') { + // bind functions that are inherited from the prototype to the object itself. + // This should handle the case of events. + return val.bind(target); + } + return val; + }, + }) as T; +} + export function createAPIFactory( rpc: RPCProtocol, pluginManager: PluginManager, @@ -492,7 +507,8 @@ export function createAPIFactory( return quickOpenExt.showQuickPick(plugin, items, options, token); }, createQuickPick(): theia.QuickPick { - return quickOpenExt.createQuickPick(plugin); + + return createAPIObject(quickOpenExt.createQuickPick(plugin)); }, showWorkspaceFolderPick(options?: theia.WorkspaceFolderPickOptions): PromiseLike { return workspaceExt.pickWorkspaceFolder(options); @@ -531,9 +547,12 @@ export function createAPIFactory( priority = priorityOrAlignment; } + // TODO: here return statusBarMessageRegistryExt.createStatusBarItem(alignment, priority, id); }, createOutputChannel(name: string, options?: { log: true }): any { + + // TODO: here return !options ? outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin)) : outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin), options); @@ -542,7 +561,7 @@ export function createAPIFactory( title: string, showOptions: theia.ViewColumn | theia.WebviewPanelShowOptions, options: theia.WebviewPanelOptions & theia.WebviewOptions = {}): theia.WebviewPanel { - return webviewExt.createWebview(viewType, title, showOptions, options, plugin); + return createAPIObject(webviewExt.createWebview(viewType, title, showOptions, options, plugin)); }, registerWebviewPanelSerializer(viewType: string, serializer: theia.WebviewPanelSerializer): theia.Disposable { return webviewExt.registerWebviewPanelSerializer(viewType, serializer, plugin); @@ -570,19 +589,19 @@ export function createAPIFactory( createTerminal(nameOrOptions: theia.TerminalOptions | theia.ExtensionTerminalOptions | theia.ExtensionTerminalOptions | (string | undefined), shellPath?: string, shellArgs?: string[] | string): theia.Terminal { - return terminalExt.createTerminal(plugin, nameOrOptions, shellPath, shellArgs); + return createAPIObject(terminalExt.createTerminal(plugin, nameOrOptions, shellPath, shellArgs)); }, onDidChangeTerminalState, onDidCloseTerminal, onDidOpenTerminal, createTextEditorDecorationType(options: theia.DecorationRenderOptions): theia.TextEditorDecorationType { - return editors.createTextEditorDecorationType(options); + return createAPIObject(editors.createTextEditorDecorationType(options)); }, registerTreeDataProvider(viewId: string, treeDataProvider: theia.TreeDataProvider): Disposable { return treeViewsExt.registerTreeDataProvider(plugin, viewId, treeDataProvider); }, createTreeView(viewId: string, options: theia.TreeViewOptions): theia.TreeView { - return treeViewsExt.createTreeView(plugin, viewId, options); + return createAPIObject(treeViewsExt.createTreeView(plugin, viewId, options)); }, withScmProgress(task: (progress: theia.Progress) => Thenable) { const options: ProgressOptions = { location: ProgressLocation.SourceControl }; @@ -601,7 +620,7 @@ export function createAPIFactory( return uriExt.registerUriHandler(handler, pluginToPluginInfo(plugin)); }, createInputBox(): theia.InputBox { - return quickOpenExt.createInputBox(plugin); + return createAPIObject(quickOpenExt.createInputBox(plugin)); }, registerTerminalLinkProvider(provider: theia.TerminalLinkProvider): theia.Disposable { return terminalExt.registerTerminalLinkProvider(provider); @@ -649,7 +668,7 @@ export function createAPIFactory( const workspace: typeof theia.workspace = { get fs(): theia.FileSystem { - return fileSystemExt.fileSystem; + return fileSystemExt.fileSystem.apiObject; }, get rootPath(): string | undefined { @@ -752,7 +771,7 @@ export function createAPIFactory( return notebooksExt.getNotebookDocument(uri).apiNotebook; }, createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): theia.FileSystemWatcher => - extHostFileSystemEvent.createFileSystemWatcher(fromGlobPattern(pattern), ignoreCreate, ignoreChange, ignoreDelete), + createAPIObject(extHostFileSystemEvent.createFileSystemWatcher(fromGlobPattern(pattern), ignoreCreate, ignoreChange, ignoreDelete)), findFiles(include: theia.GlobPattern, exclude?: theia.GlobPattern | null, maxResults?: number, token?: CancellationToken): PromiseLike { return workspaceExt.findFiles(include, exclude, maxResults, token); }, @@ -845,7 +864,7 @@ export function createAPIFactory( return telemetryExt.onDidChangeTelemetryEnabled; }, createTelemetryLogger(sender: theia.TelemetrySender, options?: theia.TelemetryLoggerOptions): theia.TelemetryLogger { - return telemetryExt.createTelemetryLogger(sender, options); + return createAPIObject(telemetryExt.createTelemetryLogger(sender, options)); }, get remoteName(): string | undefined { return envExt.remoteName; }, get machineId(): string { return envExt.machineId; }, @@ -920,7 +939,7 @@ export function createAPIFactory( return languagesExt.getDiagnostics(resource); }, createDiagnosticCollection(name?: string): theia.DiagnosticCollection { - return languagesExt.createDiagnosticCollection(name); + return createAPIObject(languagesExt.createDiagnosticCollection(name)); }, setLanguageConfiguration(language: string, configuration: theia.LanguageConfiguration): theia.Disposable { return languagesExt.setLanguageConfiguration(language, configuration); @@ -1057,7 +1076,7 @@ export function createAPIFactory( const tests: typeof theia.tests = { createTestController(id, label: string) { - return testingExt.createTestController(id, label); + return createAPIObject(testingExt.createTestController(id, label)); } }; /* End of Tests API */ @@ -1169,6 +1188,7 @@ export function createAPIFactory( }, get taskExecutions(): ReadonlyArray { + // TODO: here return tasksExt.taskExecutions; }, onDidStartTask(listener, thisArg?, disposables?) { @@ -1189,19 +1209,19 @@ export function createAPIFactory( get inputBox(): theia.SourceControlInputBox { const inputBox = scmExt.getLastInputBox(plugin); if (inputBox) { - return inputBox; + return inputBox.apiObject; } else { throw new Error('Input box not found!'); } }, createSourceControl(id: string, label: string, rootUri?: URI): theia.SourceControl { - return scmExt.createSourceControl(plugin, id, label, rootUri); + return createAPIObject(scmExt.createSourceControl(plugin, id, label, rootUri)); } }; const comments: typeof theia.comments = { createCommentController(id: string, label: string): theia.CommentController { - return commentsExt.createCommentController(plugin, id, label); + return createAPIObject(commentsExt.createCommentController(plugin, id, label)); } }; diff --git a/packages/plugin-ext/src/plugin/scm.ts b/packages/plugin-ext/src/plugin/scm.ts index 4703ab3626f14..f34556cee2ae8 100644 --- a/packages/plugin-ext/src/plugin/scm.ts +++ b/packages/plugin-ext/src/plugin/scm.ts @@ -39,6 +39,7 @@ import { URI, ThemeIcon } from './types-impl'; import { ScmCommandArg } from '../common/plugin-api-rpc'; import { sep } from '@theia/core/lib/common/paths'; import { PluginIconPath } from './plugin-icon-path'; +import { createAPIObject } from './plugin-context'; type ProviderHandle = number; type GroupHandle = number; type ResourceStateHandle = number; @@ -290,6 +291,7 @@ interface ValidateInput { export class ScmInputBoxImpl implements theia.SourceControlInputBox { private _value: string = ''; + apiObject: theia.SourceControlInputBox; get value(): string { return this._value; @@ -354,7 +356,7 @@ export class ScmInputBoxImpl implements theia.SourceControlInputBox { } constructor(private plugin: Plugin, private proxy: ScmMain, private sourceControlHandle: number) { - // noop + this.apiObject = createAPIObject(this); } onInputBoxValueChange(value: string): void { @@ -543,8 +545,7 @@ class SourceControlImpl implements theia.SourceControl { return this._rootUri; } - private _inputBox: ScmInputBoxImpl; - get inputBox(): ScmInputBoxImpl { return this._inputBox; } + readonly inputBox: ScmInputBoxImpl; private _count: number | undefined = undefined; @@ -642,7 +643,7 @@ class SourceControlImpl implements theia.SourceControl { private _label: string, private _rootUri?: theia.Uri ) { - this._inputBox = new ScmInputBoxImpl(plugin, this.proxy, this.handle); + this.inputBox = new ScmInputBoxImpl(plugin, this.proxy, this.handle); this.proxy.$registerSourceControl(this.handle, _id, _label, _rootUri); }