diff --git a/app/terminal/exec.tsx b/app/terminal/exec.tsx index fd7110e..46df421 100644 --- a/app/terminal/exec.tsx +++ b/app/terminal/exec.tsx @@ -63,6 +63,7 @@ export function ExecFile(props: ExecProps) { null, // ファイル実行で"return"メッセージが返ってくることはないはずなので、Prismを渡す必要はない props.language ); + // TODO: 実行が完了したあとに出力された場合、embedContextのsetExecResultにも出力を追加する必要があるが、それに対応したAPIになっていない }); // TODO: 1つのファイル名しか受け付けないところに無理やりコンマ区切りで全部のファイル名を突っ込んでいる setExecResult(props.filenames.join(","), outputs); diff --git a/app/terminal/repl.tsx b/app/terminal/repl.tsx index d34bcf0..5b839de 100644 --- a/app/terminal/repl.tsx +++ b/app/terminal/repl.tsx @@ -130,7 +130,7 @@ export function ReplTerminal({ // inputBufferを更新し、画面に描画する const updateBuffer = useCallback( - (newBuffer: () => string[]) => { + (newBuffer: (() => string[]) | null, insertBefore?: () => void) => { if (terminalInstanceRef.current) { hideCursor(terminalInstanceRef.current); // バッファの行数分カーソルを戻す @@ -142,8 +142,12 @@ export function ReplTerminal({ terminalInstanceRef.current.write("\r"); // バッファの内容をクリア terminalInstanceRef.current.write("\x1b[0J"); - // 新しいバッファの内容を表示 - inputBuffer.current = newBuffer(); + // バッファの前に追加で出力する内容(前のコマンドの出力)があればここで書き込む + insertBefore?.(); + // 新しいバッファの内容を表示、nullなら現状維持 + if (newBuffer) { + inputBuffer.current = newBuffer(); + } for (let i = 0; i < inputBuffer.current.length; i++) { terminalInstanceRef.current.write( (i === 0 ? prompt : (promptMore ?? prompt)) ?? "> " @@ -214,12 +218,22 @@ export function ReplTerminal({ const command = inputBuffer.current.join("\n").trim(); inputBuffer.current = []; const collectedOutputs: ReplOutput[] = []; + let executionDone = false; await runtimeMutex.runExclusive(async () => { await runCommand(command, (output) => { - collectedOutputs.push(output); - handleOutput(output); + if (executionDone) { + // すでに完了していて次のコマンドのプロンプトが出ている場合、その前に挿入 + updateBuffer(null, () => { + handleOutput(output); + }); + // TODO: embedContextのaddReplOutputにも出力を追加する必要があるが、それに対応したAPIになっていない + } else { + collectedOutputs.push(output); + handleOutput(output); + } }); }); + executionDone = true; updateBuffer(() => [""]); addReplOutput?.(terminalId, command, collectedOutputs); } diff --git a/app/terminal/worker/jsEval.worker.ts b/app/terminal/worker/jsEval.worker.ts index 64e2302..2f777ea 100644 --- a/app/terminal/worker/jsEval.worker.ts +++ b/app/terminal/worker/jsEval.worker.ts @@ -96,8 +96,6 @@ async function runCode( message: `${String(e)}`, }); } - } finally { - currentOutputCallback = null; } return { updatedFiles: {} as Record }; @@ -126,8 +124,6 @@ function runFile( message: `${String(e)}`, }); } - } finally { - currentOutputCallback = null; } return { updatedFiles: {} as Record }; diff --git a/app/terminal/worker/pyodide.worker.ts b/app/terminal/worker/pyodide.worker.ts index fbfbe7e..9464b0c 100644 --- a/app/terminal/worker/pyodide.worker.ts +++ b/app/terminal/worker/pyodide.worker.ts @@ -107,8 +107,6 @@ async function runCode( message: `予期せぬエラー: ${String(e).trim()}`, }); } - } finally { - currentOutputCallback = null; } const updatedFiles = readAllFiles(); @@ -165,8 +163,6 @@ async function runFile( message: `予期せぬエラー: ${String(e).trim()}`, }); } - } finally { - currentOutputCallback = null; } const updatedFiles = readAllFiles(); diff --git a/app/terminal/worker/ruby.worker.ts b/app/terminal/worker/ruby.worker.ts index af6779d..121a2ed 100644 --- a/app/terminal/worker/ruby.worker.ts +++ b/app/terminal/worker/ruby.worker.ts @@ -137,8 +137,6 @@ async function runCode( type: "error", message: formatRubyError(e, false), }); - } finally { - currentOutputCallback = null; } const updatedFiles = readAllFiles(); @@ -189,8 +187,6 @@ async function runFile( type: "error", message: formatRubyError(e, true), }); - } finally { - currentOutputCallback = null; } const updatedFiles = readAllFiles();