From 2247067bfa9f60cfc74992d4831f6293f99b9f39 Mon Sep 17 00:00:00 2001 From: Tobias Ortmayr Date: Wed, 29 Nov 2023 00:23:40 -0800 Subject: [PATCH] GLSP-1166 Fix dependency injection cycle in selection service (#305) Avoid binding of SelectionService as `IModelRootListner`. Instead directly inject the`CommandStack` into `SelectionService` and manually register itself as `IGModelRootListener`. This avoids a circular dependency injection if any of the `SelectionListner`s wants to inject the `ActionDispatcher`. Fixes eclipse-glsp/glsp/issues/1166 --- packages/client/src/base/default.module.ts | 1 - packages/client/src/base/selection-service.ts | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/client/src/base/default.module.ts b/packages/client/src/base/default.module.ts index c33254eb..6690f866 100644 --- a/packages/client/src/base/default.module.ts +++ b/packages/client/src/base/default.module.ts @@ -96,7 +96,6 @@ export const defaultModule = new FeatureModule((bind, unbind, isBound, rebind, . bindOrRebind(context, TYPES.ViewRegistry).to(GViewRegistry).inSingletonScope(); bind(SelectionService).toSelf().inSingletonScope(); - bind(TYPES.IGModelRootListener).toService(SelectionService); // Feedback Support ------------------------------------ // Generic re-usable feedback modifying css classes diff --git a/packages/client/src/base/selection-service.ts b/packages/client/src/base/selection-service.ts index c8ace338..bb3b1542 100644 --- a/packages/client/src/base/selection-service.ts +++ b/packages/client/src/base/selection-service.ts @@ -37,7 +37,7 @@ import { } from '@eclipse-glsp/sprotty'; import { inject, injectable, multiInject, optional, postConstruct, preDestroy } from 'inversify'; import { getElements, getMatchingElements } from '../utils/gmodel-util'; -import { IGModelRootListener } from './command-stack'; +import { GLSPCommandStack, IGModelRootListener } from './command-stack'; import { IFeedbackActionDispatcher } from './feedback/feedback-action-dispatcher'; export interface ISelectionListener { @@ -61,6 +61,9 @@ export class SelectionService implements IGModelRootListener, Disposable { @inject(TYPES.ILogger) protected logger: ILogger; + @inject(TYPES.ICommandStack) + protected commandStack: GLSPCommandStack; + @multiInject(TYPES.ISelectionListener) @optional() protected selectionListeners: ISelectionListener[] = []; @@ -69,7 +72,11 @@ export class SelectionService implements IGModelRootListener, Disposable { @postConstruct() protected initialize(): void { - this.toDispose.push(this.onSelectionChangedEmitter); + this.toDispose.push( + this.onSelectionChangedEmitter, + this.commandStack.onModelRootChanged(root => this.modelRootChanged(root)) + ); + this.selectionListeners.forEach(listener => this.onSelectionChanged(change => listener.selectionChanged(change.root, change.selectedElements, change.deselectedElements)) );