FrederickSundeep commited on
Commit
a405934
·
1 Parent(s): 0a3b0ff

commit initial 09-12-2025 021

Browse files
Files changed (4) hide show
  1. package-lock.json +20 -1
  2. package.json +3 -1
  3. src/App.js +14 -29
  4. src/Terminal.js +60 -0
package-lock.json CHANGED
@@ -19,7 +19,9 @@
19
  "react-dom": "^19.1.0",
20
  "react-hot-toast": "^2.6.0",
21
  "react-scripts": "5.0.1",
22
- "web-vitals": "^2.1.4"
 
 
23
  }
24
  },
25
  "node_modules/@adobe/css-tools": {
@@ -17561,6 +17563,23 @@
17561
  "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
17562
  "license": "MIT"
17563
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17564
  "node_modules/y18n": {
17565
  "version": "5.0.8",
17566
  "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
 
19
  "react-dom": "^19.1.0",
20
  "react-hot-toast": "^2.6.0",
21
  "react-scripts": "5.0.1",
22
+ "web-vitals": "^2.1.4",
23
+ "xterm": "^5.3.0",
24
+ "xterm-addon-fit": "^0.8.0"
25
  }
26
  },
27
  "node_modules/@adobe/css-tools": {
 
17563
  "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
17564
  "license": "MIT"
17565
  },
17566
+ "node_modules/xterm": {
17567
+ "version": "5.3.0",
17568
+ "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
17569
+ "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==",
17570
+ "deprecated": "This package is now deprecated. Move to @xterm/xterm instead.",
17571
+ "license": "MIT"
17572
+ },
17573
+ "node_modules/xterm-addon-fit": {
17574
+ "version": "0.8.0",
17575
+ "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
17576
+ "integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
17577
+ "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.",
17578
+ "license": "MIT",
17579
+ "peerDependencies": {
17580
+ "xterm": "^5.0.0"
17581
+ }
17582
+ },
17583
  "node_modules/y18n": {
17584
  "version": "5.0.8",
17585
  "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
package.json CHANGED
@@ -14,7 +14,9 @@
14
  "react-dom": "^19.1.0",
15
  "react-hot-toast": "^2.6.0",
16
  "react-scripts": "5.0.1",
17
- "web-vitals": "^2.1.4"
 
 
18
  },
19
  "scripts": {
20
  "start": "react-scripts start",
 
14
  "react-dom": "^19.1.0",
15
  "react-hot-toast": "^2.6.0",
16
  "react-scripts": "5.0.1",
17
+ "web-vitals": "^2.1.4",
18
+ "xterm": "^5.3.0",
19
+ "xterm-addon-fit": "^0.8.0"
20
  },
21
  "scripts": {
22
  "start": "react-scripts start",
src/App.js CHANGED
@@ -16,7 +16,8 @@ import {
16
  import { downloadProjectZip } from "./zipExport";
17
  import { parseProblems } from "./problemParser";
18
  import "./App.css";
19
-
 
20
  // =================== SUPPORTED LANGUAGES ===================
21
  const LANGUAGE_OPTIONS = [
22
  { id: "python", ext: ".py", icon: "🐍", monaco: "python" },
@@ -535,34 +536,18 @@ function codeNeedsInput(code, langId) {
535
  {/* Bottom panels */}
536
  <div className="ide-panels">
537
  {/* Terminal output */}
538
- <div className="ide-output-terminal" style={{ marginBottom: 8 }}>
539
- <div style={{ fontSize: 12, color: "#ccc", marginBottom: 6 }}>Terminal</div>
540
- <div className="terminal-content" style={{ background: "#000", color: "#0f0", padding: 8, borderRadius: 6, maxHeight: 220, overflowY: "auto", whiteSpace: "pre-wrap", fontFamily: "Consolas, monospace" }}>
541
- {terminalLines.length === 0 ? <div style={{ color: "#999" }}>[Program output will appear here]</div> : terminalLines.map((ln, i) => <div key={i}>{ln}</div>)}
542
- {awaitingInput && <div style={{ color: "#fff" }}>&nbsp;</div>}
543
- </div>
544
-
545
- {/* Terminal input (shown only when program asks input) */}
546
- {awaitingInput ? (
547
- <div style={{ display: "flex", gap: 6, marginTop: 6 }}>
548
- <input
549
- className="ide-input-box"
550
- placeholder="Type input and press Enter..."
551
- value={terminalInput}
552
- onChange={(e) => setTerminalInput(e.target.value)}
553
- onKeyDown={onTerminalKeyDown}
554
- disabled={!awaitingInput || isRunning}
555
- />
556
- <button onClick={sendTerminalInput} disabled={!awaitingInput || isRunning} className="ide-button">Send</button>
557
- </div>
558
- ) : (
559
- // If not awaiting input, show legacy single-run input + hint to run for interactive programs
560
- <div style={{ display: "flex", gap: 6, marginTop: 6 }}>
561
- <input className="ide-input-box" placeholder="(Optional) Program input for single-run" value={stdin} onChange={(e) => setStdin(e.target.value)} />
562
- <div style={{ alignSelf: "center", color: "#999", fontSize: 12 }}>Press Run → to execute</div>
563
- </div>
564
- )}
565
- </div>
566
 
567
  {/* Problems */}
568
  {problems.length > 0 && (
 
16
  import { downloadProjectZip } from "./zipExport";
17
  import { parseProblems } from "./problemParser";
18
  import "./App.css";
19
+ import "xterm/css/xterm.css";
20
+ import XTerm from "./Terminal";
21
  // =================== SUPPORTED LANGUAGES ===================
22
  const LANGUAGE_OPTIONS = [
23
  { id: "python", ext: ".py", icon: "🐍", monaco: "python" },
 
536
  {/* Bottom panels */}
537
  <div className="ide-panels">
538
  {/* Terminal output */}
539
+ <XTerm
540
+ output={output}
541
+ onData={(userInputLine) => {
542
+ // Send each line to backend dynamically
543
+ setAccumStdin((prev) => prev + userInputLine + "\n");
544
+
545
+ // If waiting for next input, resume execution or re-run code
546
+ if (awaitingInput) {
547
+ runCodeWithUpdatedInput();
548
+ }
549
+ }}
550
+ />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
 
552
  {/* Problems */}
553
  {problems.length > 0 && (
src/Terminal.js ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useRef } from "react";
2
+ import { Terminal } from "xterm";
3
+ import { FitAddon } from "xterm-addon-fit";
4
+ import "xterm/css/xterm.css";
5
+
6
+ export default function XTerm({ onData, output }) {
7
+ const termRef = useRef(null);
8
+ const fitAddon = new FitAddon();
9
+
10
+ useEffect(() => {
11
+ const term = new Terminal({
12
+ cursorBlink: true,
13
+ fontSize: 14,
14
+ theme: {
15
+ background: "#1e1e1e",
16
+ foreground: "#ffffff",
17
+ },
18
+ });
19
+
20
+ termRef.current = term;
21
+ term.loadAddon(fitAddon);
22
+
23
+ term.open(document.getElementById("terminal-container"));
24
+ fitAddon.fit();
25
+
26
+ term.onData((data) => {
27
+ // Echo user input (like real terminals)
28
+ term.write(data);
29
+
30
+ // When ENTER pressed, send full line to parent
31
+ if (data === "\r") {
32
+ const line = term._core.buffer.xtermBuffer.active.getLine(
33
+ term.buffer.active.cursorY
34
+ ).translateToString().trim();
35
+ onData(line);
36
+ }
37
+ });
38
+
39
+ return () => term.dispose();
40
+ }, []);
41
+
42
+ // Print backend output into terminal
43
+ useEffect(() => {
44
+ if (output) {
45
+ termRef.current?.writeln("\r\n" + output);
46
+ }
47
+ }, [output]);
48
+
49
+ return (
50
+ <div
51
+ id="terminal-container"
52
+ style={{
53
+ width: "100%",
54
+ height: "180px",
55
+ background: "#1e1e1e",
56
+ borderTop: "1px solid #333",
57
+ }}
58
+ ></div>
59
+ );
60
+ }