diff --git a/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-panel.ts b/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-panel.ts index 2cadeaa59a9..ec27fbe59ea 100644 --- a/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-panel.ts +++ b/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-panel.ts @@ -4,7 +4,6 @@ import { DisposableObject } from "../../common/disposable-object"; import { MethodModelingViewProvider } from "./method-modeling-view-provider"; import { Method } from "../method"; import { ModelingStore } from "../modeling-store"; -import { ModelEditorViewTracker } from "../model-editor-view-tracker"; import { ModelConfigListener } from "../../config"; import { DatabaseItem } from "../../databases/local-databases"; import { ModelingEvents } from "../modeling-events"; @@ -16,7 +15,6 @@ export class MethodModelingPanel extends DisposableObject { app: App, modelingStore: ModelingStore, modelingEvents: ModelingEvents, - editorViewTracker: ModelEditorViewTracker, ) { super(); @@ -29,7 +27,6 @@ export class MethodModelingPanel extends DisposableObject { app, modelingStore, modelingEvents, - editorViewTracker, modelConfig, ); this.push( diff --git a/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts b/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts index eb2bef583de..73fc3a2981f 100644 --- a/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts +++ b/extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts @@ -10,7 +10,6 @@ import { Method } from "../method"; import { ModelingStore } from "../modeling-store"; import { AbstractWebviewViewProvider } from "../../common/vscode/abstract-webview-view-provider"; import { assertNever } from "../../common/helpers-pure"; -import { ModelEditorViewTracker } from "../model-editor-view-tracker"; import { ModelConfigListener } from "../../config"; import { DatabaseItem } from "../../databases/local-databases"; import { ModelingEvents } from "../modeling-events"; @@ -33,7 +32,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider< app: App, private readonly modelingStore: ModelingStore, private readonly modelingEvents: ModelingEvents, - private readonly editorViewTracker: ModelEditorViewTracker, private readonly modelConfig: ModelConfigListener, ) { super(app, "method-modeling"); @@ -158,10 +156,10 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider< return; } - const view = this.editorViewTracker.getView( + this.modelingEvents.fireRevealInModelEditorEvent( this.databaseItem.databaseUri.toString(), + method, ); - await view?.revealMethod(method); } private registerToModelingEvents(): void { diff --git a/extensions/ql-vscode/src/model-editor/model-editor-module.ts b/extensions/ql-vscode/src/model-editor/model-editor-module.ts index 1208b26297d..4388aeb9345 100644 --- a/extensions/ql-vscode/src/model-editor/model-editor-module.ts +++ b/extensions/ql-vscode/src/model-editor/model-editor-module.ts @@ -19,7 +19,6 @@ import { setUpPack } from "./model-editor-queries-setup"; import { MethodModelingPanel } from "./method-modeling/method-modeling-panel"; import { ModelingStore } from "./modeling-store"; import { showResolvableLocation } from "../databases/local-databases/locations"; -import { ModelEditorViewTracker } from "./model-editor-view-tracker"; import { ModelConfigListener } from "../config"; import { ModelingEvents } from "./modeling-events"; import { getModelsAsDataLanguage } from "./languages"; @@ -30,7 +29,6 @@ export class ModelEditorModule extends DisposableObject { private readonly queryStorageDir: string; private readonly modelingStore: ModelingStore; private readonly modelingEvents: ModelingEvents; - private readonly editorViewTracker: ModelEditorViewTracker; private readonly methodsUsagePanel: MethodsUsagePanel; private readonly methodModelingPanel: MethodModelingPanel; private readonly modelConfig: ModelConfigListener; @@ -46,17 +44,11 @@ export class ModelEditorModule extends DisposableObject { this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results"); this.modelingEvents = new ModelingEvents(app); this.modelingStore = new ModelingStore(this.modelingEvents); - this.editorViewTracker = new ModelEditorViewTracker(); this.methodsUsagePanel = this.push( new MethodsUsagePanel(this.modelingStore, this.modelingEvents, cliServer), ); this.methodModelingPanel = this.push( - new MethodModelingPanel( - app, - this.modelingStore, - this.modelingEvents, - this.editorViewTracker, - ), + new MethodModelingPanel(app, this.modelingStore, this.modelingEvents), ); this.modelConfig = this.push(new ModelConfigListener()); @@ -144,12 +136,10 @@ export class ModelEditorModule extends DisposableObject { const initialMode = definition.availableModes?.[0] ?? INITIAL_MODE; - const existingView = this.editorViewTracker.getView( - db.databaseUri.toString(), - ); - if (existingView) { - await existingView.focusView(); - + if (this.modelingStore.isDbOpen(db.databaseUri.toString())) { + this.modelingEvents.fireFocusModelEditorEvent( + db.databaseUri.toString(), + ); return; } @@ -218,12 +208,10 @@ export class ModelEditorModule extends DisposableObject { // Check again just before opening the editor to ensure no model editor has been opened between // our first check and now. - const existingView = this.editorViewTracker.getView( - db.databaseUri.toString(), - ); - if (existingView) { - await existingView.focusView(); - + if (this.modelingStore.isDbOpen(db.databaseUri.toString())) { + this.modelingEvents.fireFocusModelEditorEvent( + db.databaseUri.toString(), + ); return; } @@ -231,7 +219,6 @@ export class ModelEditorModule extends DisposableObject { this.app, this.modelingStore, this.modelingEvents, - this.editorViewTracker, this.modelConfig, this.databaseManager, this.cliServer, diff --git a/extensions/ql-vscode/src/model-editor/model-editor-view-tracker.ts b/extensions/ql-vscode/src/model-editor/model-editor-view-tracker.ts deleted file mode 100644 index b4cf12978de..00000000000 --- a/extensions/ql-vscode/src/model-editor/model-editor-view-tracker.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Method } from "./method"; - -interface ModelEditorViewInterface { - databaseUri: string; - - revealMethod(method: Method): Promise; -} - -export class ModelEditorViewTracker< - T extends ModelEditorViewInterface = ModelEditorViewInterface, -> { - private readonly views = new Map(); - - constructor() {} - - public registerView(view: T): void { - const databaseUri = view.databaseUri; - - if (this.views.has(databaseUri)) { - throw new Error(`View for database ${databaseUri} already registered`); - } - - this.views.set(databaseUri, view); - } - - public unregisterView(view: T): void { - this.views.delete(view.databaseUri); - } - - public getView(databaseUri: string): T | undefined { - return this.views.get(databaseUri); - } -} diff --git a/extensions/ql-vscode/src/model-editor/model-editor-view.ts b/extensions/ql-vscode/src/model-editor/model-editor-view.ts index e8e7e0904ce..c23f27173a5 100644 --- a/extensions/ql-vscode/src/model-editor/model-editor-view.ts +++ b/extensions/ql-vscode/src/model-editor/model-editor-view.ts @@ -44,7 +44,6 @@ import { import { AutoModeler } from "./auto-modeler"; import { telemetryListener } from "../common/vscode/telemetry"; import { ModelingStore } from "./modeling-store"; -import { ModelEditorViewTracker } from "./model-editor-view-tracker"; import { ModelingEvents } from "./modeling-events"; import { getModelsAsDataLanguage, ModelsAsDataLanguage } from "./languages"; import { runGenerateQueries } from "./generate"; @@ -60,7 +59,6 @@ export class ModelEditorView extends AbstractWebview< protected readonly app: App, private readonly modelingStore: ModelingStore, private readonly modelingEvents: ModelingEvents, - private readonly viewTracker: ModelEditorViewTracker, private readonly modelConfig: ModelConfigListener, private readonly databaseManager: DatabaseManager, private readonly cliServer: CodeQLCliServer, @@ -79,8 +77,6 @@ export class ModelEditorView extends AbstractWebview< this.registerToModelingEvents(); this.registerToModelConfigEvents(); - this.viewTracker.registerView(this); - this.autoModeler = new AutoModeler( app, cliServer, @@ -166,7 +162,7 @@ export class ModelEditorView extends AbstractWebview< } protected onPanelDispose(): void { - this.viewTracker.unregisterView(this); + // Nothing to do } protected async onMessage(msg: FromModelEditorMessage): Promise { @@ -573,12 +569,9 @@ export class ModelEditorView extends AbstractWebview< return; } - let existingView = this.viewTracker.getView( - addedDatabase.databaseUri.toString(), - ); - if (existingView) { - await existingView.focusView(); - + const addedDbUri = addedDatabase.databaseUri.toString(); + if (this.modelingStore.isDbOpen(addedDbUri)) { + this.modelingEvents.fireFocusModelEditorEvent(addedDbUri); return; } @@ -596,12 +589,8 @@ export class ModelEditorView extends AbstractWebview< // Check again just before opening the editor to ensure no model editor has been opened between // our first check and now. - existingView = this.viewTracker.getView( - addedDatabase.databaseUri.toString(), - ); - if (existingView) { - await existingView.focusView(); - + if (this.modelingStore.isDbOpen(addedDbUri)) { + this.modelingEvents.fireFocusModelEditorEvent(addedDbUri); return; } @@ -609,7 +598,6 @@ export class ModelEditorView extends AbstractWebview< this.app, this.modelingStore, this.modelingEvents, - this.viewTracker, this.modelConfig, this.databaseManager, this.cliServer, @@ -742,6 +730,22 @@ export class ModelEditorView extends AbstractWebview< } }), ); + + this.push( + this.modelingEvents.onRevealInModelEditor(async (event) => { + if (event.dbUri === this.databaseItem.databaseUri.toString()) { + await this.revealMethod(event.method); + } + }), + ); + + this.push( + this.modelingEvents.onFocusModelEditor(async (event) => { + if (event.dbUri === this.databaseItem.databaseUri.toString()) { + await this.focusView(); + } + }), + ); } private registerToModelConfigEvents() { diff --git a/extensions/ql-vscode/src/model-editor/modeling-events.ts b/extensions/ql-vscode/src/model-editor/modeling-events.ts index 795a8d9d27f..685a5d5900d 100644 --- a/extensions/ql-vscode/src/model-editor/modeling-events.ts +++ b/extensions/ql-vscode/src/model-editor/modeling-events.ts @@ -48,6 +48,15 @@ interface InProgressMethodsChangedEvent { readonly methods: ReadonlySet; } +interface RevealInModelEditorEvent { + dbUri: string; + method: Method; +} + +interface FocusModelEditorEvent { + dbUri: string; +} + export class ModelingEvents extends DisposableObject { public readonly onActiveDbChanged: AppEvent; public readonly onDbOpened: AppEvent; @@ -59,6 +68,8 @@ export class ModelingEvents extends DisposableObject { public readonly onModifiedMethodsChanged: AppEvent; public readonly onSelectedMethodChanged: AppEvent; public readonly onInProgressMethodsChanged: AppEvent; + public readonly onRevealInModelEditor: AppEvent; + public readonly onFocusModelEditor: AppEvent; private readonly onActiveDbChangedEventEmitter: AppEventEmitter; private readonly onDbOpenedEventEmitter: AppEventEmitter; @@ -70,6 +81,8 @@ export class ModelingEvents extends DisposableObject { private readonly onModifiedMethodsChangedEventEmitter: AppEventEmitter; private readonly onSelectedMethodChangedEventEmitter: AppEventEmitter; private readonly onInProgressMethodsChangedEventEmitter: AppEventEmitter; + private readonly onRevealInModelEditorEventEmitter: AppEventEmitter; + private readonly onFocusModelEditorEventEmitter: AppEventEmitter; constructor(app: App) { super(); @@ -126,6 +139,16 @@ export class ModelingEvents extends DisposableObject { ); this.onInProgressMethodsChanged = this.onInProgressMethodsChangedEventEmitter.event; + + this.onRevealInModelEditorEventEmitter = this.push( + app.createEventEmitter(), + ); + this.onRevealInModelEditor = this.onRevealInModelEditorEventEmitter.event; + + this.onFocusModelEditorEventEmitter = this.push( + app.createEventEmitter(), + ); + this.onFocusModelEditor = this.onFocusModelEditorEventEmitter.event; } public fireActiveDbChangedEvent() { @@ -220,4 +243,17 @@ export class ModelingEvents extends DisposableObject { methods, }); } + + public fireRevealInModelEditorEvent(dbUri: string, method: Method) { + this.onRevealInModelEditorEventEmitter.fire({ + dbUri, + method, + }); + } + + public fireFocusModelEditorEvent(dbUri: string) { + this.onFocusModelEditorEventEmitter.fire({ + dbUri, + }); + } } diff --git a/extensions/ql-vscode/src/model-editor/modeling-store.ts b/extensions/ql-vscode/src/model-editor/modeling-store.ts index 537dd9b7214..4124c4af1c5 100644 --- a/extensions/ql-vscode/src/model-editor/modeling-store.ts +++ b/extensions/ql-vscode/src/model-editor/modeling-store.ts @@ -112,6 +112,10 @@ export class ModelingStore extends DisposableObject { return this.state.size > 0; } + public isDbOpen(dbUri: string): boolean { + return this.state.has(dbUri); + } + /** * Returns the method for the given database item and method signature. * Returns undefined if no method exists with that signature. diff --git a/extensions/ql-vscode/test/__mocks__/model-editor/modelEditorViewTrackerMock.ts b/extensions/ql-vscode/test/__mocks__/model-editor/modelEditorViewTrackerMock.ts deleted file mode 100644 index 9a4655c6df9..00000000000 --- a/extensions/ql-vscode/test/__mocks__/model-editor/modelEditorViewTrackerMock.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { mockedObject } from "../../vscode-tests/utils/mocking.helpers"; -import { ModelEditorViewTracker } from "../../../src/model-editor/model-editor-view-tracker"; -import { ModelEditorView } from "../../../src/model-editor/model-editor-view"; - -export function createMockModelEditorViewTracker({ - registerView = jest.fn(), - unregisterView = jest.fn(), - getView = jest.fn(), -}: { - registerView?: ModelEditorViewTracker["registerView"]; - unregisterView?: ModelEditorViewTracker["unregisterView"]; - getView?: ModelEditorViewTracker["getView"]; -} = {}): ModelEditorViewTracker { - return mockedObject>({ - registerView, - unregisterView, - getView, - }); -} diff --git a/extensions/ql-vscode/test/__mocks__/model-editor/modelingEventsMock.ts b/extensions/ql-vscode/test/__mocks__/model-editor/modelingEventsMock.ts index f297ca9d456..4d1a4f47c28 100644 --- a/extensions/ql-vscode/test/__mocks__/model-editor/modelingEventsMock.ts +++ b/extensions/ql-vscode/test/__mocks__/model-editor/modelingEventsMock.ts @@ -10,6 +10,8 @@ export function createMockModelingEvents({ onModeledMethodsChanged = jest.fn(), onModifiedMethodsChanged = jest.fn(), onInProgressMethodsChanged = jest.fn(), + onRevealInModelEditor = jest.fn(), + onFocusModelEditor = jest.fn(), }: { onActiveDbChanged?: ModelingEvents["onActiveDbChanged"]; onDbClosed?: ModelingEvents["onDbClosed"]; @@ -19,6 +21,8 @@ export function createMockModelingEvents({ onModeledMethodsChanged?: ModelingEvents["onModeledMethodsChanged"]; onModifiedMethodsChanged?: ModelingEvents["onModifiedMethodsChanged"]; onInProgressMethodsChanged?: ModelingEvents["onInProgressMethodsChanged"]; + onRevealInModelEditor?: ModelingEvents["onRevealInModelEditor"]; + onFocusModelEditor?: ModelingEvents["onFocusModelEditor"]; } = {}): ModelingEvents { return mockedObject({ onActiveDbChanged, @@ -29,5 +33,7 @@ export function createMockModelingEvents({ onModeledMethodsChanged, onModifiedMethodsChanged, onInProgressMethodsChanged, + onRevealInModelEditor, + onFocusModelEditor, }); } diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/model-editor-view.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/model-editor-view.test.ts index e9a4e3d8ecc..046ff196fd1 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/model-editor-view.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/model-editor-view.test.ts @@ -9,7 +9,6 @@ import { mockEmptyDatabaseManager } from "../query-testing/test-runner-helpers"; import { QueryRunner } from "../../../../src/query-server"; import { ExtensionPack } from "../../../../src/model-editor/shared/extension-pack"; import { createMockModelingStore } from "../../../__mocks__/model-editor/modelingStoreMock"; -import { createMockModelEditorViewTracker } from "../../../__mocks__/model-editor/modelEditorViewTrackerMock"; import { ModelConfigListener } from "../../../../src/config"; import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock"; import { QueryLanguage } from "../../../../src/common/query-language"; @@ -18,7 +17,6 @@ describe("ModelEditorView", () => { const app = createMockApp({}); const modelingStore = createMockModelingStore(); const modelingEvents = createMockModelingEvents(); - const viewTracker = createMockModelEditorViewTracker(); const modelConfig = mockedObject({ onDidChangeConfiguration: jest.fn(), }); @@ -48,7 +46,6 @@ describe("ModelEditorView", () => { app, modelingStore, modelingEvents, - viewTracker, modelConfig, databaseManager, cliServer,