From 55a7b8ce93daf53471a49469dcfc151cbffd5a98 Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Sun, 17 Nov 2024 17:21:34 -0500 Subject: [PATCH 1/9] patch over some linter errors iwth codeblock --- lib/com/codeblock.tsx | 70 +++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 74e2c36..d8e7661 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -1,11 +1,10 @@ import { component } from "../model/components.ts"; -import { Node } from "../model/mod.ts"; - +import { Workbench, Context } from "../workbench/mod.ts"; export interface CodeExecutor { // executes the source and returns an output string. // exceptions in execution should be caught and returned as a string. - async execute(source: string, options: ExecuteOptions): string; + execute(source: string, options: ExecuteOptions): Promise; canExecute(options: ExecuteOptions): boolean; } @@ -16,7 +15,10 @@ export interface ExecuteOptions { // defaultExecutor can be replaced with an external service, etc export let defaultExecutor: CodeExecutor = { - async execute(source: string, options: ExecuteOptions): Promise { + async execute( + source: string, + options: ExecuteOptions + ): Promise { if (options.language !== "javascript") { return `Unsupported language: ${options.language}`; } @@ -28,10 +30,8 @@ export let defaultExecutor: CodeExecutor = { return true; } return false; - } -} - - + }, +}; @component export class CodeBlock { @@ -49,7 +49,18 @@ export class CodeBlock { handleIcon(collapsed: boolean = false): any { return ( - + @@ -63,45 +74,52 @@ export class CodeBlock { when: (ctx: Context) => { if (!ctx.node) return false; if (ctx.node.raw.Rel === "Fields") return false; - if (ctx.node.parent && ctx.node.parent.hasComponent(Document)) return false; + if (ctx.node.parent && ctx.node.parent.hasComponent(Document)) + return false; return true; }, action: (ctx: Context) => { const com = new CodeBlock(); - ctx.node.addComponent(com); - ctx.node.changed(); - workbench.workspace.setExpanded(ctx.path.head, ctx.path.node, true); - } + if (ctx?.node) { + ctx.node.addComponent(com); + ctx.node.changed(); + workbench.workspace.setExpanded( + ctx.path.head, + ctx.path.node, + true + ); + } + }, }); } - } - const CodeEditor = { - oncreate({dom, attrs: {path}}) { + oncreate({ dom, attrs: { path } }) { const snippet = path.node.getComponent(CodeBlock); + //@ts-ignore dom.jarEditor = new window.CodeJar(dom, (editor) => { // highlight.js does not trim old tags, // let's do it by this hack. editor.textContent = editor.textContent; + //@ts-ignore window.hljs.highlightBlock(editor); - snippet.language = window.hljs.highlightAuto(editor.textContent).language || ""; + snippet.language = + //@ts-ignore + window.hljs.highlightAuto(editor.textContent).language || ""; }); dom.jarEditor.updateCode(snippet.code); - dom.jarEditor.onUpdate(code => { + dom.jarEditor.onUpdate((code) => { snippet.code = code; path.node.changed(); }); }, - view({attrs: {workbench, path}}) { + view({ attrs: { workbench, path } }) { // this cancels the keydown on the outline node // so you can use arrow keys normally const onkeydown = (e) => e.stopPropagation(); - - return ( -
- ) - } -} \ No newline at end of file + + return
; + }, +}; From c15b88597d39bce7bf9e659af3fcd1e17193e83b Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Sun, 17 Nov 2024 19:01:51 -0500 Subject: [PATCH 2/9] checkpoint on codeblock output --- lib/com/codeblock.tsx | 33 ++++++++++++++++++++++++++++++++- web/static/app/main.css | 20 ++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index d8e7661..6344776 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -44,7 +44,7 @@ export class CodeBlock { } childrenView() { - return CodeEditor; + return CodeEditorOutput; } handleIcon(collapsed: boolean = false): any { @@ -123,3 +123,34 @@ const CodeEditor = { return
; }, }; + +const CodeEditorOutput = { + oncreate({ dom, attrs: { path } }) { + const snippet = path.node.getComponent(CodeBlock); + window.hljs.highlightBlock( + dom.querySelector(".code-editor-output") + ); + + const output = snippet.output; + if (output) { + dom.querySelector("p").innerText = "Output: " + output; + } + dom + .querySelector("button") + .addEventListener("click", async () => { + snippet.output = await defaultExecutor.execute(snippet.code, { + language: snippet.language, + }); + }); + }, + + view: (vnode) => { + return m("div", [ + m(CodeEditor, { path: vnode.attrs.path }), + m("div", { class: "code-editor-output" }, [ + m("p"), + m("button", "Run"), + ]), + ]); + }, +}; diff --git a/web/static/app/main.css b/web/static/app/main.css index 7c61725..ee162cf 100644 --- a/web/static/app/main.css +++ b/web/static/app/main.css @@ -667,20 +667,32 @@ the top nav in a more elegant way at some point*/ /*------------CODE EDITOR------------*/ -.code-editor { - border-radius: 6px; +.code-editor, .code-editor-output { font-family: 'Source Code Pro', monospace; font-size: 14px; font-weight: 400; - height: 340px; letter-spacing: normal; line-height: 20px; padding: 10px; - resize: none !important; tab-size: 4; +} + +.code-editor { + border-top-left-radius: 6px; + border-top-right-radius: 6px; margin-left: -0.5rem; + height: 340px; + resize: none !important; + } .code-editor.hljs { padding: 10px; +} + +.code-editor-output{ + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + margin-left: -8px; + border-top: 1px solid white; } \ No newline at end of file From 59f50ef56eea7ae643997099cbdb4413097b20f7 Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Sun, 17 Nov 2024 23:13:22 -0500 Subject: [PATCH 3/9] 2nd checkpoint on codeblock output --- lib/com/codeblock.tsx | 25 ++++++++++++++++++------- web/static/app/main.css | 8 ++++++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 6344776..10d2111 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -22,7 +22,9 @@ export let defaultExecutor: CodeExecutor = { if (options.language !== "javascript") { return `Unsupported language: ${options.language}`; } - return JSON.stringify(window.eval(source)); + let output = window.eval(source); + //return JSON.stringify(output); + return "j"; }, canExecute(options: ExecuteOptions): boolean { @@ -124,31 +126,40 @@ const CodeEditor = { }, }; + const CodeEditorOutput = { - oncreate({ dom, attrs: { path } }) { + output: "", + oncreate(vnode) { + const { + state, + dom, + attrs: { path }, + } = vnode; const snippet = path.node.getComponent(CodeBlock); window.hljs.highlightBlock( dom.querySelector(".code-editor-output") ); - const output = snippet.output; - if (output) { - dom.querySelector("p").innerText = "Output: " + output; - } dom .querySelector("button") .addEventListener("click", async () => { snippet.output = await defaultExecutor.execute(snippet.code, { language: snippet.language, }); + console.log(snippet.output); + vnode.state.output = snippet.output; }); }, view: (vnode) => { + const output = vnode.state?.output + ? `Output: ${vnode.state.output}` + : ""; + return m("div", [ m(CodeEditor, { path: vnode.attrs.path }), m("div", { class: "code-editor-output" }, [ - m("p"), + m("p", "Output: " + vnode.state.output), m("button", "Run"), ]), ]); diff --git a/web/static/app/main.css b/web/static/app/main.css index ee162cf..a997610 100644 --- a/web/static/app/main.css +++ b/web/static/app/main.css @@ -675,12 +675,12 @@ the top nav in a more elegant way at some point*/ line-height: 20px; padding: 10px; tab-size: 4; + margin-left: -0.5rem; } .code-editor { border-top-left-radius: 6px; border-top-right-radius: 6px; - margin-left: -0.5rem; height: 340px; resize: none !important; @@ -693,6 +693,10 @@ the top nav in a more elegant way at some point*/ .code-editor-output{ border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; - margin-left: -8px; border-top: 1px solid white; + display: flex !important; + justify-content: space-between; + p { + margin: 0; + } } \ No newline at end of file From 65778da19ccb2d729a10f4e4f38459cec720b25c Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Sun, 17 Nov 2024 23:42:31 -0500 Subject: [PATCH 4/9] 3rd cp --- lib/com/codeblock.tsx | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 10d2111..0e16f57 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -39,14 +39,25 @@ export let defaultExecutor: CodeExecutor = { export class CodeBlock { code: string; language: string; + output: string; constructor() { this.code = ""; this.language = ""; + this.output = ""; } childrenView() { - return CodeEditorOutput; + return { + view: (vnode) => { + return [ + m(CodeEditor), + m(CodeEditorOutput, { + output: this.output, + }), + ]; + }, + }; } handleIcon(collapsed: boolean = false): any { @@ -97,7 +108,11 @@ export class CodeBlock { } const CodeEditor = { - oncreate({ dom, attrs: { path } }) { + oncreate(vnode) { + const { + dom, + attrs: { path }, + } = vnode; const snippet = path.node.getComponent(CodeBlock); //@ts-ignore dom.jarEditor = new window.CodeJar(dom, (editor) => { @@ -126,12 +141,10 @@ const CodeEditor = { }, }; - const CodeEditorOutput = { output: "", oncreate(vnode) { const { - state, dom, attrs: { path }, } = vnode; @@ -152,16 +165,12 @@ const CodeEditorOutput = { }, view: (vnode) => { - const output = vnode.state?.output - ? `Output: ${vnode.state.output}` - : ""; - - return m("div", [ - m(CodeEditor, { path: vnode.attrs.path }), - m("div", { class: "code-editor-output" }, [ - m("p", "Output: " + vnode.state.output), - m("button", "Run"), - ]), + return m("div", { class: "code-editor-output" }, [ + m( + "p", + vnode.state.output ? "Output: " + vnode.state.output : "" + ), + m("button", "Run"), ]); }, }; From a59720fd1c0c9771a56cae19a4135717d737334c Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Mon, 18 Nov 2024 00:16:48 -0500 Subject: [PATCH 5/9] checkpoint 4 --- lib/com/codeblock.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 0e16f57..618b4ed 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -51,9 +51,13 @@ export class CodeBlock { return { view: (vnode) => { return [ - m(CodeEditor), + m(CodeEditor, { + path: vnode.attrs.path, + workbench: vnode.attrs.workbench, + }), m(CodeEditorOutput, { output: this.output, + path: vnode.attrs.path, }), ]; }, @@ -149,18 +153,13 @@ const CodeEditorOutput = { attrs: { path }, } = vnode; const snippet = path.node.getComponent(CodeBlock); - window.hljs.highlightBlock( - dom.querySelector(".code-editor-output") - ); + + window.hljs.highlightBlock(dom); dom .querySelector("button") .addEventListener("click", async () => { - snippet.output = await defaultExecutor.execute(snippet.code, { - language: snippet.language, - }); - console.log(snippet.output); - vnode.state.output = snippet.output; + console.log(snippet); }); }, From 47180d516be82743e8ba2f81d04031e8f778aceb Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Mon, 18 Nov 2024 11:45:27 -0500 Subject: [PATCH 6/9] got output working --- lib/com/codeblock.tsx | 60 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 618b4ed..713f898 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -1,6 +1,5 @@ import { component } from "../model/components.ts"; import { Workbench, Context } from "../workbench/mod.ts"; - export interface CodeExecutor { // executes the source and returns an output string. // exceptions in execution should be caught and returned as a string. @@ -24,7 +23,7 @@ export let defaultExecutor: CodeExecutor = { } let output = window.eval(source); //return JSON.stringify(output); - return "j"; + return Math.random().toString(); }, canExecute(options: ExecuteOptions): boolean { @@ -40,11 +39,15 @@ export class CodeBlock { code: string; language: string; output: string; + updateOutput: (output: string) => void; constructor() { this.code = ""; this.language = ""; this.output = ""; + this.updateOutput = (output: string) => { + this.output = output; + }; } childrenView() { @@ -57,6 +60,7 @@ export class CodeBlock { }), m(CodeEditorOutput, { output: this.output, + updateOutput: this.updateOutput, path: vnode.attrs.path, }), ]; @@ -145,31 +149,63 @@ const CodeEditor = { }, }; -const CodeEditorOutput = { - output: "", +class CodeEditorOutput { + constructor(vnode) { + // Initialize output with m.prop() to preserve state across re-renders + this.output = vnode.attrs.output || ""; + this.updateOutput = vnode.attrs.updateOutput || (() => {}); + } + oncreate(vnode) { const { dom, attrs: { path }, } = vnode; + const snippet = path.node.getComponent(CodeBlock); + // Apply syntax highlighting window.hljs.highlightBlock(dom); - dom - .querySelector("button") - .addEventListener("click", async () => { + // Find the button element and add event listener + const button = dom.querySelector("button"); + if (button) { + button.addEventListener("click", async () => { + console.log("Button clicked"); console.log(snippet); + + try { + const res = await defaultExecutor.execute(snippet.code, { + language: snippet.language, + }); + console.log("Execution result:", res); + + // Update output using m.prop to ensure it's persistent across re-renders + this.output = res; // Call m.prop with the new value + console.log("Updated output:", this.output); + this.updateOutput(this.output); // Call the updateOutput function passed as a prop + // Trigger re-render + m.redraw.sync(); + } catch (error) { + console.error("Execution error:", error); + } }); - }, + } else { + console.warn("Button not found"); + } + } + + onupdate() { + console.log("Component updated. Current output:", this.output); // Log the updated output + } - view: (vnode) => { + view() { return m("div", { class: "code-editor-output" }, [ m( "p", - vnode.state.output ? "Output: " + vnode.state.output : "" + this.output ? "Output: " + this.output : "No output yet." ), m("button", "Run"), ]); - }, -}; + } +} From 9b75ccc0f7201556feb8b58aea8b5e18a85b6f78 Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Mon, 18 Nov 2024 13:19:21 -0500 Subject: [PATCH 7/9] got input working, but broke output in the process --- lib/com/codeblock.tsx | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 713f898..35c3b2c 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -51,21 +51,7 @@ export class CodeBlock { } childrenView() { - return { - view: (vnode) => { - return [ - m(CodeEditor, { - path: vnode.attrs.path, - workbench: vnode.attrs.workbench, - }), - m(CodeEditorOutput, { - output: this.output, - updateOutput: this.updateOutput, - path: vnode.attrs.path, - }), - ]; - }, - }; + return CodeEditorWithOutput; } handleIcon(collapsed: boolean = false): any { @@ -149,7 +135,7 @@ const CodeEditor = { }, }; -class CodeEditorOutput { +class Output { constructor(vnode) { // Initialize output with m.prop() to preserve state across re-renders this.output = vnode.attrs.output || ""; @@ -188,6 +174,7 @@ class CodeEditorOutput { m.redraw.sync(); } catch (error) { console.error("Execution error:", error); + this.output = error.toString(); } }); } else { @@ -209,3 +196,9 @@ class CodeEditorOutput { ]); } } + +class CodeEditorWithOutput { + view(vnode) { + return [m(CodeEditor, vnode.attrs), m(Output, vnode.attrs)]; + } +} From 403d28585c07d5734f473759a598ca663d9950e9 Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Mon, 18 Nov 2024 18:21:33 -0500 Subject: [PATCH 8/9] jeff's revisions, got it working --- lib/com/codeblock.tsx | 93 +++++++++++++---------------------------- web/static/app/main.css | 2 + 2 files changed, 30 insertions(+), 65 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 35c3b2c..ffb4358 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -23,7 +23,7 @@ export let defaultExecutor: CodeExecutor = { } let output = window.eval(source); //return JSON.stringify(output); - return Math.random().toString(); + return output.toString(); }, canExecute(options: ExecuteOptions): boolean { @@ -38,16 +38,10 @@ export let defaultExecutor: CodeExecutor = { export class CodeBlock { code: string; language: string; - output: string; - updateOutput: (output: string) => void; constructor() { this.code = ""; this.language = ""; - this.output = ""; - this.updateOutput = (output: string) => { - this.output = output; - }; } childrenView() { @@ -108,6 +102,7 @@ const CodeEditor = { attrs: { path }, } = vnode; const snippet = path.node.getComponent(CodeBlock); + //@ts-ignore dom.jarEditor = new window.CodeJar(dom, (editor) => { // highlight.js does not trim old tags, @@ -135,67 +130,35 @@ const CodeEditor = { }, }; -class Output { - constructor(vnode) { - // Initialize output with m.prop() to preserve state across re-renders - this.output = vnode.attrs.output || ""; - this.updateOutput = vnode.attrs.updateOutput || (() => {}); - } - - oncreate(vnode) { - const { - dom, - attrs: { path }, - } = vnode; +const Output = { + output: "", + view({ dom, attrs: { path } }) { const snippet = path.node.getComponent(CodeBlock); - // Apply syntax highlighting - window.hljs.highlightBlock(dom); - - // Find the button element and add event listener - const button = dom.querySelector("button"); - if (button) { - button.addEventListener("click", async () => { - console.log("Button clicked"); - console.log(snippet); - - try { - const res = await defaultExecutor.execute(snippet.code, { - language: snippet.language, - }); - console.log("Execution result:", res); - - // Update output using m.prop to ensure it's persistent across re-renders - this.output = res; // Call m.prop with the new value - console.log("Updated output:", this.output); - this.updateOutput(this.output); // Call the updateOutput function passed as a prop - // Trigger re-render - m.redraw.sync(); - } catch (error) { - console.error("Execution error:", error); - this.output = error.toString(); - } - }); - } else { - console.warn("Button not found"); - } - } - - onupdate() { - console.log("Component updated. Current output:", this.output); // Log the updated output - } - - view() { - return m("div", { class: "code-editor-output" }, [ - m( - "p", - this.output ? "Output: " + this.output : "No output yet." - ), - m("button", "Run"), - ]); - } -} + let handleClick = async () => { + this.output = "Running..."; + try { + const res = await defaultExecutor.execute(snippet.code, { + language: snippet.language, + }); + + // Update output using m.prop to ensure it's persistent across re-renders + this.output = res; // Call m.prop with the new value + } catch (error) { + this.output = error.toString(); + } + }; + return ( +
+

{this.output ? "Output: " + this.output : ""}

+ +
+ ); + }, +}; class CodeEditorWithOutput { view(vnode) { diff --git a/web/static/app/main.css b/web/static/app/main.css index a997610..d16be50 100644 --- a/web/static/app/main.css +++ b/web/static/app/main.css @@ -691,6 +691,8 @@ the top nav in a more elegant way at some point*/ } .code-editor-output{ + background: #232323; + color: #e6e1dc; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top: 1px solid white; From 48954b2a1e412d9926d3bde91b64a8237918a5f5 Mon Sep 17 00:00:00 2001 From: Levon Ritter Date: Mon, 18 Nov 2024 18:45:12 -0500 Subject: [PATCH 9/9] revised output to be on state --- lib/com/codeblock.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index ffb4358..b18fe8c 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -131,27 +131,25 @@ const CodeEditor = { }; const Output = { - output: "", - - view({ dom, attrs: { path } }) { + view({ dom, state, attrs: { path } }) { const snippet = path.node.getComponent(CodeBlock); let handleClick = async () => { - this.output = "Running..."; + state.output = "Running..."; try { const res = await defaultExecutor.execute(snippet.code, { language: snippet.language, }); // Update output using m.prop to ensure it's persistent across re-renders - this.output = res; // Call m.prop with the new value + state.output = res; // Call m.prop with the new value } catch (error) { - this.output = error.toString(); + state.output = error.toString(); } }; return (
-

{this.output ? "Output: " + this.output : ""}

+

{state.output ? "Output: " + state.output : ""}