move the parsing from VisualEditor to App component
This commit is contained in:
parent
65b6a343d1
commit
4f9a546fd1
11 changed files with 107 additions and 116 deletions
|
|
@ -1,8 +1,7 @@
|
|||
import { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { emptyStatechart, Statechart, Transition } from "../statecharts/abstract_syntax";
|
||||
import { handleInputEvent, initialize, RuntimeError } from "../statecharts/interpreter";
|
||||
import { BigStep, BigStepOutput, RT_Event } from "../statecharts/runtime_types";
|
||||
import { BigStep, RT_Event } from "../statecharts/runtime_types";
|
||||
import { InsertMode, VisualEditor, VisualEditorState } from "../VisualEditor/VisualEditor";
|
||||
import { getSimTime, getWallClkDelay, TimeMode } from "../statecharts/time";
|
||||
|
||||
|
|
@ -13,7 +12,7 @@ import Stack from "@mui/material/Stack";
|
|||
import Box from "@mui/material/Box";
|
||||
import { TopPanel } from "./TopPanel";
|
||||
import { ShowAST, ShowInputEvents, ShowInternalEvents, ShowOutputEvents } from "./ShowAST";
|
||||
import { TraceableError } from "../statecharts/parser";
|
||||
import { parseStatechart } from "../statecharts/parser";
|
||||
import { getKeyHandler } from "./shortcut_handler";
|
||||
import { BottomPanel } from "./BottomPanel";
|
||||
import { emptyState } from "@/statecharts/concrete_syntax";
|
||||
|
|
@ -23,6 +22,7 @@ import { DummyPlant } from "@/Plant/Dummy/Dummy";
|
|||
import { Plant } from "@/Plant/Plant";
|
||||
import { usePersistentState } from "@/util/persistent_state";
|
||||
import { RTHistory } from "./RTHistory";
|
||||
import { detectConnections } from "@/statecharts/detect_connections";
|
||||
|
||||
export type EditHistory = {
|
||||
current: VisualEditorState,
|
||||
|
|
@ -70,10 +70,8 @@ function getPlantState<T>(plant: Plant<T>, trace: TraceItem[], idx: number): T |
|
|||
}
|
||||
|
||||
export function App() {
|
||||
const [mode, setMode] = useState<InsertMode>("and");
|
||||
const [insertMode, setInsertMode] = useState<InsertMode>("and");
|
||||
const [historyState, setHistoryState] = useState<EditHistory>({current: emptyState, history: [], future: []});
|
||||
const [ast, setAST] = useState<Statechart>(emptyStatechart);
|
||||
const [errors, setErrors] = useState<TraceableError[]>([]);
|
||||
const [trace, setTrace] = useState<TraceState|null>(null);
|
||||
const [time, setTime] = useState<TimeMode>({kind: "paused", simtime: 0});
|
||||
const [modal, setModal] = useState<ReactElement|null>(null);
|
||||
|
|
@ -91,6 +89,10 @@ export function App() {
|
|||
|
||||
const refRightSideBar = useRef<HTMLDivElement>(null);
|
||||
|
||||
// parse concrete syntax always:
|
||||
const conns = useMemo(() => detectConnections(editorState), [editorState]);
|
||||
const [ast, syntaxErrors] = useMemo(() => parseStatechart(editorState, conns), [editorState, conns]);
|
||||
|
||||
// append editor state to undo history
|
||||
const makeCheckPoint = useCallback(() => {
|
||||
setHistoryState(historyState => ({
|
||||
|
|
@ -261,7 +263,7 @@ export function App() {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const onKeyDown = getKeyHandler(setMode);
|
||||
const onKeyDown = getKeyHandler(setInsertMode);
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", onKeyDown);
|
||||
|
|
@ -322,12 +324,12 @@ export function App() {
|
|||
}}
|
||||
>
|
||||
<TopPanel
|
||||
{...{trace, ast, time, setTime, onUndo, onRedo, onInit, onClear, onRaise, onBack, mode, setMode, setModal, zoom, setZoom, showKeys, setShowKeys, history: historyState}}
|
||||
{...{trace, ast, time, setTime, onUndo, onRedo, onInit, onClear, onRaise, onBack, insertMode, setInsertMode, setModal, zoom, setZoom, showKeys, setShowKeys, history: historyState}}
|
||||
/>
|
||||
</Box>
|
||||
{/* Below the top bar: Editor */}
|
||||
<Box sx={{flexGrow:1, overflow: "auto"}}>
|
||||
<VisualEditor {...{state: editorState, setState: setEditorState, ast, setAST, trace, setTrace, errors, setErrors, mode, highlightActive, highlightTransitions, setModal, makeCheckPoint, zoom}}/>
|
||||
<VisualEditor {...{state: editorState, setState: setEditorState, conns, trace, setTrace, syntaxErrors, insertMode, highlightActive, highlightTransitions, setModal, makeCheckPoint, zoom}}/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
|
@ -408,7 +410,7 @@ export function App() {
|
|||
|
||||
{/* Bottom panel */}
|
||||
<Box sx={{flex: '0 0 content'}}>
|
||||
<BottomPanel {...{errors}}/>
|
||||
<BottomPanel {...{errors: syntaxErrors}}/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</>;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Dispatch, Ref, SetStateAction } from "react";
|
||||
import { Dispatch, memo, Ref, SetStateAction, useCallback } from "react";
|
||||
import { Statechart, stateDescription } from "../statecharts/abstract_syntax";
|
||||
import { BigStep, Environment, Mode, RaisedEvent, RT_Event } from "../statecharts/runtime_types";
|
||||
import { formatTime } from "./util";
|
||||
import { TimeMode } from "../statecharts/time";
|
||||
import { TraceState } from "./App";
|
||||
import { TraceItem, TraceState } from "./App";
|
||||
|
||||
type RTHistoryProps = {
|
||||
trace: TraceState|null,
|
||||
|
|
@ -13,52 +13,55 @@ type RTHistoryProps = {
|
|||
}
|
||||
|
||||
export function RTHistory({trace, setTrace, ast, setTime}: RTHistoryProps) {
|
||||
function gotoRt(idx: number, timestamp: number) {
|
||||
const onMouseDown = useCallback((idx: number, timestamp: number) => {
|
||||
setTrace(trace => trace && {
|
||||
...trace,
|
||||
idx,
|
||||
});
|
||||
setTime({kind: "paused", simtime: timestamp});
|
||||
}
|
||||
}, [setTrace, setTime]);
|
||||
|
||||
if (trace === null) {
|
||||
return <></>;
|
||||
}
|
||||
return <div>
|
||||
{trace.trace.map((item, i) => {
|
||||
if (item.kind === "bigstep") {
|
||||
const newStates = item.mode.difference(trace.trace[i-1]?.mode || new Set());
|
||||
return <div
|
||||
className={"runtimeState" + (i === trace.idx ? " active" : "")}
|
||||
onMouseDown={() => gotoRt(i, item.simtime)}>
|
||||
<div>
|
||||
{formatTime(item.simtime)}
|
||||
 
|
||||
<div className="inputEvent">{item.inputEvent || "<init>"}</div>
|
||||
</div>
|
||||
<ShowMode mode={newStates} statechart={ast}/>
|
||||
<ShowEnvironment environment={item.environment}/>
|
||||
{item.outputEvents.length>0 && <>^
|
||||
{item.outputEvents.map((e:RaisedEvent) => <span className="outputEvent">{e.name}</span>)}
|
||||
</>}
|
||||
</div>;
|
||||
}
|
||||
else {
|
||||
return <div className="runtimeState runtimeError">
|
||||
<div>
|
||||
{formatTime(item.simtime)}
|
||||
 
|
||||
<div className="inputEvent">{item.inputEvent}</div>
|
||||
</div>
|
||||
<div>
|
||||
{item.error.message}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
})}
|
||||
{trace.trace.map((item, i) => <RTHistoryItem ast={ast} idx={i} item={item} prevItem={trace.trace[i-1]} active={i === trace.idx} onMouseDown={onMouseDown}/>)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export const RTHistoryItem = memo(function RTHistoryItem({ast, idx, item, prevItem, active, onMouseDown}: {idx: number, ast: Statechart, item: TraceItem, prevItem?: TraceItem, active: boolean, onMouseDown: (idx: number, timestamp: number) => void}) {
|
||||
if (item.kind === "bigstep") {
|
||||
// @ts-ignore
|
||||
const newStates = item.mode.difference(prevItem?.mode || new Set());
|
||||
return <div
|
||||
className={"runtimeState" + (active ? " active" : "")}
|
||||
onMouseDown={useCallback(() => onMouseDown(idx, item.simtime), [idx, item.simtime])}>
|
||||
<div>
|
||||
{formatTime(item.simtime)}
|
||||
 
|
||||
<div className="inputEvent">{item.inputEvent || "<init>"}</div>
|
||||
</div>
|
||||
<ShowMode mode={newStates} statechart={ast}/>
|
||||
<ShowEnvironment environment={item.environment}/>
|
||||
{item.outputEvents.length>0 && <>^
|
||||
{item.outputEvents.map((e:RaisedEvent) => <span className="outputEvent">{e.name}</span>)}
|
||||
</>}
|
||||
</div>;
|
||||
}
|
||||
else {
|
||||
return <div className="runtimeState runtimeError">
|
||||
<div>
|
||||
{formatTime(item.simtime)}
|
||||
 
|
||||
<div className="inputEvent">{item.inputEvent}</div>
|
||||
</div>
|
||||
<div>
|
||||
{item.error.message}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function ShowEnvironment(props: {environment: Environment}) {
|
||||
return <div>{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export function ShowAction(props: {action: Action}) {
|
|||
}
|
||||
}
|
||||
|
||||
export const ShowAST = memo(function ShowAST(props: {root: ConcreteState | PseudoState, transitions: Map<string, Transition[]>, trace: TraceState | null, highlightActive: Set<string>}) {
|
||||
export const ShowAST = memo(function ShowASTx(props: {root: ConcreteState | PseudoState}) {
|
||||
const description = stateDescription(props.root);
|
||||
// const outgoing = props.transitions.get(props.root.uid) || [];
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ export const ShowAST = memo(function ShowAST(props: {root: ConcreteState | Pseud
|
|||
{props.root.kind !== "pseudo" && props.root.children.length>0 &&
|
||||
<ul>
|
||||
{props.root.children.map(child =>
|
||||
<ShowAST key={child.uid} root={child} transitions={props.transitions} trace={props.trace} highlightActive={props.highlightActive} />
|
||||
<ShowAST key={child.uid} root={child} />
|
||||
)}
|
||||
</ul>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ export type TopPanelProps = {
|
|||
// onRaise: (e: string, p: any) => void,
|
||||
onBack: () => void,
|
||||
// ast: Statechart,
|
||||
mode: InsertMode,
|
||||
setMode: Dispatch<SetStateAction<InsertMode>>,
|
||||
insertMode: InsertMode,
|
||||
setInsertMode: Dispatch<SetStateAction<InsertMode>>,
|
||||
setModal: Dispatch<SetStateAction<ReactElement|null>>,
|
||||
zoom: number,
|
||||
setZoom: Dispatch<SetStateAction<number>>,
|
||||
|
|
@ -56,7 +56,7 @@ const insertModes: [InsertMode, string, ReactElement, ReactElement][] = [
|
|||
["text", "text", <> T </>, <kbd>X</kbd>],
|
||||
];
|
||||
|
||||
export const TopPanel = memo(function TopPanel({trace, time, setTime, onUndo, onRedo, onInit, onClear, onBack, mode, setMode, setModal, zoom, setZoom, showKeys, setShowKeys, history}: TopPanelProps) {
|
||||
export const TopPanel = memo(function TopPanel({trace, time, setTime, onUndo, onRedo, onInit, onClear, onBack, insertMode, setInsertMode, setModal, zoom, setZoom, showKeys, setShowKeys, history}: TopPanelProps) {
|
||||
const [displayTime, setDisplayTime] = useState("0.000");
|
||||
const [timescale, setTimescale] = useState(1);
|
||||
|
||||
|
|
@ -226,9 +226,9 @@ export const TopPanel = memo(function TopPanel({trace, time, setTime, onUndo, on
|
|||
<KeyInfo key={m} keyInfo={keyInfo}>
|
||||
<button
|
||||
title={"insert "+hint}
|
||||
disabled={mode===m}
|
||||
className={mode===m ? "active":""}
|
||||
onClick={() => setMode(m)}
|
||||
disabled={insertMode===m}
|
||||
className={insertMode===m ? "active":""}
|
||||
onClick={() => setInsertMode(m)}
|
||||
>{buttonTxt}</button></KeyInfo>)}
|
||||
 
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue