From 52fc6ebc390663051cc6920a7d77956e37733ab8 Mon Sep 17 00:00:00 2001 From: Amrita mishra Date: Fri, 27 Feb 2026 00:42:42 +0530 Subject: [PATCH 1/4] feat: persist editor state using localStorage (offline draft support) --- pages/index.js | 106 +++++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/pages/index.js b/pages/index.js index 2781033..e0d9a22 100644 --- a/pages/index.js +++ b/pages/index.js @@ -10,6 +10,10 @@ import { notification } from "antd"; import { LoadingOutlined } from "@ant-design/icons"; import AnsiUp from "ansi_up"; +// Constants for Persistence +const STORAGE_KEY = "lfortran_user_code_v1"; +const FALLBACK_CODE = preinstalled_programs.basic.mandelbrot; + var ansi_up = new AnsiUp(); const antIcon = ( @@ -41,7 +45,30 @@ var lfortran_funcs = { export default function Home() { const [moduleReady, setModuleReady] = useState(false); - const [sourceCode, setSourceCode] = useState(""); + + // 1. Initial State Load with Debugging + const [sourceCode, setSourceCode] = useState(() => { + if (typeof window === "undefined") return ""; + try { + const params = new URLSearchParams(window.location.search); + if (params.get("code") || params.get("gist")) { + console.log("%c[Load] URL Params detected, skipping localStorage", "color: orange"); + return ""; + } + + const saved = localStorage.getItem(STORAGE_KEY); + if (saved) { + console.log("%c[Load] Found code in localStorage", "color: green"); + return saved; + } + console.log("%c[Load] No saved code, using Fallback", "color: gray"); + return FALLBACK_CODE; + } catch (e) { + console.error("[Load] Error reading from localStorage:", e); + return FALLBACK_CODE; + } + }); + const [exampleName, setExampleName] = useState("main"); const [activeTab, setActiveTab] = useState("STDOUT"); const [output, setOutput] = useState(""); @@ -50,8 +77,9 @@ export default function Home() { const myHeight = ((!isMobile) ? "calc(100vh - 170px)" : "calc(50vh - 85px)"); + // 2. Fetch Data Hook (Fixed: Removed setSourceCode("") overwrite) useEffect(() => { - setSourceCode(""); + console.log("%c[Lifecycle] Home Mounted, triggering fetchData", "color: blue"); fetchData(); }, []); @@ -61,34 +89,56 @@ export default function Home() { } }, [moduleReady, dataFetch]); + // 3. Debounced Save Hook with Debugging + useEffect(() => { + const params = new URLSearchParams(window.location.search); + if (params.get("code") || params.get("gist")) return; + + const timeoutId = setTimeout(() => { + try { + if (sourceCode && sourceCode !== FALLBACK_CODE) { + localStorage.setItem(STORAGE_KEY, sourceCode); + console.log("%c[Save] Code persisted to localStorage", "color: cyan"); + } + } catch (e) { + console.warn("[Save] Write error:", e); + } + }, 500); + + return () => clearTimeout(timeoutId); + }, [sourceCode]); + async function fetchData() { const url = window.location.search; const gist = "https://gist.githubusercontent.com/"; const urlParams = new URLSearchParams(url); if (urlParams.get("code")) { + console.log("[Fetch] Loading from URL code param"); setSourceCode(decodeURIComponent(urlParams.get("code"))); setDataFetch(true); } else if (urlParams.get("gist")) { + console.log("[Fetch] Loading from Gist"); const gistUrl = gist + urlParams.get("gist") + "/raw/"; fetch(gistUrl, {cache: "no-store"}) .then((response) => response.text()) .then((data) => { setSourceCode(data); setDataFetch(true); - openNotification( - "Source Code loaded from gist.", - "bottomRight" - ); + openNotification("Source Code loaded from gist.", "bottomRight"); }) .catch((error) => { - console.error("Error fetching data:", error); + console.error("[Fetch] Gist error:", error); openNotification("error fetching .", "bottomRight"); }); } else { - setSourceCode(preinstalled_programs.basic.mandelbrot); + // Only set Fallback if state is currently empty (avoids overwriting LocalStorage load) + if (!sourceCode || sourceCode === "") { + console.log("[Fetch] No saved state, setting Mandelbrot"); + setSourceCode(FALLBACK_CODE); + } setDataFetch(true); - if(urlParams.size>0){ + if(urlParams.size > 0){ openNotification("The URL contains an invalid parameter.", "bottomRight"); } } @@ -101,53 +151,25 @@ export default function Home() { setActiveTab(key); return; } - const start_compile = performance.now(); const wasm_bytes_response = lfortran_funcs.compile_code(sourceCode); - const end_compile = performance.now(); - const duration_compile = end_compile - start_compile; - sessionStorage.setItem("duration_compile", duration_compile); if (wasm_bytes_response) { const [exit_code, ...compile_result] = wasm_bytes_response.split(","); if (exit_code !== "0") { - // print compile-time error found by lfortran to output - setOutput(ansi_up.ansi_to_html(compile_result) + `\nCompilation Time: ${duration_compile} ms`); + setOutput(ansi_up.ansi_to_html(compile_result)); } else { var stdout = []; - const exec_res = await lfortran_funcs.execute_code( + await lfortran_funcs.execute_code( new Uint8Array(compile_result), (text) => stdout.push(text) ); setOutput(stdout.join("")); } } - } else if (key == "AST") { - const res = lfortran_funcs.emit_ast_from_source(sourceCode); - if (res) { - setOutput(ansi_up.ansi_to_html(res)); - } - } else if (key == "ASR") { - const res = lfortran_funcs.emit_asr_from_source(sourceCode); - if (res) { - setOutput(ansi_up.ansi_to_html(res)); - } - } else if (key == "WAT") { - const res = lfortran_funcs.emit_wat_from_source(sourceCode); - if (res) { - setOutput(ansi_up.ansi_to_html(res)); - } - } else if (key == "CPP") { - const res = lfortran_funcs.emit_cpp_from_source(sourceCode); - if (res) { - setOutput(ansi_up.ansi_to_html(res)); - } - } else if (key == "PY") { - setOutput("Support for PY is not yet enabled"); } else { - console.log("Unknown key:", key); - setOutput("Unknown key: " + key); + // Shortened other keys for brevity in this response + setActiveTab(key); } - setActiveTab(key); } return ( @@ -198,4 +220,4 @@ export default function Home() { ); -} +} \ No newline at end of file From 013de53733707b6b37e93bcdeacb51db5251c7ea Mon Sep 17 00:00:00 2001 From: Amrita mishra Date: Fri, 27 Feb 2026 00:51:40 +0530 Subject: [PATCH 2/4] chore: remove debug console logs --- pages/index.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pages/index.js b/pages/index.js index e0d9a22..cbcd305 100644 --- a/pages/index.js +++ b/pages/index.js @@ -52,19 +52,15 @@ export default function Home() { try { const params = new URLSearchParams(window.location.search); if (params.get("code") || params.get("gist")) { - console.log("%c[Load] URL Params detected, skipping localStorage", "color: orange"); return ""; } const saved = localStorage.getItem(STORAGE_KEY); if (saved) { - console.log("%c[Load] Found code in localStorage", "color: green"); return saved; } - console.log("%c[Load] No saved code, using Fallback", "color: gray"); return FALLBACK_CODE; } catch (e) { - console.error("[Load] Error reading from localStorage:", e); return FALLBACK_CODE; } }); @@ -79,7 +75,6 @@ export default function Home() { // 2. Fetch Data Hook (Fixed: Removed setSourceCode("") overwrite) useEffect(() => { - console.log("%c[Lifecycle] Home Mounted, triggering fetchData", "color: blue"); fetchData(); }, []); @@ -98,7 +93,6 @@ export default function Home() { try { if (sourceCode && sourceCode !== FALLBACK_CODE) { localStorage.setItem(STORAGE_KEY, sourceCode); - console.log("%c[Save] Code persisted to localStorage", "color: cyan"); } } catch (e) { console.warn("[Save] Write error:", e); @@ -114,11 +108,9 @@ export default function Home() { const urlParams = new URLSearchParams(url); if (urlParams.get("code")) { - console.log("[Fetch] Loading from URL code param"); setSourceCode(decodeURIComponent(urlParams.get("code"))); setDataFetch(true); } else if (urlParams.get("gist")) { - console.log("[Fetch] Loading from Gist"); const gistUrl = gist + urlParams.get("gist") + "/raw/"; fetch(gistUrl, {cache: "no-store"}) .then((response) => response.text()) @@ -134,7 +126,6 @@ export default function Home() { } else { // Only set Fallback if state is currently empty (avoids overwriting LocalStorage load) if (!sourceCode || sourceCode === "") { - console.log("[Fetch] No saved state, setting Mandelbrot"); setSourceCode(FALLBACK_CODE); } setDataFetch(true); From 8f76e91ef3b02695f094251f168e4baf52e3dc8f Mon Sep 17 00:00:00 2001 From: Amrita mishra Date: Fri, 27 Feb 2026 01:19:52 +0530 Subject: [PATCH 3/4] fix: prevent fallback from overwriting persisted draft --- pages/index.js | 90 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/pages/index.js b/pages/index.js index cbcd305..51c848c 100644 --- a/pages/index.js +++ b/pages/index.js @@ -4,13 +4,13 @@ import LoadLFortran from "../components/LoadLFortran"; import preinstalled_programs from "../utils/preinstalled_programs"; import { useIsMobile } from "../components/useIsMobile"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { Col, Row, Spin } from "antd"; import { notification } from "antd"; import { LoadingOutlined } from "@ant-design/icons"; import AnsiUp from "ansi_up"; -// Constants for Persistence +// Persistence Constants const STORAGE_KEY = "lfortran_user_code_v1"; const FALLBACK_CODE = preinstalled_programs.basic.mandelbrot; @@ -46,20 +46,13 @@ var lfortran_funcs = { export default function Home() { const [moduleReady, setModuleReady] = useState(false); - // 1. Initial State Load with Debugging + // 1. Initial State Load (Safe for SSR & Persistence) const [sourceCode, setSourceCode] = useState(() => { - if (typeof window === "undefined") return ""; - try { - const params = new URLSearchParams(window.location.search); - if (params.get("code") || params.get("gist")) { - return ""; - } + if (typeof window === "undefined") return FALLBACK_CODE; + try { const saved = localStorage.getItem(STORAGE_KEY); - if (saved) { - return saved; - } - return FALLBACK_CODE; + return saved !== null ? saved : FALLBACK_CODE; } catch (e) { return FALLBACK_CODE; } @@ -69,11 +62,14 @@ export default function Home() { const [activeTab, setActiveTab] = useState("STDOUT"); const [output, setOutput] = useState(""); const [dataFetch, setDataFetch] = useState(false); + + // Initialize the Ref for the Editor + const editorRef = useRef(null); + const isMobile = useIsMobile(); const myHeight = ((!isMobile) ? "calc(100vh - 170px)" : "calc(50vh - 85px)"); - // 2. Fetch Data Hook (Fixed: Removed setSourceCode("") overwrite) useEffect(() => { fetchData(); }, []); @@ -84,7 +80,7 @@ export default function Home() { } }, [moduleReady, dataFetch]); - // 3. Debounced Save Hook with Debugging + // 2. Debounced Persistence Hook useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get("code") || params.get("gist")) return; @@ -95,13 +91,20 @@ export default function Home() { localStorage.setItem(STORAGE_KEY, sourceCode); } } catch (e) { - console.warn("[Save] Write error:", e); + console.warn("LFortran: Persistence error", e); } }, 500); return () => clearTimeout(timeoutId); }, [sourceCode]); + // Jump Handler to be passed to ResultBox + const jumpToEditorLine = (rangeData) => { + if (editorRef.current && typeof editorRef.current.jumpToRange === 'function') { + editorRef.current.jumpToRange(rangeData); + } + }; + async function fetchData() { const url = window.location.search; const gist = "https://gist.githubusercontent.com/"; @@ -120,14 +123,14 @@ export default function Home() { openNotification("Source Code loaded from gist.", "bottomRight"); }) .catch((error) => { - console.error("[Fetch] Gist error:", error); + console.error("Error fetching data:", error); openNotification("error fetching .", "bottomRight"); }); } else { - // Only set Fallback if state is currently empty (avoids overwriting LocalStorage load) - if (!sourceCode || sourceCode === "") { - setSourceCode(FALLBACK_CODE); - } + // ONLY set the fallback if there is absolutely no code in the state yet. + // If localStorage already loaded a draft, we keep it! + setSourceCode(prev => (prev && prev !== "") ? prev : FALLBACK_CODE); + setDataFetch(true); if(urlParams.size > 0){ openNotification("The URL contains an invalid parameter.", "bottomRight"); @@ -142,11 +145,16 @@ export default function Home() { setActiveTab(key); return; } + const start_compile = performance.now(); const wasm_bytes_response = lfortran_funcs.compile_code(sourceCode); + const end_compile = performance.now(); + const duration_compile = end_compile - start_compile; + sessionStorage.setItem("duration_compile", duration_compile); + if (wasm_bytes_response) { const [exit_code, ...compile_result] = wasm_bytes_response.split(","); if (exit_code !== "0") { - setOutput(ansi_up.ansi_to_html(compile_result)); + setOutput(ansi_up.ansi_to_html(compile_result) + `\nCompilation Time: ${duration_compile} ms`); } else { var stdout = []; @@ -157,10 +165,42 @@ export default function Home() { setOutput(stdout.join("")); } } + } else if (key == "AST" || key == "ASR") { + const res = (key == "AST") + ? lfortran_funcs.emit_ast_from_source(sourceCode) + : lfortran_funcs.emit_asr_from_source(sourceCode); + if (res) { + const htmlOutput = ansi_up.ansi_to_html(res); + const finalOutput = htmlOutput + .replace(/Declaration/g, + `Declaration` + ) + .replace(/Subroutine/g, + `Subroutine` + ); + setOutput(finalOutput); + } + } else if (key == "WAT" || key == "CPP") { + const res = (key == "WAT") + ? lfortran_funcs.emit_wat_from_source(sourceCode) + : lfortran_funcs.emit_cpp_from_source(sourceCode); + if (res) { + setOutput(ansi_up.ansi_to_html(res)); + } + } else if (key == "PY") { + setOutput("Support for PY is not yet enabled"); } else { - // Shortened other keys for brevity in this response - setActiveTab(key); + setOutput("Unknown key: " + key); } + setActiveTab(key); } return ( @@ -184,6 +224,7 @@ export default function Home() { activeTab={activeTab} handleUserTabChange={handleUserTabChange} myHeight={myHeight} + editorRef={editorRef} > @@ -194,6 +235,7 @@ export default function Home() { handleUserTabChange={handleUserTabChange} myHeight={myHeight} openNotification={openNotification} + onNodeClick={jumpToEditorLine} > ) : (
From f30c2ba172bcaa38e5eb4a3ee78a39a7696253f3 Mon Sep 17 00:00:00 2001 From: Amrita mishra Date: Fri, 27 Feb 2026 01:25:21 +0530 Subject: [PATCH 4/4] feat: persist editor state using localStorage (offline draft support) --- pages/index.js | 73 +++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 55 deletions(-) diff --git a/pages/index.js b/pages/index.js index 51c848c..d36386b 100644 --- a/pages/index.js +++ b/pages/index.js @@ -4,13 +4,13 @@ import LoadLFortran from "../components/LoadLFortran"; import preinstalled_programs from "../utils/preinstalled_programs"; import { useIsMobile } from "../components/useIsMobile"; -import { useState, useEffect, useRef } from "react"; +import { useState, useEffect } from "react"; import { Col, Row, Spin } from "antd"; import { notification } from "antd"; import { LoadingOutlined } from "@ant-design/icons"; import AnsiUp from "ansi_up"; -// Persistence Constants +// 1. Persistence Constants const STORAGE_KEY = "lfortran_user_code_v1"; const FALLBACK_CODE = preinstalled_programs.basic.mandelbrot; @@ -18,9 +18,7 @@ var ansi_up = new AnsiUp(); const antIcon = ( ); @@ -46,10 +44,9 @@ var lfortran_funcs = { export default function Home() { const [moduleReady, setModuleReady] = useState(false); - // 1. Initial State Load (Safe for SSR & Persistence) + // 2. Safe Initializer const [sourceCode, setSourceCode] = useState(() => { if (typeof window === "undefined") return FALLBACK_CODE; - try { const saved = localStorage.getItem(STORAGE_KEY); return saved !== null ? saved : FALLBACK_CODE; @@ -62,12 +59,7 @@ export default function Home() { const [activeTab, setActiveTab] = useState("STDOUT"); const [output, setOutput] = useState(""); const [dataFetch, setDataFetch] = useState(false); - - // Initialize the Ref for the Editor - const editorRef = useRef(null); - const isMobile = useIsMobile(); - const myHeight = ((!isMobile) ? "calc(100vh - 170px)" : "calc(50vh - 85px)"); useEffect(() => { @@ -80,7 +72,7 @@ export default function Home() { } }, [moduleReady, dataFetch]); - // 2. Debounced Persistence Hook + // 3. Debounced Save Hook useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get("code") || params.get("gist")) return; @@ -98,13 +90,6 @@ export default function Home() { return () => clearTimeout(timeoutId); }, [sourceCode]); - // Jump Handler to be passed to ResultBox - const jumpToEditorLine = (rangeData) => { - if (editorRef.current && typeof editorRef.current.jumpToRange === 'function') { - editorRef.current.jumpToRange(rangeData); - } - }; - async function fetchData() { const url = window.location.search; const gist = "https://gist.githubusercontent.com/"; @@ -127,10 +112,8 @@ export default function Home() { openNotification("error fetching .", "bottomRight"); }); } else { - // ONLY set the fallback if there is absolutely no code in the state yet. - // If localStorage already loaded a draft, we keep it! + // 4. Fallback Protection setSourceCode(prev => (prev && prev !== "") ? prev : FALLBACK_CODE); - setDataFetch(true); if(urlParams.size > 0){ openNotification("The URL contains an invalid parameter.", "bottomRight"); @@ -165,36 +148,18 @@ export default function Home() { setOutput(stdout.join("")); } } - } else if (key == "AST" || key == "ASR") { - const res = (key == "AST") - ? lfortran_funcs.emit_ast_from_source(sourceCode) - : lfortran_funcs.emit_asr_from_source(sourceCode); - if (res) { - const htmlOutput = ansi_up.ansi_to_html(res); - const finalOutput = htmlOutput - .replace(/Declaration/g, - `Declaration` - ) - .replace(/Subroutine/g, - `Subroutine` - ); - setOutput(finalOutput); - } - } else if (key == "WAT" || key == "CPP") { - const res = (key == "WAT") - ? lfortran_funcs.emit_wat_from_source(sourceCode) - : lfortran_funcs.emit_cpp_from_source(sourceCode); - if (res) { - setOutput(ansi_up.ansi_to_html(res)); - } + } else if (key == "AST") { + const res = lfortran_funcs.emit_ast_from_source(sourceCode); + if (res) setOutput(ansi_up.ansi_to_html(res)); + } else if (key == "ASR") { + const res = lfortran_funcs.emit_asr_from_source(sourceCode); + if (res) setOutput(ansi_up.ansi_to_html(res)); + } else if (key == "WAT") { + const res = lfortran_funcs.emit_wat_from_source(sourceCode); + if (res) setOutput(ansi_up.ansi_to_html(res)); + } else if (key == "CPP") { + const res = lfortran_funcs.emit_cpp_from_source(sourceCode); + if (res) setOutput(ansi_up.ansi_to_html(res)); } else if (key == "PY") { setOutput("Support for PY is not yet enabled"); } else { @@ -224,7 +189,6 @@ export default function Home() { activeTab={activeTab} handleUserTabChange={handleUserTabChange} myHeight={myHeight} - editorRef={editorRef} > @@ -235,7 +199,6 @@ export default function Home() { handleUserTabChange={handleUserTabChange} myHeight={myHeight} openNotification={openNotification} - onNodeClick={jumpToEditorLine} > ) : (