@@ -8,19 +8,17 @@ import {
88 useTerminal ,
99} from "./terminal" ;
1010import { writeOutput } from "./repl" ;
11- import { useState } from "react" ;
11+ import { useEffect , useState } from "react" ;
1212import { useEmbedContext } from "./embedContext" ;
13- import { useRuntime } from "./runtime" ;
14-
15- export type ExecLang = "python" | "cpp" ;
13+ import { RuntimeLang , useRuntime } from "./runtime" ;
1614
1715interface ExecProps {
1816 /*
1917 * Pythonの場合はメインファイル1つのみを指定する。
2018 * C++の場合はソースコード(.cpp)を全部指定する。
2119 */
2220 filenames : string [ ] ;
23- language : ExecLang ;
21+ language : RuntimeLang ;
2422 content : string ;
2523}
2624export function ExecFile ( props : ExecProps ) {
@@ -33,70 +31,65 @@ export function ExecFile(props: ExecProps) {
3331 }
3432 } ,
3533 } ) ;
36- const sectionContext = useEmbedContext ( ) ;
34+ const { setExecResult } = useEmbedContext ( ) ;
3735
38- const runtime = useRuntime ( props . language ) ;
36+ const { ready , runFiles , getCommandlineStr } = useRuntime ( props . language ) ;
3937
40- // 表示するコマンドライン文字列
41- let commandline : string ;
42- if ( props . language === "python" ) {
43- if ( props . filenames . length !== 1 ) {
44- throw new Error ( "Pythonの実行にはファイル名が1つ必要です" ) ;
45- }
46- commandline = `python ${ props . filenames [ 0 ] } ` ;
47- } else if ( props . language === "cpp" ) {
48- if ( ! props . filenames || props . filenames . length === 0 ) {
49- throw new Error ( "C++の実行には filenames プロパティが必要です" ) ;
38+ // ユーザーがクリックした時(triggered) && ランタイムが準備できた時に、実際にinitCommandを実行する(executing)
39+ const [ executionState , setExecutionState ] = useState <
40+ "idle" | "triggered" | "executing"
41+ > ( "idle" ) ;
42+ useEffect ( ( ) => {
43+ if ( executionState === "triggered" && ready ) {
44+ setExecutionState ( "executing" ) ;
45+ ( async ( ) => {
46+ clearTerminal ( terminalInstanceRef . current ! ) ;
47+ terminalInstanceRef . current ! . write ( systemMessageColor ( "実行中です..." ) ) ;
48+ const outputs = await runFiles ( props . filenames ) ;
49+ clearTerminal ( terminalInstanceRef . current ! ) ;
50+ writeOutput ( terminalInstanceRef . current ! , outputs , false ) ;
51+ // TODO: 1つのファイル名しか受け付けないところに無理やりコンマ区切りで全部のファイル名を突っ込んでいる
52+ setExecResult ( props . filenames . join ( "," ) , outputs ) ;
53+ setExecutionState ( "idle" ) ;
54+ } ) ( ) ;
5055 }
51- commandline = runtime . getCommandlineStr
52- ? runtime . getCommandlineStr ( props . filenames )
53- : `g++ ${ props . filenames . join ( " " ) } ` ;
54- } else {
55- props . language satisfies never ;
56- commandline = `エラー: 非対応の言語 ${ props . language } ` ;
57- }
58-
59- const runtimeInitializing = runtime . initializing ;
60- const beforeExec = runtime . ready ? null : runtime . init ;
61- const exec = ( ) => runtime . runFiles ( props . filenames ) ;
56+ } , [
57+ executionState ,
58+ ready ,
59+ props . filenames ,
60+ runFiles ,
61+ setExecResult ,
62+ terminalInstanceRef ,
63+ ] ) ;
6264
63- // 実行中です... と表示される
64- const [ isExecuting , setIsExecuting ] = useState < boolean > ( false ) ;
65-
66- const onClick = async ( ) => {
67- if ( beforeExec ) {
68- clearTerminal ( terminalInstanceRef . current ! ) ;
69- terminalInstanceRef . current ! . write (
70- systemMessageColor ( "(初期化しています...しばらくお待ちください)" )
71- ) ;
72- await beforeExec ( ) ;
73- }
74- clearTerminal ( terminalInstanceRef . current ! ) ;
75- terminalInstanceRef . current ! . write ( systemMessageColor ( "実行中です..." ) ) ;
76- setIsExecuting ( true ) ;
77- const outputs = await exec ( ) ;
78- setIsExecuting ( false ) ;
79- clearTerminal ( terminalInstanceRef . current ! ) ;
80- writeOutput ( terminalInstanceRef . current ! , outputs , false ) ;
81- // TODO: 1つのファイル名しか受け付けないところに無理やりコンマ区切りで全部のファイル名を突っ込んでいる
82- sectionContext ?. setExecResult ( props . filenames . join ( "," ) , outputs ) ;
83- } ;
8465 return (
8566 < div className = "relative" >
8667 < div >
8768 < button
8869 className = "btn btn-soft btn-primary rounded-tl-lg rounded-none"
89- onClick = { onClick }
90- disabled = { ! termReady || runtimeInitializing }
70+ onClick = { ( ) => {
71+ if ( ! ready ) {
72+ clearTerminal ( terminalInstanceRef . current ! ) ;
73+ terminalInstanceRef . current ! . write (
74+ systemMessageColor (
75+ "(初期化しています...しばらくお待ちください)"
76+ )
77+ ) ;
78+ }
79+ setExecutionState ( "triggered" ) ;
80+ } }
81+ disabled = { ! termReady || executionState !== "idle" }
9182 >
9283 ▶ 実行
9384 </ button >
94- < code className = "text-sm ml-4" > { commandline } </ code >
85+ < code className = "text-sm ml-4" >
86+ { getCommandlineStr ( props . filenames ) }
87+ </ code >
9588 </ div >
9689 < div className = "bg-base-300 p-4 pt-2 rounded-b-lg" >
9790 < div ref = { terminalRef } />
9891 </ div >
99- { ( runtimeInitializing || isExecuting ) && (
92+ { executionState !== "idle" && (
10093 < div className = "absolute z-10 inset-0 cursor-wait" />
10194 ) }
10295 </ div >
0 commit comments