diff --git a/src/components/Markdown.tsx b/src/components/Markdown.tsx index c7d734f..1a15787 100644 --- a/src/components/Markdown.tsx +++ b/src/components/Markdown.tsx @@ -13,6 +13,8 @@ import userDebounce from "../helpers/userDebounce"; import { Point } from "unist"; import { isObjectEqual } from "../helpers/isObjectEqual"; import { getPythonResult } from "../helpers/getPythonResult"; +import { loadPyodide } from "pyodide"; +import { getPythonRuntime } from "../helpers/getPythonRuntime"; interface MarkdownProps { readonly className?: string; @@ -20,9 +22,17 @@ interface MarkdownProps { readonly children: string; } +const RunnerResultPlaceholder = ` +๐Ÿ˜ˆ [Info] ็ป“ๆžœ้œ€ไปฅ print ่พ“ๅ‡บ +๐Ÿš€ [Info] ๅฐ่ฏ•ๆ‰ง่กŒ Python ่„šๆœฌ... +`; + export const Markdown = (props: MarkdownProps) => { const { className, typingEffect, children } = props; + const [pythonRuntime, setPythonRuntime] = useState | null>(null); const [pythonResult, setPythonResult] = useState<{ result: string; startPos: Point | null; @@ -43,6 +53,12 @@ export const Markdown = (props: MarkdownProps) => { 1200 ); + const handleRunnerResult = (x: string) => + setPythonResult((prev) => ({ + ...prev, + result: `${prev.result.replace(RunnerResultPlaceholder, "")}\n${x}`, + })); + const handleRunPython = userDebounce( async ( startPos: Point | null, @@ -50,31 +66,24 @@ export const Markdown = (props: MarkdownProps) => { code: string, currentTarget: EventTarget ) => { - const resultPlaceholder = ` -๐Ÿ˜ˆ [Info] ็ป“ๆžœ้œ€ไปฅ print ่พ“ๅ‡บ -๐Ÿš€ [Info] ๅฐ่ฏ•ๆ‰ง่กŒ Python ่„šๆœฌ... -`; + let runtime: ReturnType | null; + if (pythonRuntime) { + runtime = pythonRuntime; + } else { + runtime = getPythonRuntime( + `${window.location.pathname}pyodide/`, + handleRunnerResult, + handleRunnerResult + ); + setPythonRuntime(runtime); + } (currentTarget as HTMLButtonElement).disabled = true; setPythonResult({ - result: `$ python3 script.py${resultPlaceholder}`, + result: `$ python3 script.py${RunnerResultPlaceholder}`, startPos, endPos, }); - const handler = (x: string) => - setPythonResult((prev) => ({ - ...prev, - result: `${prev.result.replace( - resultPlaceholder, - "" - )}\n${x}`, - })); - await getPythonResult( - code, - `${window.location.pathname}pyodide/`, - handler, - handler, - handler - ); + await getPythonResult(runtime, code, handleRunnerResult); (currentTarget as HTMLButtonElement).disabled = false; }, 300 diff --git a/src/helpers/getPythonResult.tsx b/src/helpers/getPythonResult.tsx index bc73c04..2fe79a4 100644 --- a/src/helpers/getPythonResult.tsx +++ b/src/helpers/getPythonResult.tsx @@ -1,10 +1,8 @@ import { loadPyodide } from "pyodide"; export const getPythonResult = async ( + pyodide: ReturnType, code: string, - repoURL: string, - onStdout: (x: string) => void, - onStderr: (x: string) => void, onException: (x: string) => void ) => { const availablePackages = [ @@ -25,12 +23,6 @@ export const getPythonResult = async ( { keyword: "hashlib", package: "hashlib" }, ]; try { - const pyodide = await loadPyodide({ - indexURL: repoURL, - stdout: onStdout, - stderr: onStderr, - homedir: "/home/user", - }); const matchedPackages = availablePackages .filter( ({ keyword }) => @@ -39,15 +31,17 @@ export const getPythonResult = async ( ) .map(({ package: pkg }) => pkg); if (!!matchedPackages.length) { - await pyodide.loadPackage(matchedPackages); + await (await pyodide).loadPackage(matchedPackages); } - await pyodide.runPythonAsync(` + await ( + await pyodide + ).runPythonAsync(` from js import prompt def input(p): return prompt(p) __builtins__.input = input `); - await pyodide.runPythonAsync(code); + await (await pyodide).runPythonAsync(code); } catch (e) { onException(`${e}`); } diff --git a/src/helpers/getPythonRuntime.tsx b/src/helpers/getPythonRuntime.tsx new file mode 100644 index 0000000..fcccf7e --- /dev/null +++ b/src/helpers/getPythonRuntime.tsx @@ -0,0 +1,13 @@ +import { loadPyodide } from "pyodide"; + +export const getPythonRuntime = ( + repoURL: string, + onStdout: (x: string) => void, + onStderr: (x: string) => void +) => + loadPyodide({ + indexURL: repoURL, + stdout: onStdout, + stderr: onStderr, + homedir: "/home/user", + });