diff --git a/app.js b/app.js
index b540b32..cf25363 100644
--- a/app.js
+++ b/app.js
@@ -230,9 +230,17 @@ function setupUI() {
const btn = e.target.closest("button");
if (!btn) return;
if (handleBlockAction(btn)) return;
+ const prog = $id("main-program");
if (btn.dataset.action === "add-section" && typeof enterSectionCreateMode === "function") {
enterSectionCreateMode();
}
+ if (btn.dataset.action === "generate") prog.generateAndDownload();
+ if (btn.dataset.action === "save") saveWorkspace();
+ if (btn.dataset.action === "load") loadWorkspace();
+ if (btn.dataset.action === "new") newWorkspace();
+ if (btn.dataset.action === "run-tests") {
+ if (window.APP_TEST_SUITE) APP_TEST_SUITE.run();
+ }
});
}
@@ -340,25 +348,6 @@ function setupUI() {
});
}
- /* Global toolbar */
- const globalToolbar = document.querySelector(".global-toolbar");
- if (globalToolbar) {
- globalToolbar.addEventListener("click", e => {
- const btn = e.target.closest("button");
- if (!btn) return;
- const prog = $id("main-program");
- if (!prog) { showError("Main program element not found"); return; }
- if (btn.dataset.action === "generate") prog.generateCode();
- if (btn.dataset.action === "save") saveWorkspace();
- if (btn.dataset.action === "load") loadWorkspace();
- if (btn.dataset.action === "new") newWorkspace();
- if (btn.dataset.action === "copy-code") copyCode();
- if (btn.dataset.action === "run-tests") {
- if (window.APP_TEST_SUITE) APP_TEST_SUITE.run();
- }
- });
- }
-
/* Tab bar */
const tabBar = document.querySelector(".tab-bar");
if (tabBar) {
diff --git a/helpers.js b/helpers.js
index d945830..82cd5a9 100644
--- a/helpers.js
+++ b/helpers.js
@@ -232,11 +232,6 @@ function findDataSource(hook) {
}
/** Copies the generated C code text to the clipboard. */
-function copyCode() {
- const el = $id("ir-code");
- if (el && el.textContent) navigator.clipboard.writeText(el.textContent).catch(() => {});
-}
-
/**
* Escapes special characters for embedding in a C string literal.
* Handles backslash, double-quote, newline, carriage return, and tab.
diff --git a/index.html b/index.html
index 42326a3..3e85c94 100644
--- a/index.html
+++ b/index.html
@@ -374,6 +374,12 @@
+
+
+
+
+
+
-
-
+
×
diff --git a/style.css b/style.css
index 34c14c1..f7fcdb0 100644
--- a/style.css
+++ b/style.css
@@ -46,6 +46,12 @@ h1 {
flex-shrink: 0; flex-wrap: wrap;
background: var(--surface); border-bottom: 1px solid var(--border);
}
+.pane-toolbar button.action-btn {
+ padding: 0.3rem 0.6rem; font-size: 0.78rem; font-weight: 500;
+ background: var(--accent); color: #fff; border: 1px solid var(--accent);
+ line-height: 1.2;
+}
+.pane-toolbar button.action-btn:hover { background: #357abd; border-color: #357abd; }
.pane-toolbar button {
padding: 0.3rem; font: inherit; font-size: 0.75rem; cursor: pointer;
background: var(--bg); color: var(--text); border: 1px solid var(--border);
@@ -463,31 +469,7 @@ wc-assign #hook-next[data-direction="out"] {
flex-direction: column;
}
-.global-toolbar {
- display: flex; gap: 0.25rem; padding: 0.3rem;
- align-items: flex-start; flex-shrink: 0;
- border-top: 1px solid var(--border); background: var(--surface);
-}
-.global-toolbar button {
- padding: 0.4rem 0.8rem; font: inherit; font-size: 0.8rem; cursor: pointer;
- background: var(--accent); color: #fff; border: none; border-radius: 3px;
-}
-.global-toolbar button:hover { background: #357abd; }
-.global-toolbar .code-output {
- flex: 1; min-height: 80px; max-height: 50vh; overflow: auto; resize: vertical;
- background: var(--bg); border: 1px solid var(--border);
- font-family: 'Courier New', monospace; font-size: 0.8rem; line-height: 1.5;
- padding: 0.3rem; position: relative;
-}
-.global-toolbar .code-output pre {
- margin: 0; white-space: pre; tab-size: 4;
-}
-.global-toolbar .code-output code {
- display: block;
-}
-.global-toolbar .code-output code.hljs {
- background: transparent; padding: 0;
-}
+
[data-block] {
diff --git a/wcprogram.js b/wcprogram.js
index 300fa28..ee5f6cb 100644
--- a/wcprogram.js
+++ b/wcprogram.js
@@ -208,12 +208,8 @@ class WCProgram extends HTMLElement {
return lines.join("\n");
}
- generateCode() {
- const outputEl = $id("ir-code");
- if (!outputEl) { showError("Missing #ir-code output element"); return; }
-
+ _generateIR() {
const { usedQuantities, usedUnits } = this._gatherUsedTypes();
-
const typeDefs = this._generateTypeDefs(usedQuantities);
const unitDefs = this._generateUnitDefs(usedUnits);
const { boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs } = this._generateVariableDeclarations();
@@ -225,24 +221,32 @@ class WCProgram extends HTMLElement {
? CodeGen.emitFlat(firstChild)
: "; no flowchart body\n";
- // Collect external function declarations from used libraries
const proccalls = this.querySelectorAll("wc-proccall");
const decls = this._generateLLVMDecls(proccalls);
- // Collect string globals
const strPool = CodeGen.getStringPool();
const globals = strPool.map(function (_, i) { return CodeGen.stringGlobal(i); }).join("\n");
- // Variable declarations -> alloca instructions in the prologue
const dataSection = (boolDefs || scalarDefs || vectorDefs || stringDefs || arrayDefs)
? [boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs]
.filter(Boolean).map(function (s) { return s + "\n"; }).join("")
: "";
- const raw = CodeGen.generateIRFile(firstChild, decls, globals, dataSection);
- outputEl.textContent = raw;
- if (typeof hljs !== "undefined") hljs.highlightElement(outputEl);
- outputEl.parentElement.dataset.language = "llvm";
+ return CodeGen.generateIRFile(firstChild, decls, globals, dataSection);
+ }
+
+ generateAndDownload() {
+ const ir = this._generateIR();
+ if (!ir) { showError("No IR to download"); return; }
+ const blob = new Blob([ir], { type: "text/plain" });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = "program.ll";
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
}
}