Get rid of 1 cyclic dependency

This commit is contained in:
lee-at-zoo-corp
2025-04-03 14:32:04 -04:00
parent 277c489e38
commit 3471f73479
3 changed files with 56 additions and 33 deletions

View File

@ -47,7 +47,6 @@ export const setDiagnosticsEvent = setDiagnosticsAnnotation.of(true)
export default class EditorManager {
private _copilotEnabled: boolean = true
private engineCommandManager: EngineCommandManager
private kclManager: KclManager
private _isAllTextSelected: boolean = false
private _isShiftDown: boolean = false
@ -67,13 +66,12 @@ export default class EditorManager {
private _highlightRange: Array<[number, number]> = [[0, 0]]
public _editorView: EditorView | null = null
public kclManager?: KclManager
constructor(
engineCommandManager: EngineCommandManager,
kclManager: KclManager
) {
this.engineCommandManager = engineCommandManager
this.kclManager = kclManager
}
setCopilotEnabled(enabled: boolean) {
@ -387,6 +385,11 @@ export default class EditorManager {
}
)
if (!this.kclManager) {
console.error('unreachable')
return
}
const eventInfo = processCodeMirrorRanges({
codeMirrorRanges: viewUpdate.state.selection.ranges,
selectionRanges: this._selectionRanges,

View File

@ -1,3 +1,7 @@
import type { SceneInfra } from '@src/clientSideScene/sceneInfra'
import type EditorManager from '@src/editor/manager'
import type CodeManager from '@src/lang/codeManager'
import type RustContext from '@src/lib/rustContext'
import type { Diagnostic } from '@codemirror/lint'
import type {
EntityType_type,
@ -47,12 +51,7 @@ import type {
KclSettingsAnnotation,
} from '@src/lib/settings/settingsTypes'
import { jsAppSettings } from '@src/lib/settings/settingsUtils'
import {
codeManager,
editorManager,
rustContext,
sceneInfra,
} from '@src/lib/singletons'
import { err, reportRejection } from '@src/lib/trap'
import { deferExecution, isOverlap, uuidv4 } from '@src/lib/utils'
@ -61,6 +60,15 @@ interface ExecuteArgs {
executionId?: number
}
// Each of our singletons has dependencies on _other_ singletons, so importing
// can easily become cyclic. Each will have its own Singletons type.
interface Singletons {
rustContext: RustContext
codeManager: CodeManager
editorManager: EditorManager
sceneInfra: SceneInfra
}
export class KclManager {
/**
* The artifactGraph is a client-side representation of the commands that have been sent
@ -99,6 +107,7 @@ export class KclManager {
private _switchedFiles = false
private _fileSettings: KclSettingsAnnotation = {}
private _kclVersion: string | undefined = undefined
private singletons: Singletons
engineCommandManager: EngineCommandManager
@ -189,7 +198,7 @@ export class KclManager {
}
setDiagnosticsForCurrentErrors() {
editorManager?.setDiagnostics(this.diagnostics)
this.singletons.editorManager?.setDiagnostics(this.diagnostics)
this._diagnosticsCallback(this.diagnostics)
}
@ -226,12 +235,13 @@ export class KclManager {
this._wasmInitFailedCallback(wasmInitFailed)
}
constructor(engineCommandManager: EngineCommandManager) {
constructor(engineCommandManager: EngineCommandManager, singletons: Singletons) {
this.engineCommandManager = engineCommandManager
this.singletons = singletons
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.ensureWasmInit().then(async () => {
await this.safeParse(codeManager.code).then((ast) => {
await this.safeParse(this.singletons.codeManager.code).then((ast) => {
if (ast) {
this.ast = ast
}
@ -297,9 +307,9 @@ export class KclManager {
// If we were switching files and we hit an error on parse we need to bust
// the cache and clear the scene.
if (this._astParseFailed && this._switchedFiles) {
await rustContext.clearSceneAndBustCache(
await this.singletons.rustContext.clearSceneAndBustCache(
{ settings: await jsAppSettings() },
codeManager.currentFilePath || undefined
this.singletons.codeManager.currentFilePath || undefined
)
} else if (this._switchedFiles) {
// Reset the switched files boolean.
@ -422,8 +432,8 @@ export class KclManager {
await this.ensureWasmInit()
const { logs, errors, execState, isInterrupted } = await executeAst({
ast,
path: codeManager.currentFilePath || undefined,
rustContext,
path: this.singletons.codeManager.currentFilePath || undefined,
rustContext: this.singletons.rustContext,
})
// Program was not interrupted, setup the scene
@ -471,7 +481,7 @@ export class KclManager {
await this.updateArtifactGraph(execState.artifactGraph)
this._executeCallback()
if (!isInterrupted) {
sceneInfra.modelingSend({ type: 'code edit during sketch' })
this.singletons.sceneInfra.modelingSend({ type: 'code edit during sketch' })
}
this.engineCommandManager.addCommandLog({
type: CommandLogType.ExecutionDone,
@ -519,7 +529,7 @@ export class KclManager {
const { logs, errors, execState } = await executeAstMock({
ast: newAst,
rustContext,
rustContext: this.singletons.rustContext,
})
this._logs = logs
@ -536,7 +546,7 @@ export class KclManager {
})
}
async executeCode(): Promise<void> {
const ast = await this.safeParse(codeManager.code)
const ast = await this.safeParse(this.singletons.codeManager.code)
if (!ast) {
// By clearing the AST we indicate to our callers that there was an issue with execution and
@ -550,7 +560,7 @@ export class KclManager {
}
async format() {
const originalCode = codeManager.code
const originalCode = this.singletons.codeManager.code
const ast = await this.safeParse(originalCode)
if (!ast) {
this.clearAst()
@ -564,10 +574,10 @@ export class KclManager {
if (originalCode === code) return
// Update the code state and the editor.
codeManager.updateCodeStateEditor(code)
this.singletons.codeManager.updateCodeStateEditor(code)
// Write back to the file system.
void codeManager
void this.singletons.codeManager
.writeToFile()
.then(() => this.executeCode())
.catch(reportRejection)
@ -643,7 +653,7 @@ export class KclManager {
}
get defaultPlanes() {
return rustContext.defaultPlanes
return this.singletons.rustContext.defaultPlanes
}
showPlanes(all = false) {

View File

@ -10,8 +10,8 @@ import { SceneInfra } from '@src/clientSideScene/sceneInfra'
import type { BaseUnit } from '@src/lib/settings/settingsTypes'
export const codeManager = new CodeManager()
export const engineCommandManager = new EngineCommandManager()
export const rustContext = new RustContext(engineCommandManager)
declare global {
interface Window {
@ -23,21 +23,31 @@ declare global {
// Accessible for tests mostly
window.engineCommandManager = engineCommandManager
// This needs to be after codeManager is created.
export const kclManager = new KclManager(engineCommandManager)
engineCommandManager.kclManager = kclManager
export const sceneInfra = new SceneInfra(engineCommandManager)
engineCommandManager.camControlsCameraChange = sceneInfra.onCameraChange
// This needs to be after sceneInfra and engineCommandManager are is created.
export const editorManager = new EditorManager(engineCommandManager)
// This needs to be after codeManager is created.
// (lee: what??? why?)
export const kclManager = new KclManager(engineCommandManager, {
rustContext,
codeManager,
editorManager,
sceneInfra,
})
// The most obvious of cyclic dependencies.
// This is because the handleOnViewUpdate(viewUpdate: ViewUpdate): void {
// method requires it for the current ast.
editorManager.kclManager = kclManager
engineCommandManager.kclManager = kclManager
kclManager.sceneInfraBaseUnitMultiplierSetter = (unit: BaseUnit) => {
sceneInfra.baseUnit = unit
}
// This needs to be after sceneInfra and engineCommandManager are is created.
export const editorManager = new EditorManager(engineCommandManager, kclManager)
export const rustContext = new RustContext(engineCommandManager)
export const sceneEntitiesManager = new SceneEntities(
engineCommandManager,
sceneInfra,