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 { export default class EditorManager {
private _copilotEnabled: boolean = true private _copilotEnabled: boolean = true
private engineCommandManager: EngineCommandManager private engineCommandManager: EngineCommandManager
private kclManager: KclManager
private _isAllTextSelected: boolean = false private _isAllTextSelected: boolean = false
private _isShiftDown: boolean = false private _isShiftDown: boolean = false
@ -67,13 +66,12 @@ export default class EditorManager {
private _highlightRange: Array<[number, number]> = [[0, 0]] private _highlightRange: Array<[number, number]> = [[0, 0]]
public _editorView: EditorView | null = null public _editorView: EditorView | null = null
public kclManager?: KclManager
constructor( constructor(
engineCommandManager: EngineCommandManager, engineCommandManager: EngineCommandManager,
kclManager: KclManager
) { ) {
this.engineCommandManager = engineCommandManager this.engineCommandManager = engineCommandManager
this.kclManager = kclManager
} }
setCopilotEnabled(enabled: boolean) { setCopilotEnabled(enabled: boolean) {
@ -387,6 +385,11 @@ export default class EditorManager {
} }
) )
if (!this.kclManager) {
console.error('unreachable')
return
}
const eventInfo = processCodeMirrorRanges({ const eventInfo = processCodeMirrorRanges({
codeMirrorRanges: viewUpdate.state.selection.ranges, codeMirrorRanges: viewUpdate.state.selection.ranges,
selectionRanges: this._selectionRanges, 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 { Diagnostic } from '@codemirror/lint'
import type { import type {
EntityType_type, EntityType_type,
@ -47,12 +51,7 @@ import type {
KclSettingsAnnotation, KclSettingsAnnotation,
} from '@src/lib/settings/settingsTypes' } from '@src/lib/settings/settingsTypes'
import { jsAppSettings } from '@src/lib/settings/settingsUtils' import { jsAppSettings } from '@src/lib/settings/settingsUtils'
import {
codeManager,
editorManager,
rustContext,
sceneInfra,
} from '@src/lib/singletons'
import { err, reportRejection } from '@src/lib/trap' import { err, reportRejection } from '@src/lib/trap'
import { deferExecution, isOverlap, uuidv4 } from '@src/lib/utils' import { deferExecution, isOverlap, uuidv4 } from '@src/lib/utils'
@ -61,6 +60,15 @@ interface ExecuteArgs {
executionId?: number 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 { export class KclManager {
/** /**
* The artifactGraph is a client-side representation of the commands that have been sent * 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 _switchedFiles = false
private _fileSettings: KclSettingsAnnotation = {} private _fileSettings: KclSettingsAnnotation = {}
private _kclVersion: string | undefined = undefined private _kclVersion: string | undefined = undefined
private singletons: Singletons
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
@ -189,7 +198,7 @@ export class KclManager {
} }
setDiagnosticsForCurrentErrors() { setDiagnosticsForCurrentErrors() {
editorManager?.setDiagnostics(this.diagnostics) this.singletons.editorManager?.setDiagnostics(this.diagnostics)
this._diagnosticsCallback(this.diagnostics) this._diagnosticsCallback(this.diagnostics)
} }
@ -226,12 +235,13 @@ export class KclManager {
this._wasmInitFailedCallback(wasmInitFailed) this._wasmInitFailedCallback(wasmInitFailed)
} }
constructor(engineCommandManager: EngineCommandManager) { constructor(engineCommandManager: EngineCommandManager, singletons: Singletons) {
this.engineCommandManager = engineCommandManager this.engineCommandManager = engineCommandManager
this.singletons = singletons
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
this.ensureWasmInit().then(async () => { this.ensureWasmInit().then(async () => {
await this.safeParse(codeManager.code).then((ast) => { await this.safeParse(this.singletons.codeManager.code).then((ast) => {
if (ast) { if (ast) {
this.ast = 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 // If we were switching files and we hit an error on parse we need to bust
// the cache and clear the scene. // the cache and clear the scene.
if (this._astParseFailed && this._switchedFiles) { if (this._astParseFailed && this._switchedFiles) {
await rustContext.clearSceneAndBustCache( await this.singletons.rustContext.clearSceneAndBustCache(
{ settings: await jsAppSettings() }, { settings: await jsAppSettings() },
codeManager.currentFilePath || undefined this.singletons.codeManager.currentFilePath || undefined
) )
} else if (this._switchedFiles) { } else if (this._switchedFiles) {
// Reset the switched files boolean. // Reset the switched files boolean.
@ -422,8 +432,8 @@ export class KclManager {
await this.ensureWasmInit() await this.ensureWasmInit()
const { logs, errors, execState, isInterrupted } = await executeAst({ const { logs, errors, execState, isInterrupted } = await executeAst({
ast, ast,
path: codeManager.currentFilePath || undefined, path: this.singletons.codeManager.currentFilePath || undefined,
rustContext, rustContext: this.singletons.rustContext,
}) })
// Program was not interrupted, setup the scene // Program was not interrupted, setup the scene
@ -471,7 +481,7 @@ export class KclManager {
await this.updateArtifactGraph(execState.artifactGraph) await this.updateArtifactGraph(execState.artifactGraph)
this._executeCallback() this._executeCallback()
if (!isInterrupted) { if (!isInterrupted) {
sceneInfra.modelingSend({ type: 'code edit during sketch' }) this.singletons.sceneInfra.modelingSend({ type: 'code edit during sketch' })
} }
this.engineCommandManager.addCommandLog({ this.engineCommandManager.addCommandLog({
type: CommandLogType.ExecutionDone, type: CommandLogType.ExecutionDone,
@ -519,7 +529,7 @@ export class KclManager {
const { logs, errors, execState } = await executeAstMock({ const { logs, errors, execState } = await executeAstMock({
ast: newAst, ast: newAst,
rustContext, rustContext: this.singletons.rustContext,
}) })
this._logs = logs this._logs = logs
@ -536,7 +546,7 @@ export class KclManager {
}) })
} }
async executeCode(): Promise<void> { async executeCode(): Promise<void> {
const ast = await this.safeParse(codeManager.code) const ast = await this.safeParse(this.singletons.codeManager.code)
if (!ast) { if (!ast) {
// By clearing the AST we indicate to our callers that there was an issue with execution and // 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() { async format() {
const originalCode = codeManager.code const originalCode = this.singletons.codeManager.code
const ast = await this.safeParse(originalCode) const ast = await this.safeParse(originalCode)
if (!ast) { if (!ast) {
this.clearAst() this.clearAst()
@ -564,10 +574,10 @@ export class KclManager {
if (originalCode === code) return if (originalCode === code) return
// Update the code state and the editor. // Update the code state and the editor.
codeManager.updateCodeStateEditor(code) this.singletons.codeManager.updateCodeStateEditor(code)
// Write back to the file system. // Write back to the file system.
void codeManager void this.singletons.codeManager
.writeToFile() .writeToFile()
.then(() => this.executeCode()) .then(() => this.executeCode())
.catch(reportRejection) .catch(reportRejection)
@ -643,7 +653,7 @@ export class KclManager {
} }
get defaultPlanes() { get defaultPlanes() {
return rustContext.defaultPlanes return this.singletons.rustContext.defaultPlanes
} }
showPlanes(all = false) { showPlanes(all = false) {

View File

@ -10,8 +10,8 @@ import { SceneInfra } from '@src/clientSideScene/sceneInfra'
import type { BaseUnit } from '@src/lib/settings/settingsTypes' import type { BaseUnit } from '@src/lib/settings/settingsTypes'
export const codeManager = new CodeManager() export const codeManager = new CodeManager()
export const engineCommandManager = new EngineCommandManager() export const engineCommandManager = new EngineCommandManager()
export const rustContext = new RustContext(engineCommandManager)
declare global { declare global {
interface Window { interface Window {
@ -23,21 +23,31 @@ declare global {
// Accessible for tests mostly // Accessible for tests mostly
window.engineCommandManager = engineCommandManager 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) export const sceneInfra = new SceneInfra(engineCommandManager)
engineCommandManager.camControlsCameraChange = sceneInfra.onCameraChange 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) => { kclManager.sceneInfraBaseUnitMultiplierSetter = (unit: BaseUnit) => {
sceneInfra.baseUnit = unit 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( export const sceneEntitiesManager = new SceneEntities(
engineCommandManager, engineCommandManager,
sceneInfra, sceneInfra,