{(digith) => (
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
)}
@@ -52,3 +50,31 @@ export function Scrowl(props: Props) {
);
}
+// For focusing on a Digith
+// This works basically in two ways:
+// - We have the list of digiths, and each time any of them is mounted, there's `attemptScroll` check done on all of them.
+// - Whenever `scrowl.focusTarget` changes, it reactively broadcasts the change to each of the digith,
+// and each digith asks itself, "Am I focus-target?".
+function DigithWrapper(props: { id: DigithId, children: any }) {
+ let ref: HTMLDivElement | undefined;
+
+ // The Logic: Run this whenever 'scrowl.focusTarget' changes OR when this component mounts
+ const attemptScroll = () => {
+ if (scrowl.focusTarget === props.id && ref) {
+ ref.scrollIntoView({ behavior: "smooth", block: "start" });
+ setTimeout(clearFocus, 0); // This sets asynchronously the focus-target to null.
+ }
+ };
+
+ onMount(attemptScroll);
+ createEffect(attemptScroll);
+
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/src/ui/Sidebar.tsx b/src/ui/Sidebar.tsx
new file mode 100644
index 0000000..996f852
--- /dev/null
+++ b/src/ui/Sidebar.tsx
@@ -0,0 +1,19 @@
+import { Controls } from "./Controls";
+import { ProgramMeta } from "./ProgramMeta";
+
+export function Sidebar() {
+ return (
+
+ );
+}
diff --git a/src/ui/scrowlStore.ts b/src/ui/scrowlStore.ts
index 9f9d8d6..4c7756d 100644
--- a/src/ui/scrowlStore.ts
+++ b/src/ui/scrowlStore.ts
@@ -1,21 +1,114 @@
import { createStore } from "solid-js/store";
import { Digith } from "./Digith";
+import { Program } from "src/lang/program";
+import { FunctionName } from "src/lang/expr";
+
+export type DigithId = number;
export type Scrowl = {
- digiths: Digith[];
+ digiths: Digith[],
+ nextId: DigithId,
+ focusTarget: DigithId | null, // 99.99999% of time this is null, but it flickers briefly - and on that flicker focus can happen.
+}
+
+export namespace Scrowl {
+ export type Error =
+ | Program.Error
+
+ export type Result
=
+ | { tag: "ok", value: T }
+ | { tag: "error", error: Error }
+
+ export namespace Result {
+ export function ok(value: T): Result { return { tag: "ok", value } }
+ export function error(error: Error): Result { return { tag: "error", error } }
+ }
+
}
export const [scrowl, setScrowl] = createStore({
- digiths: [{ tag: 'repl' }]
+ digiths: [{ tag: 'repl', id: 0 }],
+ nextId: 1,
+ focusTarget: null,
});
-export function spawnFunctionDraft() {
+function prependDigith(newDigith: Digith) {
+ setScrowl("digiths", (prev) => [newDigith, ...prev]);
+}
+
+export function updateDigith(targetId: DigithId, newDigith: Digith) {
+ setScrowl("digiths", (items) =>
+ items.map((item) => item.id === targetId ? newDigith : item)
+ );
+}
+
+export function closeDigith(targetId: DigithId) {
+ setScrowl("digiths", (prev) => prev.filter((d) => d.id !== targetId));
+}
+
+export function closeAllDigiths() {
+ setScrowl("digiths", []);
+}
+
+export function requestFocus(id: DigithId) {
+ setScrowl("focusTarget", id);
+}
+
+export function clearFocus() {
+ setScrowl("focusTarget", null);
+}
+
+function generateId(): DigithId {
+ const id = scrowl.nextId;
+ setScrowl("nextId", (prev) => prev + 1);
+ return id;
+}
+
+export function spawnNewFunctionDraftDigith() {
+ const id = generateId();
+
const newDraft: Digith = {
+ id,
tag: 'new-fn-draft',
raw_name: '',
raw_parameters: '',
raw_body: '',
};
+
+ requestFocus(id);
setScrowl("digiths", (prev) => [newDraft, ...prev]);
};
+export function spawnFunctionDigith(program: Program, name: FunctionName, targetId?: DigithId): Scrowl.Result {
+ const lookupRes = Program.getFunction(program, name);
+ if (lookupRes.tag === "error") {
+ return Scrowl.Result.error(lookupRes.error);
+ }
+ const fnDef = lookupRes.value;
+
+ // TODO: Maybe consider representing some read-only Digith for primitive (it would just display the name, it wouldn't have code).
+ if (fnDef.tag === "primitive") {
+ return Scrowl.Result.error({ tag: "CannotEditPrimitiveFunction", name });
+ }
+ const userDef = fnDef.def;
+ const id = targetId ?? generateId();
+
+ const newDigith: Digith.Function = {
+ id: id,
+ tag: "fn",
+
+ name: userDef.name,
+ raw_parameters: userDef.raw_parameters,
+ raw_body: userDef.raw_body,
+ };
+
+ if (targetId === undefined) {
+ prependDigith(newDigith);
+ } else {
+ // Swap with old function draft.
+ updateDigith(targetId, newDigith);
+ }
+
+ return Scrowl.Result.ok(newDigith);
+}
+