import { useState, useEffect, useRef } from "react"; import Editor from "@monaco-editor/react"; import { askAgent } from "./agent/assistant"; import { runCode } from "./agent/runner"; import { loadTree, saveTree, addFile, addFolder, renameNode, deleteNode, getNodeByPath, updateFileContent, searchTree, } from "./fileStore"; import { downloadProjectZip } from "./zipExport"; import { parseProblems } from "./problemParser"; import "./App.css"; // =================== SUPPORTED LANGUAGES =================== const LANGUAGE_OPTIONS = [ { id: "python", ext: ".py", icon: "๐", monaco: "python" }, { id: "javascript", ext: ".js", icon: "๐จ", monaco: "javascript" }, { id: "typescript", ext: ".ts", icon: "๐ฆ", monaco: "typescript" }, { id: "cpp", ext: ".cpp", icon: "๐ ", monaco: "cpp" }, { id: "c", ext: ".c", icon: "๐ท", monaco: "c" }, { id: "java", ext: ".java", icon: "โ", monaco: "java" }, { id: "html", ext: ".html", icon: "๐", monaco: "html" }, { id: "css", ext: ".css", icon: "๐จ", monaco: "css" }, { id: "json", ext: ".json", icon: "๐งพ", monaco: "json" }, ]; const RUNNABLE_LANGS = ["python", "javascript", "java"]; // =================== APP =================== function App() { const [tree, setTree] = useState(loadTree()); const [activePath, setActivePath] = useState("main.py"); const [output, setOutput] = useState(""); const [prompt, setPrompt] = useState(""); const [explanation, setExplanation] = useState(""); const [stdin, setStdin] = useState(""); const [problems, setProblems] = useState([]); const [theme, setTheme] = useState("vs-dark"); const [searchOpen, setSearchOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const [aiSuggestions, setAiSuggestions] = useState([]); const [contextMenu, setContextMenu] = useState(null); // right-click menu const editorRef = useRef(null); const currentFile = getNodeByPath(tree, activePath); const langMeta = LANGUAGE_OPTIONS.find((l) => currentFile?.name.endsWith(l.ext)) || LANGUAGE_OPTIONS[0]; // Save after tree change useEffect(() => { saveTree(tree); }, [tree]); // =================== FILE ACTIONS =================== const handleNewFile = () => { const name = window.prompt("Filename (with extension):"); if (!name) return; setTree(addFile(tree, name)); }; const handleNewFolder = () => { const name = window.prompt("Folder name:"); if (!name) return; setTree(addFolder(tree, name)); }; const handleRename = () => { if (!activePath) return; const newName = window.prompt("New name:", currentFile.name); if (!newName) return; setTree(renameNode(tree, activePath, newName)); setActivePath(newName); }; const handleDelete = () => { if (!activePath) return; setTree(deleteNode(tree, activePath)); setActivePath(""); // unselect }; const downloadFile = () => { if (!currentFile?.content) return; const blob = new Blob([currentFile.content], { type: "text/plain;charset=utf-8", }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = currentFile.name; a.click(); }; // =================== RUN =================== const handleRun = async () => { if (!currentFile?.content) return; const selectedLang = langMeta.id; if (!RUNNABLE_LANGS.includes(selectedLang)) { setOutput(`โ ๏ธ Cannot run ${selectedLang}.`); return; } const res = await runCode(currentFile.content, selectedLang, stdin); setOutput(res.output || ""); setProblems(res.error ? parseProblems(res.output) : []); }; // =================== AI =================== const handleAskFix = async () => { if (!currentFile) return; const userHint = prompt.trim() ? `User request: ${prompt}` : ""; const reply = await askAgent( `Improve, debug, or refactor this ${langMeta.id} file. ${userHint} Return ONLY updated code, no explanation. CODE: ${currentFile.content}` ); updateActiveFileContent(reply); }; const handleExplainSelection = async () => { if (!currentFile) return; const editor = editorRef.current; const selected = editor .getModel() .getValueInRange(editor.getSelection()); const code = selected.trim() || currentFile.content; const userHint = prompt.trim() ? `Focus on: ${prompt}` : "Give a clear and simple explanation."; const reply = await askAgent( `Explain what this ${langMeta.id} code does, any risks, and improvements. ${userHint} CODE: ${code}` ); setExplanation(reply); }; const updateActiveFileContent = (value) => { const updated = updateFileContent(tree, activePath, value); setTree(updated); }; // ===== AI Autocomplete Suggestions (Popup) ===== const fetchAiSuggestions = async (code) => { if (!code?.trim()) return; const reply = await askAgent( `Suggest possible next lines for continuation. Return 3 short snippets.\n${code}` ); setAiSuggestions(reply.split("\n").filter((l) => l.trim())); }; // =================== SEARCH =================== const handleSearchToggle = () => setSearchOpen(!searchOpen); const handleSearchNow = () => { if (!searchQuery) return; alert( `Found occurrences:\n${JSON.stringify( searchTree(tree, searchQuery), null, 2 )}` ); }; // =================== UI =================== return (
{output}
setStdin(e.target.value)}
/>
{problems.length > 0 && (