Refactor to make language selection dynamic

This commit is contained in:
Nilay Majorwar
2021-12-18 17:15:22 +05:30
parent 2322ebe55d
commit bb9e85f422
9 changed files with 172 additions and 111 deletions

View File

@ -4,11 +4,15 @@ import { InputEditor, InputEditorRef } from "../ui/input-editor";
import { MainLayout } from "../ui/MainLayout";
import { useExecController } from "../ui/use-exec-controller";
import { LanguageProvider, StepExecutionResult } from "../engines/types";
import BrainfuckProvider from "../engines/brainfuck";
import { OutputViewer, OutputViewerRef } from "../ui/output-viewer";
import { ExecutionControls } from "./execution-controls";
import { RendererRef, RendererWrapper } from "./renderer-wrapper";
type Props<RS> = {
langName: string;
provider: LanguageProvider<RS>;
};
/**
* React component that contains and controls the entire IDE.
*
@ -17,10 +21,10 @@ import { RendererRef, RendererWrapper } from "./renderer-wrapper";
* small execution intervals if rendered on every execution. All state management
* is delegated to imperatively controlled child components.
*/
export const Mainframe = () => {
export const Mainframe = <RS extends {}>({ langName, provider }: Props<RS>) => {
// Language provider and engine
const providerRef = React.useRef<LanguageProvider<any>>(BrainfuckProvider);
const execController = useExecController();
const providerRef = React.useRef(provider);
const execController = useExecController(langName);
// Refs for controlling UI components
const codeEditorRef = React.useRef<CodeEditorRef>(null);
@ -137,7 +141,7 @@ export const Mainframe = () => {
renderRenderer={() => (
<RendererWrapper
ref={rendererRef}
renderer={providerRef.current.Renderer}
renderer={providerRef.current.Renderer as any}
/>
)}
renderInput={() => <InputEditor ref={inputEditorRef} />}

View File

@ -21,7 +21,7 @@ type WorkerState =
* Also abstracts away the details of message-passing and exposes
* an imperative API to the parent component.
*/
export const useExecController = <RS>() => {
export const useExecController = <RS>(langName: string) => {
const workerRef = React.useRef<Worker | null>(null);
const [workerState, setWorkerState] = React.useState<WorkerState>("loading");
@ -74,9 +74,7 @@ export const useExecController = <RS>() => {
React.useEffect(() => {
(async () => {
if (workerRef.current) throw new Error("Tried to reinitialize worker");
workerRef.current = new Worker(
new URL("../engines/worker.ts", import.meta.url)
);
workerRef.current = new Worker(`../workers/${langName}.js`);
const res = await requestWorker({ type: "Init" });
if (res.type === "ack" && res.data === "init") setWorkerState("empty");
else throwUnexpectedRes("init", res);