Skip to content

Commit

Permalink
Wrap api objects returned to clients in a proxy and bind member
Browse files Browse the repository at this point in the history
functions to the object.

Fixes #13522

Contributed on behalf of STMicroelectronics

Signed-off-by: Thomas Mäder <[email protected]>
  • Loading branch information
tsmaeder committed Sep 23, 2024
1 parent 19556f4 commit 5682df5
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
10 changes: 7 additions & 3 deletions packages/plugin-ext/src/plugin/file-system-ext-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -137,8 +138,11 @@ export class FsLinkProvider {
}

class ConsumerFileSystem implements vscode.FileSystem {
apiObject: vscode.FileSystem;

constructor(private _proxy: FileSystemMain, private _capabilities: Map<string, number>) { }
constructor(private _proxy: FileSystemMain, private _capabilities: Map<string, number>) {
this.apiObject = createAPIObject(this);
}

stat(uri: vscode.Uri): Promise<vscode.FileStat> {
return this._proxy.$stat(uri).catch(ConsumerFileSystem._handleError);
Expand Down Expand Up @@ -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);
Expand Down
48 changes: 34 additions & 14 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,21 @@ import { NotebookEditorsExtImpl } from './notebook/notebook-editors';
import { TestingExtImpl } from './tests';
import { UriExtImpl } from './uri-ext';

export function createAPIObject<T extends Object>(rawObject: T): T {
return new Proxy({}, {
get(target, p, receiver) {
const isOwnProperty = !!Object.getOwnPropertyDescriptor(rawObject, p);
const val = Reflect.get(rawObject, 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(rawObject);
}
return val;
},
}) as T;
}

export function createAPIFactory(
rpc: RPCProtocol,
pluginManager: PluginManager,
Expand Down Expand Up @@ -492,7 +507,8 @@ export function createAPIFactory(
return quickOpenExt.showQuickPick(plugin, items, options, token);
},
createQuickPick<T extends theia.QuickPickItem>(): theia.QuickPick<T> {
return quickOpenExt.createQuickPick(plugin);

return createAPIObject(quickOpenExt.createQuickPick(plugin));
},
showWorkspaceFolderPick(options?: theia.WorkspaceFolderPickOptions): PromiseLike<theia.WorkspaceFolder | undefined> {
return workspaceExt.pickWorkspaceFolder(options);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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<T>(viewId: string, treeDataProvider: theia.TreeDataProvider<T>): Disposable {
return treeViewsExt.registerTreeDataProvider(plugin, viewId, treeDataProvider);
},
createTreeView<T>(viewId: string, options: theia.TreeViewOptions<T>): theia.TreeView<T> {
return treeViewsExt.createTreeView(plugin, viewId, options);
return createAPIObject(treeViewsExt.createTreeView(plugin, viewId, options));
},
withScmProgress<R>(task: (progress: theia.Progress<number>) => Thenable<R>) {
const options: ProgressOptions = { location: ProgressLocation.SourceControl };
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<URI[]> {
return workspaceExt.findFiles(include, exclude, maxResults, token);
},
Expand Down Expand Up @@ -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; },
Expand Down Expand Up @@ -920,7 +939,7 @@ export function createAPIFactory(
return <any>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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -1169,6 +1188,7 @@ export function createAPIFactory(
},

get taskExecutions(): ReadonlyArray<theia.TaskExecution> {
// TODO: here
return tasksExt.taskExecutions;
},
onDidStartTask(listener, thisArg?, disposables?) {
Expand All @@ -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));
}
};

Expand Down
9 changes: 5 additions & 4 deletions packages/plugin-ext/src/plugin/scm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -290,6 +291,7 @@ interface ValidateInput {
export class ScmInputBoxImpl implements theia.SourceControlInputBox {

private _value: string = '';
apiObject: theia.SourceControlInputBox;

get value(): string {
return this._value;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 5682df5

Please sign in to comment.