summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-04 17:06:57 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-04 17:06:57 -0700
commit8288d086480d88ac4237f19c194d5829157bac38 (patch)
tree2e5fdc5e9367dcfad7db2df6c444d1d92fd26262
parentccc1e182cf72916c9cdc4f10043048aa01a63390 (diff)
downloadthe-abstraction-engine-8288d086480d88ac4237f19c194d5829157bac38.tar.gz
the-abstraction-engine-8288d086480d88ac4237f19c194d5829157bac38.zip
working lambda editor
-rw-r--r--src/css/editor.css2
-rw-r--r--src/css/modal.css2
-rw-r--r--src/css/style.css11
-rw-r--r--src/engine/entities/LambdaFactory.ts216
4 files changed, 120 insertions, 111 deletions
diff --git a/src/css/editor.css b/src/css/editor.css
index 9b1588e..8ce5a81 100644
--- a/src/css/editor.css
+++ b/src/css/editor.css
@@ -2,7 +2,7 @@
.code {
width: 100%;
- font-size: 1.5rem;
+ font-size: 1.25rem;
}
.syntax-error {
diff --git a/src/css/modal.css b/src/css/modal.css
index c10070e..802dc4d 100644
--- a/src/css/modal.css
+++ b/src/css/modal.css
@@ -22,7 +22,7 @@
margin: auto;
padding: 20px;
border: 1px solid var(--yellow);
- width: 40%;
+ width: 60%;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
animation: scaleUp 0.25s;
border-radius: 8px;
diff --git a/src/css/style.css b/src/css/style.css
index c14682b..35fdc31 100644
--- a/src/css/style.css
+++ b/src/css/style.css
@@ -1,6 +1,7 @@
@import url("./theme.css");
@import url("./tf.css");
@import url("./modal.css");
+@import url("./editor.css");
@font-face {
font-family: "scientifica";
@@ -95,10 +96,6 @@ a:visited {
margin: 0;
}
-.code {
- width: 100%;
-}
-
button {
padding: 0.5rem;
border: none;
@@ -108,12 +105,6 @@ button {
cursor: pointer;
transition: background 0.2s ease-in-out;
}
-
button:hover {
background-color: var(--blue);
}
-
-.syntax-error {
- color: var(--red);
- background-color: var(--yellow);
-}
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));