Spaces:
Running
Running
Commit ·
bbfdaf1
1
Parent(s): 1700d78
commit initial 09-12-2025 023
Browse files- src/App.js +29 -60
src/App.js
CHANGED
|
@@ -17,7 +17,7 @@ import { downloadProjectZip } from "./zipExport";
|
|
| 17 |
import { parseProblems } from "./problemParser";
|
| 18 |
import "./App.css";
|
| 19 |
import "xterm/css/xterm.css";
|
| 20 |
-
|
| 21 |
// =================== SUPPORTED LANGUAGES ===================
|
| 22 |
const LANGUAGE_OPTIONS = [
|
| 23 |
{ id: "python", ext: ".py", icon: "🐍", monaco: "python" },
|
|
@@ -242,58 +242,7 @@ function codeNeedsInput(code, langId) {
|
|
| 242 |
return false;
|
| 243 |
}
|
| 244 |
}
|
| 245 |
-
// ----------------------
|
| 246 |
-
// Call this whenever a new terminal line arrives (from xterm onData)
|
| 247 |
-
// It appends the line to accumulated stdin and re-runs the current file.
|
| 248 |
-
// Uses a local variable for stdin to avoid setState races.
|
| 249 |
-
// ----------------------
|
| 250 |
-
const runCodeWithUpdatedInput = async (inputLine) => {
|
| 251 |
-
// echo the line in terminal UI
|
| 252 |
-
appendTerminal(`> ${inputLine}`);
|
| 253 |
-
|
| 254 |
-
// build new accumulated stdin locally (so we can use it immediately)
|
| 255 |
-
const newAccum = (accumStdin || "") + inputLine + "\n";
|
| 256 |
-
// update state so further interactions know about it
|
| 257 |
-
setAccumStdin(newAccum);
|
| 258 |
-
|
| 259 |
-
// get current file node
|
| 260 |
-
const node = getNodeByPath(tree, activePath);
|
| 261 |
-
if (!node || node.type !== "file") {
|
| 262 |
-
appendTerminal("[Error] No file selected to run.");
|
| 263 |
-
setAwaitingInput(false);
|
| 264 |
-
return;
|
| 265 |
-
}
|
| 266 |
-
|
| 267 |
-
const selectedLang = LANGUAGE_OPTIONS.find((l) => node.name.endsWith(l.ext))?.id;
|
| 268 |
-
if (!selectedLang || !RUNNABLE_LANGS.includes(selectedLang)) {
|
| 269 |
-
appendTerminal(`[Error] Run not supported for ${node.name}`);
|
| 270 |
-
setAwaitingInput(false);
|
| 271 |
-
return;
|
| 272 |
-
}
|
| 273 |
|
| 274 |
-
// run immediately with local stdin (newAccum)
|
| 275 |
-
setIsRunning(true);
|
| 276 |
-
try {
|
| 277 |
-
const res = await runCode(node.content, selectedLang, newAccum);
|
| 278 |
-
const out = res.output ?? "";
|
| 279 |
-
setOutput(out);
|
| 280 |
-
appendTerminal(out);
|
| 281 |
-
setProblems(res.error ? parseProblems(res.output) : []);
|
| 282 |
-
|
| 283 |
-
// if output indicates program needs more input, keep awaitingInput true
|
| 284 |
-
if (outputLooksForInput(out)) {
|
| 285 |
-
setAwaitingInput(true);
|
| 286 |
-
} else {
|
| 287 |
-
setAwaitingInput(false);
|
| 288 |
-
}
|
| 289 |
-
} catch (err) {
|
| 290 |
-
const errText = String(err);
|
| 291 |
-
appendTerminal(errText);
|
| 292 |
-
setAwaitingInput(false);
|
| 293 |
-
} finally {
|
| 294 |
-
setIsRunning(false);
|
| 295 |
-
}
|
| 296 |
-
};
|
| 297 |
const handleRun = async () => {
|
| 298 |
const node = getNodeByPath(tree, activePath);
|
| 299 |
if (!node || node.type !== "file") {
|
|
@@ -587,14 +536,34 @@ const runCodeWithUpdatedInput = async (inputLine) => {
|
|
| 587 |
{/* Bottom panels */}
|
| 588 |
<div className="ide-panels">
|
| 589 |
{/* Terminal output */}
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 598 |
|
| 599 |
{/* Problems */}
|
| 600 |
{problems.length > 0 && (
|
|
|
|
| 17 |
import { parseProblems } from "./problemParser";
|
| 18 |
import "./App.css";
|
| 19 |
import "xterm/css/xterm.css";
|
| 20 |
+
|
| 21 |
// =================== SUPPORTED LANGUAGES ===================
|
| 22 |
const LANGUAGE_OPTIONS = [
|
| 23 |
{ id: "python", ext: ".py", icon: "🐍", monaco: "python" },
|
|
|
|
| 242 |
return false;
|
| 243 |
}
|
| 244 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
const handleRun = async () => {
|
| 247 |
const node = getNodeByPath(tree, activePath);
|
| 248 |
if (!node || node.type !== "file") {
|
|
|
|
| 536 |
{/* Bottom panels */}
|
| 537 |
<div className="ide-panels">
|
| 538 |
{/* Terminal output */}
|
| 539 |
+
<div className="ide-output-terminal" style={{ marginBottom: 8 }}>
|
| 540 |
+
<div style={{ fontSize: 12, color: "#ccc", marginBottom: 6 }}>Terminal</div>
|
| 541 |
+
<div className="terminal-content" style={{ background: "#000", color: "#0f0", padding: 8, borderRadius: 6, maxHeight: 220, overflowY: "auto", whiteSpace: "pre-wrap", fontFamily: "Consolas, monospace" }}>
|
| 542 |
+
{terminalLines.length === 0 ? <div style={{ color: "#999" }}>[Program output will appear here]</div> : terminalLines.map((ln, i) => <div key={i}>{ln}</div>)}
|
| 543 |
+
{awaitingInput && <div style={{ color: "#fff" }}> </div>}
|
| 544 |
+
</div>
|
| 545 |
+
|
| 546 |
+
{/* Terminal input (shown only when program asks input) */}
|
| 547 |
+
{awaitingInput ? (
|
| 548 |
+
<div style={{ display: "flex", gap: 6, marginTop: 6 }}>
|
| 549 |
+
<input
|
| 550 |
+
className="ide-input-box"
|
| 551 |
+
placeholder="Type input and press Enter..."
|
| 552 |
+
value={terminalInput}
|
| 553 |
+
onChange={(e) => setTerminalInput(e.target.value)}
|
| 554 |
+
onKeyDown={onTerminalKeyDown}
|
| 555 |
+
disabled={!awaitingInput || isRunning}
|
| 556 |
+
/>
|
| 557 |
+
<button onClick={sendTerminalInput} disabled={!awaitingInput || isRunning} className="ide-button">Send</button>
|
| 558 |
+
</div>
|
| 559 |
+
) : (
|
| 560 |
+
// If not awaiting input, show legacy single-run input + hint to run for interactive programs
|
| 561 |
+
<div style={{ display: "flex", gap: 6, marginTop: 6 }}>
|
| 562 |
+
<input className="ide-input-box" placeholder="(Optional) Program input for single-run" value={stdin} onChange={(e) => setStdin(e.target.value)} />
|
| 563 |
+
<div style={{ alignSelf: "center", color: "#999", fontSize: 12 }}>Press Run → to execute</div>
|
| 564 |
+
</div>
|
| 565 |
+
)}
|
| 566 |
+
</div>
|
| 567 |
|
| 568 |
{/* Problems */}
|
| 569 |
{problems.length > 0 && (
|