diff options
author | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2024-03-04 17:06:57 -0700 |
---|---|---|
committer | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2024-03-04 17:06:57 -0700 |
commit | 8288d086480d88ac4237f19c194d5829157bac38 (patch) | |
tree | 2e5fdc5e9367dcfad7db2df6c444d1d92fd26262 /src/engine/entities | |
parent | ccc1e182cf72916c9cdc4f10043048aa01a63390 (diff) | |
download | the-abstraction-engine-8288d086480d88ac4237f19c194d5829157bac38.tar.gz the-abstraction-engine-8288d086480d88ac4237f19c194d5829157bac38.zip |
working lambda editor
Diffstat (limited to 'src/engine/entities')
-rw-r--r-- | src/engine/entities/LambdaFactory.ts | 216 |
1 files changed, 117 insertions, 99 deletions
diff --git a/src/engine/entities/LambdaFactory.ts b/src/engine/entities/LambdaFactory.ts index 49436fe..1c897eb 100644 --- a/src/engine/entities/LambdaFactory.ts +++ b/src/engine/entities/LambdaFactory.ts @@ -35,6 +35,9 @@ import { parse } from "../../interpreter"; interface CodeEditorState { view: EditorView; editorElement: HTMLElement; + syntaxError: HTMLElement; + canvas: HTMLCanvasElement; + closeButton: HTMLButtonElement; } const highlightEffect = StateEffect.define<Range<Decoration>[]>(); @@ -54,12 +57,16 @@ const highlightExtension = StateField.define({ }, provide: (f) => EditorView.decorations.from(f), }); + const FontSizeTheme = EditorView.theme({ $: { - fontSize: "20pt", + fontSize: "16pt", }, }); const FontSizeThemeExtension: Extension = [FontSizeTheme]; +const syntaxErrorDecoration = Decoration.mark({ + class: "syntax-error", +}); export class LambdaFactory extends Entity { private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( @@ -67,13 +74,11 @@ export class LambdaFactory extends Entity { ) as SpriteSpec; private codeEditorState: CodeEditorState | null; - private code: string; private spawns: number; constructor(gridPosition: Coord2D, code: string, spawns: number) { super(EntityNames.LambdaFactory); - this.code = code; this.spawns = spawns; this.codeEditorState = null; @@ -95,7 +100,7 @@ export class LambdaFactory extends Entity { this.addComponent(new Colliding()); - this.addComponent(new LambdaSpawn(this.spawns, this.code)); + this.addComponent(new LambdaSpawn(this.spawns, code)); this.addComponent(new Grid(gridPosition)); @@ -134,115 +139,128 @@ export class LambdaFactory extends Entity { this.addComponent(text); } - private onHighlight(direction: Direction) { - if (direction === Direction.LEFT || direction === Direction.RIGHT) { - this.addComponent(new Interactable(() => this.spawnNewLambda(direction))); + private openCodeEditor() { + const modalContent = + "<div class='code'><div id='code'></div><br><p id='syntax-error' class='error'></p><button id='close-modal'>Save</button></div>"; + openModal(modalContent); + + const { code } = this.getComponent<LambdaSpawn>(ComponentNames.LambdaSpawn); + const startState = EditorState.create({ + doc: code, + extensions: [ + basicSetup, + keymap.of(defaultKeymap), + rainbowBrackets(), + highlightExtension, + FontSizeThemeExtension, + ], + }); + + const codeBox = document.getElementById("code")!; + const syntaxError = document.getElementById("syntax-error")!; + const canvas = document.getElementById( + Miscellaneous.CANVAS_ID, + ) as HTMLCanvasElement; + const closeButton = document.getElementById( + "close-modal", + ) as HTMLButtonElement; + closeButton.addEventListener("click", () => this.saveAndCloseCodeEditor()); + + const editorView = new EditorView({ + state: startState, + parent: codeBox, + }); + editorView.focus(); + + this.codeEditorState = { + view: editorView, + editorElement: codeBox, + syntaxError, + canvas, + closeButton, + }; + } + + private refreshCodeEditorText(text: string) { + if (!this.codeEditorState) { return; } + const { view } = this.codeEditorState; + + view.dispatch({ + changes: { + from: 0, + to: text.length, + insert: "", + }, + }); + view.dispatch({ + changes: { + from: 0, + to: 0, + insert: text, + }, + }); + } - let modalOpen = false; - let editorView: EditorView | null = null; + private saveAndCloseCodeEditor() { + if (!this.codeEditorState) { + return; + } - const syntaxErrorDecoration = Decoration.mark({ - class: "syntax-error", - }); + const { canvas, view, editorElement, syntaxError } = this.codeEditorState; + const text = view.state.doc.toString(); + this.refreshCodeEditorText(text); + syntaxError.innerText = ""; - const close = () => { - if (editorView) { - const text = editorView.state.doc.toString(); - - // remove all text from the editor - editorView.dispatch({ - changes: { - from: 0, - to: text.length, - insert: "", - }, - }); - // add the new text to the editor - editorView.dispatch({ - changes: { - from: 0, - to: 0, - insert: text, - }, - }); - - try { - parse(text); - } catch (e: any) { - if (!e.location) { - return; - } - const { - location: { - start: { offset: start }, - end: { offset: end }, - }, - } = e; - - editorView.dispatch({ - effects: highlightEffect.of([ - syntaxErrorDecoration.range( - start === end ? start - 1 : start, - end, - ), - ]), - }); - - document.getElementById("syntax-error")!.innerText = e.message; - - return; - } - - const spawner = this.getComponent<LambdaSpawn>( - ComponentNames.LambdaSpawn, - ); - spawner.code = text; - this.addComponent(spawner); + try { + parse(text); + } catch (e: any) { + if (!e.location) { + return; } + const { + location: { + start: { offset: start }, + end: { offset: end }, + }, + } = e; - modalOpen = false; - closeModal(); + view.dispatch({ + effects: highlightEffect.of([ + syntaxErrorDecoration.range(start === end ? start - 1 : start, end), + ]), + }); - document.getElementById(Miscellaneous.CANVAS_ID)!.focus(); + syntaxError.innerText = e.message; return; - }; + } + + const spawner = this.getComponent<LambdaSpawn>(ComponentNames.LambdaSpawn); + spawner.code = text; + this.addComponent(spawner); + + view.destroy(); + editorElement.innerHTML = ""; + this.codeEditorState = null; + closeModal(); + + canvas.focus(); + } + + private onHighlight(direction: Direction) { + if (direction === Direction.LEFT || direction === Direction.RIGHT) { + this.addComponent(new Interactable(() => this.spawnNewLambda(direction))); + return; + } const interaction = () => { - if (modalOpen) { - close(); + if (this.codeEditorState) { + this.saveAndCloseCodeEditor(); return; } - modalOpen = true; - - openModal( - "<div class='code'><div id='code'></div><br><p id='syntax-error' class='error'></p><button id='close-modal'>Save</button></div>", - ); - const spawner = this.getComponent<LambdaSpawn>( - ComponentNames.LambdaSpawn, - ); - - const startState = EditorState.create({ - doc: spawner.code, - extensions: [ - basicSetup, - keymap.of(defaultKeymap), - rainbowBrackets(), - highlightExtension, - FontSizeThemeExtension, - ], - }); - - const codeBox = document.getElementById("code")!; - editorView = new EditorView({ - state: startState, - parent: codeBox, - }); - - editorView.focus(); - document.getElementById("close-modal")!.addEventListener("click", close); + this.openCodeEditor(); }; this.addComponent(new Interactable(interaction)); |