Add interval setter UI

This commit is contained in:
Nilay Majorwar 2021-12-16 21:37:53 +05:30
parent 7d9fb457ff
commit c9346da331
2 changed files with 64 additions and 15 deletions

View File

@ -3,7 +3,11 @@ import { CodeEditor, CodeEditorRef } from "../ui/code-editor";
import { InputEditor, InputEditorRef } from "../ui/input-editor";
import { MainLayout } from "../ui/MainLayout";
import { useExecController } from "../ui/use-exec-controller";
import { DocumentRange, LanguageProvider } from "../engines/types";
import {
DocumentRange,
LanguageProvider,
StepExecutionResult,
} from "../engines/types";
import BrainfuckProvider from "../engines/brainfuck";
import { OutputViewer } from "../ui/output-viewer";
import { ExecutionControls } from "./execution-controls";
@ -15,12 +19,20 @@ export const Mainframe = () => {
const execController = useExecController();
// UI states used in execution time
const [execInterval, setExecInterval] = React.useState(20);
const [rendererState, setRendererState] = React.useState<any>(null);
const [output, setOutput] = React.useState<string | null>(null);
const [codeHighlights, setCodeHighlights] = React.useState<
DocumentRange | undefined
>();
/** Utility that updates UI with the provided execution result */
const updateWithResult = (result: StepExecutionResult<any>) => {
setRendererState(result.rendererState);
setCodeHighlights(result.nextStepLocation || undefined);
setOutput((o) => (o || "") + (result.output || ""));
};
/** Reset and begin a new execution */
const runProgram = async () => {
// Check if controller is free for execution
@ -40,11 +52,7 @@ export const Mainframe = () => {
);
// Begin execution
await execController.execute((result) => {
setRendererState(result.rendererState);
setCodeHighlights(result.nextStepLocation || undefined);
setOutput((o) => (o || "") + (result.output || ""));
}, 40);
await execController.execute(updateWithResult, execInterval);
};
/** Pause the ongoing execution */
@ -67,9 +75,7 @@ export const Mainframe = () => {
// Run and update execution states
const result = await execController.executeStep();
setRendererState(result.rendererState);
setCodeHighlights(result.nextStepLocation || undefined);
setOutput((o) => (o || "") + (result.output || ""));
updateWithResult(result);
};
/** Resume the currently paused execution */
@ -81,11 +87,7 @@ export const Mainframe = () => {
}
// Begin execution
await execController.execute((result) => {
setRendererState(result.rendererState);
setCodeHighlights(result.nextStepLocation || undefined);
setOutput((o) => (o || "") + (result.output || ""));
}, 40);
await execController.execute(updateWithResult, execInterval);
};
/** Stop the currently active execution */
@ -142,6 +144,7 @@ export const Mainframe = () => {
onResume={resumeExecution}
onStep={executeStep}
onStop={stopExecution}
onChangeInterval={setExecInterval}
/>
)}
/>

View File

@ -1,11 +1,52 @@
import { Button, ButtonGroup, Icon } from "@blueprintjs/core";
import {
Button,
ButtonGroup,
Icon,
NumericInput,
Tag,
} from "@blueprintjs/core";
const styles = {
container: {
display: "flex",
alignItems: "center",
paddingRight: 5,
marginRight: -15,
},
inputWrapper: {
/**
* As of Dec'21, NumericInput doesn't have `small` prop yet,
* so we instead use `transform` to hack up a smaller input.
*/
transform: "scale(0.8)",
},
input: {
width: 125,
},
};
/** Input field for changing execution interval */
const IntervalInput = (props: {
disabled: boolean;
onChange: (v: number) => void;
}) => {
return (
<div style={styles.inputWrapper}>
<NumericInput
min={20}
defaultValue={20}
stepSize={10}
minorStepSize={null}
leftIcon="time"
clampValueOnBlur
style={styles.input}
disabled={props.disabled}
onValueChange={(v) => props.onChange(v)}
rightElement={<Tag minimal>ms</Tag>}
allowNumericCharactersOnly
/>
</div>
);
};
/** Button for starting code execution */
@ -59,6 +100,7 @@ type Props = {
onResume: () => void;
onStep: () => void;
onStop: () => void;
onChangeInterval: (value: number) => void;
};
export const ExecutionControls = (props: Props) => {
@ -75,6 +117,10 @@ export const ExecutionControls = (props: Props) => {
onStop={props.onStop}
/>
)}
<IntervalInput
disabled={props.state === "running"}
onChange={props.onChangeInterval}
/>
</div>
);
};