scrowl/src/ui/Digith/Function/NewFunctionDraftDigith.tsx
2026-04-06 20:34:20 +02:00

125 lines
3.8 KiB
TypeScript

import { createSignal } from "solid-js";
import { Digith } from "src/ui/Digith";
import { useProgram } from "src/ui/ProgramProvider";
import { CodeEditor } from "src/ui/Component/CodeEditor";
import { sourceText } from "source-region";
import { Program } from "src/lang/program";
import { V, Validation, letValidate } from "src/ui/validation";
import { validateExprRaw, validateNameRaw, validateParamsRaw } from "src/ui/validation/helpers";
import { spawnFunctionDigith } from "src/ui/Scrowl/scrowlStore";
import { DigithError } from "src/ui/Digith/DigithError";
type Input = {
raw_name: string,
raw_params: string,
raw_body: string,
}
const validator: Validation<Input, Program.CreateFunction, DigithError> = letValidate(
(input) =>({
name: V.elseErr(validateNameRaw(input.raw_name), err =>({
payload: { tag: "Parse", err, src: sourceText(input.raw_name).fullRegion() },
ids: ["name"],
tags: ["footer"],
config: { title: "Function Name", display: "flat" },
})),
parameters: V.elseErr(validateParamsRaw(input.raw_params), err => ({
payload: { tag: "Parse", err, src: sourceText(input.raw_params).fullRegion() },
ids: ["params"],
tags: ["footer"],
config: { title: "Parameters", display: "flat" },
})),
body: V.elseErr(validateExprRaw(input.raw_body), err => ({
payload: { tag: "Parse", err, src: sourceText(input.raw_body).fullRegion() },
ids: ["body"],
tags: ["footer"],
config: { title: "Function Body", display: "flat" },
})),
}),
(fields, input) => {
const createFunction: Program.CreateFunction = {
name: fields.name,
parameters: fields.parameters,
body: fields.body,
raw_parameters: input.raw_params,
raw_body: input.raw_body,
};
return V.ok(createFunction);
})
export function NewFunctionDraftDigith(props: { draft: Digith.NewFunctionDraft }) {
const program = useProgram();
const [name, setName] = createSignal(props.draft.raw_name);
const [params, setParams] = createSignal(props.draft.raw_parameters);
const [body, setBody] = createSignal(props.draft.raw_body);
const [errors, setErrors] = createSignal<DigithError[]>([]);
function handleCommit() {
setErrors([]);
const validRes = validator({ raw_name: name(), raw_params: params(), raw_body: body() });
if (validRes.tag === "errors") {
setErrors(validRes.errors);
return;
}
const createFunction = validRes.value;
const programRes = Program.registerFunction(program, createFunction);
if (programRes.tag === "error") {
setErrors([{
payload: { tag: "Program", err: programRes.error },
ids: ["program"],
tags: ["footer"],
config: { title: "Registration Failed" },
}]);
return;
}
const fnName = programRes.value;
spawnFunctionDigith(program, fnName, props.draft.id);
};
return (
<article>
<header><strong>Fn (Draft)</strong></header>
<div class="grid">
<label>
Name
<input
type="text"
placeholder="my_func"
value={name()}
onInput={(e) => setName(e.currentTarget.value)}
/>
</label>
<label>
Parameters (comma separated)
<input
type="text"
placeholder="x, y"
value={params()}
onInput={(e) => setParams(e.currentTarget.value)}
/>
</label>
</div>
<label>Body</label>
<CodeEditor
value={body()}
onUpdate={setBody}
onRun={handleCommit}
/>
<footer>
<button class="primary" onClick={handleCommit}>Commit</button>
</footer>
<div style={{ "margin-top": "1rem" }}>
<DigithError.ByTag errors={errors()} tag="footer" />
</div>
</article>
);
}