1
0

Code widget refactor

This commit is contained in:
Zef Hemel 2023-10-31 10:33:38 +01:00
parent 4ef857acf4
commit d8318c4ad7
13 changed files with 64 additions and 32 deletions

View File

@ -0,0 +1,10 @@
import type { CodeWidgetContent } from "$sb/types.ts";
import { syscall } from "./syscall.ts";
export function render(
lang: string,
body: string,
pageName: string,
): Promise<CodeWidgetContent> {
return syscall("codeWidget.render", lang, body, pageName);
}

View File

@ -7,3 +7,4 @@ export * as sync from "./sync.ts";
export * as debug from "./debug.ts"; export * as debug from "./debug.ts";
export * as language from "./language.ts"; export * as language from "./language.ts";
export * as handlebars from "./handlebars.ts"; export * as handlebars from "./handlebars.ts";
export * as codeWidget from "./code_widget.ts";

View File

@ -120,6 +120,7 @@ export type ObjectQuery = Omit<Query, "prefix">;
// Code widget stuff // Code widget stuff
export type CodeWidgetCallback = ( export type CodeWidgetCallback = (
bodyText: string, bodyText: string,
pageName: string,
) => Promise<CodeWidgetContent>; ) => Promise<CodeWidgetContent>;
export type CodeWidgetContent = { export type CodeWidgetContent = {

View File

@ -6,7 +6,7 @@ import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
import { extractAttributes } from "$sb/lib/attribute.ts"; import { extractAttributes } from "$sb/lib/attribute.ts";
import { indexObjects } from "./api.ts"; import { indexObjects } from "./api.ts";
type PageObject = ObjectValue< export type PageObject = ObjectValue<
// The base is PageMeta, but we override lastModified to be a string // The base is PageMeta, but we override lastModified to be a string
Omit<PageMeta, "lastModified"> & { Omit<PageMeta, "lastModified"> & {
lastModified: string; // indexing it as a string lastModified: string; // indexing it as a string
@ -14,6 +14,10 @@ type PageObject = ObjectValue<
>; >;
export async function indexPage({ name, tree }: IndexTreeEvent) { export async function indexPage({ name, tree }: IndexTreeEvent) {
if (name.startsWith("_")) {
// Don't index pages starting with _
return;
}
const pageMeta = await space.getPageMeta(name); const pageMeta = await space.getPageMeta(name);
let pageObj: PageObject = { let pageObj: PageObject = {
ref: name, ref: name,

View File

@ -24,7 +24,7 @@ async function init() {
const body = widget.innerText; const body = widget.innerText;
try { try {
const result = await syscall("widget.render", lang, body); const result = await syscall("codeWidget.render", lang, body, pageName);
const iframe = document.createElement("iframe"); const iframe = document.createElement("iframe");
iframe.src = "about:blank"; iframe.src = "about:blank";

View File

@ -5,6 +5,7 @@ import { renderMarkdownToHtml } from "./markdown_render.ts";
export async function markdownContentWidget( export async function markdownContentWidget(
markdownText: string, markdownText: string,
pageName: string,
): Promise<WidgetContent> { ): Promise<WidgetContent> {
// Parse markdown to a ParseTree // Parse markdown to a ParseTree
const mdTree = await markdown.parseMarkdown(markdownText); const mdTree = await markdown.parseMarkdown(markdownText);
@ -12,16 +13,17 @@ export async function markdownContentWidget(
const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true }); const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true });
return { return {
html: await wrapHTML(html), html: await wrapHTML(html),
script: await prepareJS(markdownText), script: await prepareJS(markdownText, pageName),
// And add back the markdown text so we can render it in a different way if desired // And add back the markdown text so we can render it in a different way if desired
markdown: markdownText, markdown: markdownText,
}; };
} }
export async function prepareJS(originalMarkdown: string) { export async function prepareJS(pageName: string, originalMarkdown: string) {
const iframeJS = await asset.readAsset("assets/markdown_widget.js"); const iframeJS = await asset.readAsset("assets/markdown_widget.js");
return ` return `
const panelHtml = ${JSON.stringify(panelHtml)}; const panelHtml = ${JSON.stringify(panelHtml)};
const pageName = ${JSON.stringify(pageName)};
const originalMarkdown = ${JSON.stringify(originalMarkdown)}; const originalMarkdown = ${JSON.stringify(originalMarkdown)};
${iframeJS} ${iframeJS}
`; `;

View File

@ -1,13 +1,15 @@
import type { WidgetContent } from "$sb/app_event.ts"; import type { WidgetContent } from "$sb/app_event.ts";
import { editor, events, language, space, system } from "$sb/syscalls.ts"; import { events, language, space, system } from "$sb/syscalls.ts";
import { parseTreeToAST } from "$sb/lib/tree.ts"; import { parseTreeToAST } from "$sb/lib/tree.ts";
import { astToKvQuery } from "$sb/lib/parse-query.ts"; import { astToKvQuery } from "$sb/lib/parse-query.ts";
import { jsonToMDTable, renderTemplate } from "../directive/util.ts"; import { jsonToMDTable, renderTemplate } from "../directive/util.ts";
import { replaceTemplateVars } from "../template/template.ts"; import { replaceTemplateVars } from "../template/template.ts";
import { parse } from "../../common/markdown_parser/parse_tree.ts";
export async function widget(bodyText: string): Promise<WidgetContent> { export async function widget(
const pageMeta = await space.getPageMeta(await editor.getCurrentPage()); bodyText: string,
pageName: string,
): Promise<WidgetContent> {
const pageMeta = await space.getPageMeta(pageName);
try { try {
const queryAST = parseTreeToAST( const queryAST = parseTreeToAST(

View File

@ -29,9 +29,10 @@ import { DenoKvPrimitives } from "../plugos/lib/deno_kv_primitives.ts";
import { DataStore } from "../plugos/lib/datastore.ts"; import { DataStore } from "../plugos/lib/datastore.ts";
import { dataStoreSyscalls } from "../plugos/syscalls/datastore.ts"; import { dataStoreSyscalls } from "../plugos/syscalls/datastore.ts";
import { DataStoreMQ } from "../plugos/lib/mq.datastore.ts"; import { DataStoreMQ } from "../plugos/lib/mq.datastore.ts";
import { language } from "@codemirror/language";
import { languageSyscalls } from "../common/syscalls/language.ts"; import { languageSyscalls } from "../common/syscalls/language.ts";
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts"; import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
import { codeWidgetSyscalls } from "../web/syscalls/code_widget.ts";
import { CodeWidgetHook } from "../web/hooks/code_widget.ts";
const fileListInterval = 30 * 1000; // 30s const fileListInterval = 30 * 1000; // 30s
@ -72,6 +73,10 @@ export class ServerSystem {
this.system.addHook(new MQHook(this.system, mq)); this.system.addHook(new MQHook(this.system, mq));
const codeWidgetHook = new CodeWidgetHook();
this.system.addHook(codeWidgetHook);
this.spacePrimitives = new EventedSpacePrimitives( this.spacePrimitives = new EventedSpacePrimitives(
new PlugSpacePrimitives( new PlugSpacePrimitives(
this.baseSpacePrimitives, this.baseSpacePrimitives,
@ -94,6 +99,7 @@ export class ServerSystem {
handlebarsSyscalls(), handlebarsSyscalls(),
dataStoreSyscalls(this.ds), dataStoreSyscalls(this.ds),
debugSyscalls(), debugSyscalls(),
codeWidgetSyscalls(codeWidgetHook),
markdownSyscalls(buildMarkdown([])), // Will later be replaced with markdown extensions markdownSyscalls(buildMarkdown([])), // Will later be replaced with markdown extensions
); );

View File

@ -403,7 +403,7 @@ export class Client {
this.eventHook.addLocalListener("file:listed", (fileList: FileMeta[]) => { this.eventHook.addLocalListener("file:listed", (fileList: FileMeta[]) => {
this.ui.viewDispatch({ this.ui.viewDispatch({
type: "pages-listed", type: "pages-listed",
pages: fileList.filter((f) => f.name.endsWith(".md")).map( pages: fileList.filter(this.space.isListedPage).map(
fileMetaToPageMeta, fileMetaToPageMeta,
), ),
}); });

View File

@ -36,7 +36,7 @@ import { DataStore } from "../plugos/lib/datastore.ts";
import { MessageQueue } from "../plugos/lib/mq.ts"; import { MessageQueue } from "../plugos/lib/mq.ts";
import { languageSyscalls } from "../common/syscalls/language.ts"; import { languageSyscalls } from "../common/syscalls/language.ts";
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts"; import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
import { widgetSyscalls } from "./syscalls/widget.ts"; import { codeWidgetSyscalls } from "./syscalls/code_widget.ts";
export class ClientSystem { export class ClientSystem {
commandHook: CommandHook; commandHook: CommandHook;
@ -143,7 +143,7 @@ export class ClientSystem {
assetSyscalls(this.system), assetSyscalls(this.system),
yamlSyscalls(), yamlSyscalls(),
handlebarsSyscalls(), handlebarsSyscalls(),
widgetSyscalls(this.client), codeWidgetSyscalls(this.codeWidgetHook),
languageSyscalls(), languageSyscalls(),
this.client.syncMode this.client.syncMode
// In sync mode handle locally // In sync mode handle locally

View File

@ -27,7 +27,7 @@ class IFrameWidget extends WidgetType {
const iframe = createWidgetSandboxIFrame( const iframe = createWidgetSandboxIFrame(
this.editor, this.editor,
this.bodyText, this.bodyText,
this.codeWidgetCallback(this.bodyText), this.codeWidgetCallback(this.bodyText, this.editor.currentPage!),
(message) => { (message) => {
switch (message.type) { switch (message.type) {
case "blur": case "blur":
@ -38,16 +38,18 @@ class IFrameWidget extends WidgetType {
break; break;
case "reload": case "reload":
this.codeWidgetCallback(this.bodyText).then( this.codeWidgetCallback(this.bodyText, this.editor.currentPage!)
(widgetContent: WidgetContent) => { .then(
iframe.contentWindow!.postMessage({ (widgetContent: WidgetContent) => {
type: "html", iframe.contentWindow!.postMessage({
html: widgetContent.html, type: "html",
script: widgetContent.script, html: widgetContent.html,
theme: document.getElementsByTagName("html")[0].dataset.theme, script: widgetContent.script,
}); theme:
}, document.getElementsByTagName("html")[0].dataset.theme,
); });
},
);
break; break;
} }
}, },

View File

@ -23,9 +23,12 @@ export class CodeWidgetHook implements Hook<CodeWidgetT> {
if (!functionDef.codeWidget) { if (!functionDef.codeWidget) {
continue; continue;
} }
this.codeWidgetCallbacks.set(functionDef.codeWidget, (bodyText) => { this.codeWidgetCallbacks.set(
return plug.invoke(name, [bodyText]); functionDef.codeWidget,
}); (bodyText, pageName) => {
return plug.invoke(name, [bodyText, pageName]);
},
);
} }
} }
} }

View File

@ -1,23 +1,24 @@
import { CodeWidgetContent } from "$sb/types.ts"; import { CodeWidgetContent } from "$sb/types.ts";
import { SysCallMapping } from "../../plugos/system.ts"; import { SysCallMapping } from "../../plugos/system.ts";
import { Client } from "../client.ts"; import { CodeWidgetHook } from "../hooks/code_widget.ts";
export function widgetSyscalls( export function codeWidgetSyscalls(
client: Client, codeWidgetHook: CodeWidgetHook,
): SysCallMapping { ): SysCallMapping {
return { return {
"widget.render": ( "codeWidget.render": (
_ctx, _ctx,
lang: string, lang: string,
body: string, body: string,
pageName: string,
): Promise<CodeWidgetContent> => { ): Promise<CodeWidgetContent> => {
const langCallback = client.system.codeWidgetHook.codeWidgetCallbacks.get( const langCallback = codeWidgetHook.codeWidgetCallbacks.get(
lang, lang,
); );
if (!langCallback) { if (!langCallback) {
throw new Error(`Code widget ${lang} not found`); throw new Error(`Code widget ${lang} not found`);
} }
return langCallback(body); return langCallback(body, pageName);
}, },
}; };
} }