diff --git a/lib/com/codeblock.tsx b/lib/com/codeblock.tsx index 74e2c36..b18fe8c 100644 --- a/lib/com/codeblock.tsx +++ b/lib/com/codeblock.tsx @@ -1,11 +1,9 @@ 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,11 +14,16 @@ 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}`; } - return JSON.stringify(window.eval(source)); + let output = window.eval(source); + //return JSON.stringify(output); + return output.toString(); }, canExecute(options: ExecuteOptions): boolean { @@ -28,10 +31,8 @@ export let defaultExecutor: CodeExecutor = { return true; } return false; - } -} - - + }, +}; @component export class CodeBlock { @@ -44,12 +45,23 @@ export class CodeBlock { } childrenView() { - return CodeEditor; + return CodeEditorWithOutput; } handleIcon(collapsed: boolean = false): any { return ( - + @@ -63,45 +75,91 @@ 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(vnode) { + const { + dom, + 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, // 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
; + }, +}; + +const Output = { + view({ dom, state, attrs: { path } }) { + const snippet = path.node.getComponent(CodeBlock); + + let handleClick = async () => { + 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 + state.output = res; // Call m.prop with the new value + } catch (error) { + state.output = error.toString(); + } + }; return ( -
- ) +
+

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

+ +
+ ); + }, +}; + +class CodeEditorWithOutput { + view(vnode) { + return [m(CodeEditor, vnode.attrs), m(Output, vnode.attrs)]; } -} \ No newline at end of file +} diff --git a/web/static/app/main.css b/web/static/app/main.css index 7c61725..d16be50 100644 --- a/web/static/app/main.css +++ b/web/static/app/main.css @@ -667,20 +667,38 @@ 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; margin-left: -0.5rem; } +.code-editor { + border-top-left-radius: 6px; + border-top-right-radius: 6px; + height: 340px; + resize: none !important; + +} + .code-editor.hljs { padding: 10px; +} + +.code-editor-output{ + background: #232323; + color: #e6e1dc; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid white; + display: flex !important; + justify-content: space-between; + p { + margin: 0; + } } \ No newline at end of file