22
33import chalk from "chalk" ;
44import { usePyodide } from "./python/pyodide" ;
5- import { clearTerminal , getRows , useTerminal } from "./terminal" ;
5+ import { clearTerminal , getRows , hideCursor , useTerminal } from "./terminal" ;
66import { useSectionCode } from "../[docs_id]/section" ;
7+ import { useWandbox } from "./wandbox/wandbox" ;
8+
9+ export type ExecLang = "python" | "cpp" ;
710
811interface ExecProps {
9- filename : string ;
10- language : string ;
12+ /*
13+ * Pythonの場合はメインファイル1つのみを指定する。
14+ * C++の場合はソースコード(.cpp)とヘッダー(.h)を全部指定し、ExecFile内で拡張子を元にソースコードと追加コードを分ける。
15+ */
16+ filenames : string [ ] ;
17+ language : ExecLang ;
1118 content : string ;
1219}
1320export function ExecFile ( props : ExecProps ) {
1421 const { terminalRef, terminalInstanceRef, termReady } = useTerminal ( {
1522 getRows : ( cols : number ) => getRows ( props . content , cols ) + 1 ,
1623 onReady : ( ) => {
17- // カーソル非表示
18- terminalInstanceRef . current ! . write ( "\x1b[?25l" ) ;
24+ hideCursor ( terminalInstanceRef . current ! ) ;
1925 for ( const line of props . content . split ( "\n" ) ) {
2026 terminalInstanceRef . current ! . writeln ( line ) ;
2127 }
@@ -24,13 +30,17 @@ export function ExecFile(props: ExecProps) {
2430 const sectionContext = useSectionCode ( ) ;
2531
2632 const pyodide = usePyodide ( ) ;
33+ const wandbox = useWandbox ( ) ;
2734
2835 let commandline : string ;
2936 let exec : ( ) => Promise < void > | void ;
3037 let runtimeInitializing : boolean ;
3138 switch ( props . language ) {
3239 case "python" :
33- commandline = `python ${ props . filename } ` ;
40+ if ( props . filenames . length !== 1 ) {
41+ throw new Error ( "Pythonの実行にはファイル名が1つ必要です" ) ;
42+ }
43+ commandline = `python ${ props . filenames [ 0 ] } ` ;
3444 runtimeInitializing = pyodide . initializing ;
3545 exec = async ( ) => {
3646 if ( ! pyodide . ready ) {
@@ -41,8 +51,12 @@ export function ExecFile(props: ExecProps) {
4151 await pyodide . init ( ) ;
4252 }
4353 clearTerminal ( terminalInstanceRef . current ! ) ;
44- const outputs = await pyodide . runFile ( props . filename ) ;
45- for ( const output of outputs ) {
54+ const outputs = await pyodide . runFile ( props . filenames [ 0 ] ) ;
55+ for ( let i = 0 ; i < outputs . length ; i ++ ) {
56+ const output = outputs [ i ] ;
57+ if ( i > 0 ) {
58+ terminalInstanceRef . current ! . writeln ( "" ) ;
59+ }
4660 // 出力内容に応じて色を変える
4761 const message = String ( output . message ) . replace ( / \n / g, "\r\n" ) ;
4862 switch ( output . type ) {
@@ -54,10 +68,51 @@ export function ExecFile(props: ExecProps) {
5468 break ;
5569 }
5670 }
57- sectionContext ?. setExecResult ( props . filename , outputs ) ;
71+ sectionContext ?. setExecResult ( props . filenames [ 0 ] , outputs ) ;
72+ } ;
73+ break ;
74+ case "cpp" :
75+ if ( ! props . filenames || props . filenames . length === 0 ) {
76+ throw new Error ( "C++の実行には filenames プロパティが必要です" ) ;
77+ }
78+ commandline = wandbox . cppOptions
79+ ? `${ wandbox . cppOptions . commandline } ${ props . filenames . join ( " " ) } && ./a.out`
80+ : "" ;
81+ runtimeInitializing = false ;
82+ exec = async ( ) => {
83+ clearTerminal ( terminalInstanceRef . current ! ) ;
84+ const namesSource = props . filenames ! . filter ( ( name ) =>
85+ name . endsWith ( ".cpp" )
86+ ) ;
87+ const namesAdditional = props . filenames ! . filter (
88+ ( name ) => ! name . endsWith ( ".cpp" )
89+ ) ;
90+ const outputs = await wandbox . runFiles (
91+ "C++" ,
92+ namesSource ,
93+ namesAdditional
94+ ) ;
95+ for ( let i = 0 ; i < outputs . length ; i ++ ) {
96+ const output = outputs [ i ] ;
97+ if ( i > 0 ) {
98+ terminalInstanceRef . current ! . writeln ( "" ) ;
99+ }
100+ // 出力内容に応じて色を変える
101+ const message = String ( output . message ) . replace ( / \n / g, "\r\n" ) ;
102+ switch ( output . type ) {
103+ case "error" :
104+ terminalInstanceRef . current ! . write ( chalk . red ( message ) ) ;
105+ break ;
106+ default :
107+ terminalInstanceRef . current ! . write ( message ) ;
108+ break ;
109+ }
110+ }
111+ sectionContext ?. setExecResult ( props . filename ! , outputs ) ;
58112 } ;
59113 break ;
60114 default :
115+ props . language satisfies never ;
61116 commandline = `エラー: 非対応の言語 ${ props . language } ` ;
62117 runtimeInitializing = false ;
63118 exec = ( ) => undefined ;
0 commit comments