refactor a bit
This commit is contained in:
parent
4fee37944d
commit
230916ceb1
12 changed files with 342 additions and 398 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { useContext } from "react";
|
||||
|
||||
import { getSymbol, getType, symbolFunction } from "dope2";
|
||||
import { getType } from "dope2";
|
||||
|
||||
import { CallBlock, type CallBlockState } from "./CallBlock";
|
||||
import { EnvContext } from "./EnvContext";
|
||||
|
|
@ -9,11 +9,11 @@ import { InputBlock, type InputBlockState } from "./InputBlock";
|
|||
import { LambdaBlock, type LambdaBlockState } from "./LambdaBlock";
|
||||
import { LetInBlock, type LetInBlockState } from "./LetInBlock";
|
||||
import { Type } from "./Type";
|
||||
import { initialEditorState } from "./configurations";
|
||||
import { evalEditorBlock, removeFocus, type ResolvedType } from "./eval";
|
||||
import { focusNextElement, focusPrevElement } from "./util/dom_trickery";
|
||||
import { evalEditorBlock, type ResolvedType } from "./eval";
|
||||
|
||||
import "./ExprBlock.css";
|
||||
import { Input } from "./Input";
|
||||
import { getActions } from "./actions";
|
||||
|
||||
export type ExprBlockState =
|
||||
InputBlockState
|
||||
|
|
@ -34,160 +34,57 @@ interface ExprBlockProps extends State2Props<ExprBlockState> {
|
|||
addParam: (e: ExprBlockState) => void;
|
||||
}
|
||||
|
||||
function getCommands(type) {
|
||||
const commands = ['e', 't', 'Enter', 'Backspace', 'ArrowLeft', 'ArrowRight', 'Tab', 'l', '=', '.'];
|
||||
if (getSymbol(type) === symbolFunction) {
|
||||
commands.push('c');
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
function getShortCommands(type) {
|
||||
if (getSymbol(type) === symbolFunction) {
|
||||
return 'c|Tab|.';
|
||||
}
|
||||
return 'Tab|.';
|
||||
}
|
||||
|
||||
export function ExprBlock({state, setState, suggestionPriority, onCancel, addParam}: ExprBlockProps) {
|
||||
const env = useContext(EnvContext);
|
||||
const [needCommand, setNeedCommand] = useState(false);
|
||||
const commandInputRef = useRef<HTMLInputElement>(null);
|
||||
useEffect(() => {
|
||||
if (needCommand) {
|
||||
commandInputRef.current?.focus();
|
||||
}
|
||||
}, [needCommand]);
|
||||
|
||||
const globalContext = useContext(GlobalContext);
|
||||
const onCommand = (e: React.KeyboardEvent) => {
|
||||
const commands = ['e', 't', 'Enter', 'Backspace', 'ArrowLeft', 'ArrowRight', 'Tab', 'l', 'L', '=', '.', 'c', 'a'];
|
||||
if (!commands.includes(e.key)) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
setNeedCommand(false);
|
||||
// u -> pass Up
|
||||
if (e.key === "e" || e.key === "Enter" || e.key === "Tab" && !e.shiftKey) {
|
||||
// onResolve(state);
|
||||
globalContext?.doHighlight.eval();
|
||||
return;
|
||||
}
|
||||
if (e.key === "Tab" && e.shiftKey) {
|
||||
setNeedCommand(false);
|
||||
focusPrevElement();
|
||||
}
|
||||
// c -> Call
|
||||
if (e.key === "c") {
|
||||
// we become CallBlock
|
||||
setState(state => ({
|
||||
kind: "call",
|
||||
fn: removeFocus(state),
|
||||
input: initialEditorState,
|
||||
}));
|
||||
globalContext?.doHighlight.call();
|
||||
// focusNextElement();
|
||||
return;
|
||||
}
|
||||
// t -> Transform
|
||||
if (e.key === "t" || e.key === ".") {
|
||||
// we become CallBlock
|
||||
setState(state => ({
|
||||
kind: "call",
|
||||
fn: initialEditorState,
|
||||
input: removeFocus(state),
|
||||
}));
|
||||
globalContext?.doHighlight.transform();
|
||||
return;
|
||||
}
|
||||
if (e.key === "Backspace" || e.key === "ArrowLeft") {
|
||||
focusPrevElement();
|
||||
return;
|
||||
}
|
||||
if (e.key === "ArrowRight") {
|
||||
focusNextElement();
|
||||
return;
|
||||
}
|
||||
// l -> Let ... in ...
|
||||
// = -> assign to name
|
||||
if (e.key === 'l' || e.key === '=' && !e.shiftKey) {
|
||||
// we become LetInBlock
|
||||
setState(state => ({
|
||||
kind: "let",
|
||||
name: "",
|
||||
focus: true,
|
||||
value: removeFocus(state),
|
||||
inner: removeFocus(initialEditorState),
|
||||
}));
|
||||
globalContext?.doHighlight.let();
|
||||
return;
|
||||
}
|
||||
if (e.key === 'L' || e.key === '=' && e.shiftKey) {
|
||||
setState(state => ({
|
||||
kind: "let",
|
||||
name: "",
|
||||
focus: true,
|
||||
value: removeFocus(initialEditorState),
|
||||
inner: removeFocus(state),
|
||||
}));
|
||||
}
|
||||
// a -> lAmbdA
|
||||
if (e.key === "a") {
|
||||
setState(state => ({
|
||||
kind: "lambda",
|
||||
paramName: "",
|
||||
focus: true,
|
||||
expr: removeFocus(state),
|
||||
}));
|
||||
globalContext?.doHighlight.lambda();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const renderBlock = () => {
|
||||
switch (state.kind) {
|
||||
case "input":
|
||||
return <InputBlock
|
||||
state={state}
|
||||
setState={setState as (callback:(p:InputBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
onCancel={onCancel}
|
||||
addParam={addParam}
|
||||
/>;
|
||||
case "call":
|
||||
return <CallBlock
|
||||
state={state}
|
||||
setState={setState as (callback:(p:CallBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
/>;
|
||||
case "let":
|
||||
return <LetInBlock
|
||||
state={state}
|
||||
setState={setState as (callback:(p:LetInBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
addParam={addParam}
|
||||
/>;
|
||||
case "lambda":
|
||||
return <LambdaBlock
|
||||
state={state}
|
||||
setState={setState as (callback:(p:LambdaBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
addParam={addParam}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
const renderBlock = {
|
||||
input: () => <InputBlock
|
||||
state={state as InputBlockState}
|
||||
setState={setState as (callback:(p:InputBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
onCancel={onCancel}
|
||||
addParam={addParam}
|
||||
/>,
|
||||
call: () => <CallBlock
|
||||
state={state as CallBlockState}
|
||||
setState={setState as (callback:(p:CallBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
/>,
|
||||
let: () => <LetInBlock
|
||||
state={state as LetInBlockState}
|
||||
setState={setState as (callback:(p:LetInBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
addParam={addParam}
|
||||
/>,
|
||||
lambda: () => <LambdaBlock
|
||||
state={state as LambdaBlockState}
|
||||
setState={setState as (callback:(p:LambdaBlockState)=>ExprBlockState)=>void}
|
||||
suggestionPriority={suggestionPriority}
|
||||
addParam={addParam}
|
||||
/>,
|
||||
};
|
||||
|
||||
const [resolved] = evalEditorBlock(state, env);
|
||||
const actions = getActions(globalContext, setState);
|
||||
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
||||
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
||||
|
||||
return <span className={"editor" + ((resolved.kind!=="value") ? " "+resolved.kind : "")}>
|
||||
{renderBlock()}
|
||||
{renderBlock[state.kind]()}
|
||||
<div className="typeSignature">
|
||||
:: <Type type={getType(resolved)} />
|
||||
</div>
|
||||
<input
|
||||
ref={commandInputRef}
|
||||
spellCheck={false}
|
||||
className="editable commandInput"
|
||||
placeholder={`<c>`}
|
||||
onKeyDown={onCommand}
|
||||
value={""}
|
||||
onChange={() => {}} />
|
||||
<Input
|
||||
placeholder="<c>"
|
||||
text=""
|
||||
suggestion=""
|
||||
focus={false}
|
||||
onEnter={() => {}}
|
||||
onCancel={onCancel}
|
||||
onTextChange={() => {}}
|
||||
setFocus={() => {}}
|
||||
extraHandlers={extraHandlers}
|
||||
/>
|
||||
</span>;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue