From b177c03c951333425eb35fe104bc280881d210ea Mon Sep 17 00:00:00 2001 From: Tobias Ortmayr Date: Wed, 29 Nov 2023 18:01:37 +0100 Subject: [PATCH 1/2] GLSP-1181: Fix support for simultaneously open diagrams Fixes https://github.com/eclipse-glsp/glsp/issues/1181 Also: Update changelog to reflect latest changes --- CHANGELOG.md | 11 ++++++++--- .../jsonrpc/base-jsonrpc-glsp-client.ts | 11 ++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebc9420..e72c5a40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,17 @@ # Eclipse GLSP Client Changelog -## v2.10.0 - active +## v2.1.0 - active ### Changes +- [diagram] Fix a bug that prevented correct rendering of projection bars when using `GLSPProjectionView` [#298](https://github.com/eclipse-glsp/glsp-client/pull/298) +- [a11y] Improved responsibility and feedback when resizing or moving diagram elements with keyboard-only commands [#295](https://github.com/eclipse-glsp/glsp-client/pull/295) +- [diagram] Extends `configureDiagramOptions` function to also allow partial configuration of `ViewerOptions` [#296](https://github.com/eclipse-glsp/glsp-client/pull/296) - [diagram] Remove unused handleSetContextActions from ToolPalette [#301](https://github.com/eclipse-glsp/glsp-client/pull/301) - -### Breaking Changes +- [diagram] Deprecate `ISModelRootListener` API in favor of `IGModelRootListener` [#303](https://github.com/eclipse-glsp/glsp-client/pull/303) +- [diagram] Ensure that the suggestion container position of the `AutoCompleteWidget` is rendered correctly [#304](https://github.com/eclipse-glsp/glsp-client/pull/304) +- [feature] Extend `ToolPalette`/`CreateOperation` API to support rendering of preview/ghost elements when creating new nodes [#301](https://github.com/eclipse-glsp/glsp-client/pull/301) +- [protocol] Fix a bug in `BaseJsonRpcClient` to ensure that it can handle multiple open diagram sessions [#307](https://github.com/eclipse-glsp/glsp-client/pull/307) ## [v2.0.0 - 14/10/2023](https://github.com/eclipse-glsp/glsp-client/releases/tag/v2.0.0) diff --git a/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts b/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts index 47e9dd71..cc17491a 100644 --- a/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts +++ b/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts @@ -36,6 +36,11 @@ export class BaseJsonrpcGLSPClient implements GLSPClient { return this.onServerInitializedEmitter.event; } + protected onActionMessageNotificationEmitter = new Emitter(); + protected get onActionMessageNotification(): Event { + return this.onActionMessageNotificationEmitter.event; + } + constructor(options: JsonrpcGLSPClient.Options) { Object.assign(this, options); this.state = ClientState.Initial; @@ -66,7 +71,7 @@ export class BaseJsonrpcGLSPClient implements GLSPClient { } onActionMessage(handler: ActionMessageHandler, clientId?: string): Disposable { - return this.checkedConnection.onNotification(JsonrpcGLSPClient.ActionMessageNotification, msg => { + return this.onActionMessageNotification(msg => { if (!clientId || msg.clientId === clientId) { handler(msg); } @@ -91,6 +96,9 @@ export class BaseJsonrpcGLSPClient implements GLSPClient { try { this.state = ClientState.Starting; const connection = await this.resolveConnection(); + connection.onNotification(JsonrpcGLSPClient.ActionMessageNotification, msg => + this.onActionMessageNotificationEmitter.fire(msg) + ); connection.listen(); this.resolvedConnection = connection; this.state = ClientState.Running; @@ -113,6 +121,7 @@ export class BaseJsonrpcGLSPClient implements GLSPClient { connection.dispose(); this.state = ClientState.Stopped; this.onStop = undefined; + this.onActionMessageNotificationEmitter.dispose(); this.connectionPromise = undefined; this.resolvedConnection = undefined; })); From 7c3d36d63e6210bfb8388dc829dd358c5fc29427 Mon Sep 17 00:00:00 2001 From: Tobias Ortmayr Date: Thu, 30 Nov 2023 09:43:10 +0100 Subject: [PATCH 2/2] Address review feedback and fix tests --- .../jsonrpc/base-jsonrpc-glsp-client.spec.ts | 33 +++++++++++++++---- .../jsonrpc/base-jsonrpc-glsp-client.ts | 4 +-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.spec.ts b/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.spec.ts index 51b7c3fe..5538f763 100644 --- a/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.spec.ts +++ b/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.spec.ts @@ -19,6 +19,7 @@ import * as sinon from 'sinon'; import { Disposable, Event, MessageConnection, NotificationHandler, ProgressType } from 'vscode-jsonrpc'; import { ActionMessage } from '../../action-protocol/base-protocol'; import { remove } from '../../utils/array-util'; +import { Emitter } from '../../utils/event'; import { expectToThrowAsync } from '../../utils/test-util'; import { ClientState } from '../glsp-client'; import { InitializeResult } from '../types'; @@ -68,13 +69,23 @@ class StubMessageConnection implements MessageConnection { inspect(): void {} } +class TestJsonRpcClient extends BaseJsonrpcGLSPClient { + protected override onActionMessageNotificationEmitter = new Emitter({ + onFirstListenerAdd: () => (this.firstListenerAdded = true), + onLastListenerRemove: () => (this.lastListenerRemoved = true) + }); + + firstListenerAdded: boolean; + lastListenerRemoved: boolean; +} + describe('Base JSON-RPC GLSP Client', () => { const sandbox = sinon.createSandbox(); const connection = sandbox.stub(new StubMessageConnection()); - let client = new BaseJsonrpcGLSPClient({ id: 'test', connectionProvider: connection }); + let client = new TestJsonRpcClient({ id: 'test', connectionProvider: connection }); async function resetClient(setRunning = true): Promise { sandbox.reset(); - client = new BaseJsonrpcGLSPClient({ id: 'test', connectionProvider: connection }); + client = new TestJsonRpcClient({ id: 'test', connectionProvider: connection }); if (setRunning) { return client.start(); } @@ -221,16 +232,24 @@ describe('Base JSON-RPC GLSP Client', () => { // eslint-disable-next-line @typescript-eslint/no-empty-function const handler = sandbox.spy((_message: ActionMessage): void => {}); - it('should fail if client is not running', async () => { + it('should be registered to message emitter if client is not running', async () => { await resetClient(false); - await expectToThrowAsync(() => client.onActionMessage(handler)); - expect(connection.onNotification.called).to.be.false; + client.onActionMessage(handler); + expect(client.firstListenerAdded).to.be.true; }); - it('should invoked the corresponding connection method', async () => { + it('should be registered to message emitter if client is running', async () => { await resetClient(); client.onActionMessage(handler, 'someId'); - expect(connection.onNotification.withArgs(JsonrpcGLSPClient.ActionMessageNotification).calledOnce).to.be.true; + expect(client.firstListenerAdded).to.be.true; + }); + it('should unregister lister if dispose is invoked', () => { + resetClient(false); + const clientId = 'clientId'; + const toDispose = client.onActionMessage(handler, clientId); + expect(client.firstListenerAdded).to.be.true; + toDispose.dispose(); + expect(client.lastListenerRemoved).to.be.true; }); }); diff --git a/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts b/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts index cc17491a..9cc1adc7 100644 --- a/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts +++ b/packages/protocol/src/client-server-protocol/jsonrpc/base-jsonrpc-glsp-client.ts @@ -96,9 +96,6 @@ export class BaseJsonrpcGLSPClient implements GLSPClient { try { this.state = ClientState.Starting; const connection = await this.resolveConnection(); - connection.onNotification(JsonrpcGLSPClient.ActionMessageNotification, msg => - this.onActionMessageNotificationEmitter.fire(msg) - ); connection.listen(); this.resolvedConnection = connection; this.state = ClientState.Running; @@ -138,6 +135,7 @@ export class BaseJsonrpcGLSPClient implements GLSPClient { const connection = typeof this.connectionProvider === 'function' ? await this.connectionProvider() : this.connectionProvider; connection.onError(data => this.handleConnectionError(data[0], data[1], data[2])); connection.onClose(() => this.handleConnectionClosed()); + connection.onNotification(JsonrpcGLSPClient.ActionMessageNotification, msg => this.onActionMessageNotificationEmitter.fire(msg)); return connection; }