import { useCallback, useState, useRef } from 'react'; export const LANGUAGE_OPTIONS = [ { value: 'python', label: 'Python', monacoLanguage: 'python', extension: 'py', pistonLang: 'python', pistonVersion: '3.10.0' }, { value: 'python3', label: 'Python 3', monacoLanguage: 'python', extension: 'py', pistonLang: 'python3', pistonVersion: '3.10.0' }, { value: 'javascript', label: 'JavaScript', monacoLanguage: 'javascript', extension: 'js', pistonLang: 'javascript', pistonVersion: '18.15.0' }, { value: 'java', label: 'Java', monacoLanguage: 'java', extension: 'java', pistonLang: 'java', pistonVersion: '15.0.2' }, { value: 'c', label: 'C', monacoLanguage: 'c', extension: 'c', pistonLang: 'c', pistonVersion: '10.2.0' }, { value: 'cpp', label: 'C++', monacoLanguage: 'cpp', extension: 'cpp', pistonLang: 'c++', pistonVersion: '10.2.0' }, ]; export const DEFAULT_CODE_BY_LANGUAGE = { python: `# Type your input in the terminal box below after clicking RUN name = input("Enter your name: ") print(f"Hello, {name}!") `, python3: `# Type your input in the terminal box below after clicking RUN name = input("Enter your name: ") print(f"Hello, {name}!") `, javascript: `const fs = require("fs"); const input = fs.readFileSync(0, "utf8").trim(); console.log(\`Hello, \${input}!\`); `, java: `import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String name = scanner.next(); System.out.println("Hello, " + name + "!"); } } `, c: `#include int main() { char name[100]; scanf("%99s", name); printf("Hello, %s!\\n", name); return 0; } `, cpp: `#include using namespace std; int main() { string name; cin >> name; cout << "Hello, " << name << "!" << endl; return 0; } `, }; function compilerApiUrl() { const base = (import.meta.env.VITE_COMPILER_API_BASE ?? '').trim().replace(/\/$/, ''); return `${base}/api/compile`; } async function parseResponse(response) { const text = await response.text(); if (!text) return {}; try { return JSON.parse(text); } catch { return { error: text }; } } export default function useCompiler(initialLanguage = 'python') { const [language, setLanguage] = useState(initialLanguage); const [code, setCode] = useState(DEFAULT_CODE_BY_LANGUAGE[initialLanguage]); const [input, setInput] = useState(''); const [output, setOutput] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [executionTime, setExecutionTime] = useState(null); const [status, setStatus] = useState('idle'); // idle | running | success | error | compile_error const [compileOutput, setCompileOutput] = useState(''); const [analysis, setAnalysis] = useState(null); const [executionId, setExecutionId] = useState(null); const eventSourceRef = useRef(null); const handleRunInteractive = useCallback( async (overrides = {}) => { const runCode = overrides.code ?? code; const runLanguage = overrides.language ?? language; const onStdout = overrides.onStdout ?? (() => {}); const onStderr = overrides.onStderr ?? (() => {}); const onDone = overrides.onDone ?? (() => {}); if (!runCode.trim()) { onStderr('Code is required.'); onDone('error', 0); return; } setLoading(true); setOutput(''); setError(''); setExecutionTime(null); setStatus('running'); setCompileOutput(''); setAnalysis(null); setExecutionId(null); if (eventSourceRef.current) { eventSourceRef.current.close(); eventSourceRef.current = null; } try { const base = (import.meta.env.VITE_COMPILER_API_BASE ?? '').trim().replace(/\/$/, ''); const startRes = await fetch(`${base}/api/compile/start`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: runCode, language: runLanguage }), }); const startData = await parseResponse(startRes); if (!startRes.ok || !startData.executionId) { throw new Error(startData.error || 'Failed to start execution'); } const id = startData.executionId; setExecutionId(id); const es = new EventSource(`${base}/api/compile/stream/${id}`); eventSourceRef.current = es; es.addEventListener('stdout', (e) => { try { const text = JSON.parse(e.data); setOutput(prev => prev + text); onStdout(text); } catch(err) {} }); es.addEventListener('stderr', (e) => { try { const text = JSON.parse(e.data); setError(prev => prev + text); onStderr(text); } catch(err) {} }); es.addEventListener('done', (e) => { try { const data = JSON.parse(e.data); setStatus(data.status); setExecutionTime(data.executionTime); onDone(data.status, data.executionTime); } catch(err) {} setLoading(false); es.close(); eventSourceRef.current = null; }); es.onerror = () => { if (es.readyState === EventSource.CLOSED) return; const msg = '\n[Connection lost — is the compiler server running?]'; setError(prev => prev + msg); onStderr(msg); onDone('error', 0); setStatus('error'); setLoading(false); es.close(); eventSourceRef.current = null; }; } catch (err) { const msg = err.message; setError(msg); onStderr(msg); onDone('error', 0); setStatus('error'); setLoading(false); } }, [code, language], ); const sendInput = useCallback(async (text) => { if (!executionId || status !== 'running') return; try { const base = (import.meta.env.VITE_COMPILER_API_BASE ?? '').trim().replace(/\/$/, ''); await fetch(`${base}/api/compile/input/${executionId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ input: text + '\n' }), }); } catch (err) { console.error('Failed to send input', err); } }, [executionId, status]); const resetResult = useCallback(() => { if (eventSourceRef.current) { eventSourceRef.current.close(); eventSourceRef.current = null; } setOutput(''); setError(''); setExecutionTime(null); setStatus('idle'); setCompileOutput(''); setAnalysis(null); setExecutionId(null); }, []); return { code, setCode, language, setLanguage, input, setInput, output, setOutput, error, setError, loading, executionTime, status, compileOutput, analysis, handleRunInteractive, sendInput, resetResult, }; }