import { getSymbol, getType, module2Env, ModuleStd, symbolFunction } from "dope2"; import { InputBlock, type InputBlockState } from "./InputBlock"; import { type Dynamic, type State2Props } from "./util/extra"; import { CallBlock, type CallBlockState } from "./CallBlock"; import { useEffect, useState } from "react"; import { Type } from "./Type"; import "./Editor.css" import { focusNextElement, focusPrevElement } from "./util/dom_trickery"; interface LetInBlockState { kind: "let"; env: any; name: string; value: EditorState; inner: EditorState; resolved: undefined | Dynamic; rollback?: EditorState; } interface LambdaBlockState { kind: "lambda"; env: any; paramName: string; expr: EditorState; resolved: undefined | Dynamic; rollback?: EditorState; } export type EditorState = InputBlockState | CallBlockState | LetInBlockState | LambdaBlockState; export const initialEditorState: EditorState = { kind: "input", env: module2Env(ModuleStd), text: "", resolved: undefined, rollback: undefined, }; interface EditorProps extends State2Props { onResolve: (state: EditorState) => void; onCancel: () => void; } const dontFilter = () => true; function getCommands(type) { const commands = ['u', 't', 'Enter', 'Backspace', 'ArrowLeft', 'Tab']; if (getSymbol(type) === symbolFunction) { commands.push('c'); } return commands; } export function Editor({state, setState, onResolve, onCancel}: EditorProps) { const [needCommand, setNeedCommand] = useState(false); const onMyResolve = (editorState: EditorState) => { setState(editorState); if (editorState.resolved) { setNeedCommand(true); } else { // unresolved setNeedCommand(false); onResolve(editorState); // pass up the fact that we're unresolved } } // const onMyCancel const onCommand = (e: React.KeyboardEvent) => { const type = getType(state.resolved); const commands = getCommands(type); if (!commands.includes(e.key)) { return; } e.preventDefault(); setNeedCommand(false); // u -> pass Up if (e.key === "u" || e.key === "Enter" || e.key === "Tab") { onResolve(state); return; } // c -> Call if (e.key === "c") { // we become CallBlock setState({ kind: "call", env: state.env, fn: state, input: initialEditorState, resolved: undefined, rollback: state, }); return; } // t -> Transform if (e.key === "t") { // we become CallBlock setState({ kind: "call", env: state.env, fn: initialEditorState, input: state, resolved: undefined, rollback: state, }); return; } if (e.key === "Backspace" || e.key === "ArrowLeft") { focusPrevElement(); return; } }; const renderBlock = () => { switch (state.kind) { case "input": return ; case "call": return ; case "let": return <>; case "lambda": return <>; } } return <> {renderBlock()} { (state.resolved) ?
:: { (needCommand) ? : <> }
: <> } ; }