From d8318c4ad77dc5a4d0d24f1e8473bce8da1c3554 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Tue, 31 Oct 2023 10:33:38 +0100 Subject: [PATCH] Code widget refactor --- plug-api/silverbullet-syscall/code_widget.ts | 10 ++++++++ plug-api/silverbullet-syscall/mod.ts | 1 + plug-api/types.ts | 1 + plugs/index/page.ts | 6 ++++- plugs/markdown/assets/markdown_widget.js | 2 +- plugs/markdown/markdown_content_widget.ts | 6 +++-- plugs/query/query.ts | 10 ++++---- server/server_system.ts | 8 ++++++- web/client.ts | 2 +- web/client_system.ts | 4 ++-- web/cm_plugins/fenced_code.ts | 24 +++++++++++--------- web/hooks/code_widget.ts | 9 +++++--- web/syscalls/{widget.ts => code_widget.ts} | 13 ++++++----- 13 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 plug-api/silverbullet-syscall/code_widget.ts rename web/syscalls/{widget.ts => code_widget.ts} (55%) diff --git a/plug-api/silverbullet-syscall/code_widget.ts b/plug-api/silverbullet-syscall/code_widget.ts new file mode 100644 index 00000000..87f83826 --- /dev/null +++ b/plug-api/silverbullet-syscall/code_widget.ts @@ -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 { + return syscall("codeWidget.render", lang, body, pageName); +} diff --git a/plug-api/silverbullet-syscall/mod.ts b/plug-api/silverbullet-syscall/mod.ts index 5f740884..f1ab19df 100644 --- a/plug-api/silverbullet-syscall/mod.ts +++ b/plug-api/silverbullet-syscall/mod.ts @@ -7,3 +7,4 @@ export * as sync from "./sync.ts"; export * as debug from "./debug.ts"; export * as language from "./language.ts"; export * as handlebars from "./handlebars.ts"; +export * as codeWidget from "./code_widget.ts"; diff --git a/plug-api/types.ts b/plug-api/types.ts index 5822d3ac..ad5020de 100644 --- a/plug-api/types.ts +++ b/plug-api/types.ts @@ -120,6 +120,7 @@ export type ObjectQuery = Omit; // Code widget stuff export type CodeWidgetCallback = ( bodyText: string, + pageName: string, ) => Promise; export type CodeWidgetContent = { diff --git a/plugs/index/page.ts b/plugs/index/page.ts index 002dbf28..b5ff6c4e 100644 --- a/plugs/index/page.ts +++ b/plugs/index/page.ts @@ -6,7 +6,7 @@ import { extractFrontmatter } from "$sb/lib/frontmatter.ts"; import { extractAttributes } from "$sb/lib/attribute.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 Omit & { lastModified: string; // indexing it as a string @@ -14,6 +14,10 @@ type PageObject = ObjectValue< >; export async function indexPage({ name, tree }: IndexTreeEvent) { + if (name.startsWith("_")) { + // Don't index pages starting with _ + return; + } const pageMeta = await space.getPageMeta(name); let pageObj: PageObject = { ref: name, diff --git a/plugs/markdown/assets/markdown_widget.js b/plugs/markdown/assets/markdown_widget.js index 7f885b2c..7d864201 100644 --- a/plugs/markdown/assets/markdown_widget.js +++ b/plugs/markdown/assets/markdown_widget.js @@ -24,7 +24,7 @@ async function init() { const body = widget.innerText; try { - const result = await syscall("widget.render", lang, body); + const result = await syscall("codeWidget.render", lang, body, pageName); const iframe = document.createElement("iframe"); iframe.src = "about:blank"; diff --git a/plugs/markdown/markdown_content_widget.ts b/plugs/markdown/markdown_content_widget.ts index 9ebc1f56..0c7b34f3 100644 --- a/plugs/markdown/markdown_content_widget.ts +++ b/plugs/markdown/markdown_content_widget.ts @@ -5,6 +5,7 @@ import { renderMarkdownToHtml } from "./markdown_render.ts"; export async function markdownContentWidget( markdownText: string, + pageName: string, ): Promise { // Parse markdown to a ParseTree const mdTree = await markdown.parseMarkdown(markdownText); @@ -12,16 +13,17 @@ export async function markdownContentWidget( const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true }); return { 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 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"); return ` const panelHtml = ${JSON.stringify(panelHtml)}; + const pageName = ${JSON.stringify(pageName)}; const originalMarkdown = ${JSON.stringify(originalMarkdown)}; ${iframeJS} `; diff --git a/plugs/query/query.ts b/plugs/query/query.ts index 1691660c..5fc4b4a7 100644 --- a/plugs/query/query.ts +++ b/plugs/query/query.ts @@ -1,13 +1,15 @@ 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 { astToKvQuery } from "$sb/lib/parse-query.ts"; import { jsonToMDTable, renderTemplate } from "../directive/util.ts"; import { replaceTemplateVars } from "../template/template.ts"; -import { parse } from "../../common/markdown_parser/parse_tree.ts"; -export async function widget(bodyText: string): Promise { - const pageMeta = await space.getPageMeta(await editor.getCurrentPage()); +export async function widget( + bodyText: string, + pageName: string, +): Promise { + const pageMeta = await space.getPageMeta(pageName); try { const queryAST = parseTreeToAST( diff --git a/server/server_system.ts b/server/server_system.ts index 4981ccf5..7e5b93c5 100644 --- a/server/server_system.ts +++ b/server/server_system.ts @@ -29,9 +29,10 @@ import { DenoKvPrimitives } from "../plugos/lib/deno_kv_primitives.ts"; import { DataStore } from "../plugos/lib/datastore.ts"; import { dataStoreSyscalls } from "../plugos/syscalls/datastore.ts"; import { DataStoreMQ } from "../plugos/lib/mq.datastore.ts"; -import { language } from "@codemirror/language"; import { languageSyscalls } from "../common/syscalls/language.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 @@ -72,6 +73,10 @@ export class ServerSystem { this.system.addHook(new MQHook(this.system, mq)); + const codeWidgetHook = new CodeWidgetHook(); + + this.system.addHook(codeWidgetHook); + this.spacePrimitives = new EventedSpacePrimitives( new PlugSpacePrimitives( this.baseSpacePrimitives, @@ -94,6 +99,7 @@ export class ServerSystem { handlebarsSyscalls(), dataStoreSyscalls(this.ds), debugSyscalls(), + codeWidgetSyscalls(codeWidgetHook), markdownSyscalls(buildMarkdown([])), // Will later be replaced with markdown extensions ); diff --git a/web/client.ts b/web/client.ts index 7a3cb693..0ecbc3cd 100644 --- a/web/client.ts +++ b/web/client.ts @@ -403,7 +403,7 @@ export class Client { this.eventHook.addLocalListener("file:listed", (fileList: FileMeta[]) => { this.ui.viewDispatch({ type: "pages-listed", - pages: fileList.filter((f) => f.name.endsWith(".md")).map( + pages: fileList.filter(this.space.isListedPage).map( fileMetaToPageMeta, ), }); diff --git a/web/client_system.ts b/web/client_system.ts index aa3f3e79..9f0918ee 100644 --- a/web/client_system.ts +++ b/web/client_system.ts @@ -36,7 +36,7 @@ import { DataStore } from "../plugos/lib/datastore.ts"; import { MessageQueue } from "../plugos/lib/mq.ts"; import { languageSyscalls } from "../common/syscalls/language.ts"; import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts"; -import { widgetSyscalls } from "./syscalls/widget.ts"; +import { codeWidgetSyscalls } from "./syscalls/code_widget.ts"; export class ClientSystem { commandHook: CommandHook; @@ -143,7 +143,7 @@ export class ClientSystem { assetSyscalls(this.system), yamlSyscalls(), handlebarsSyscalls(), - widgetSyscalls(this.client), + codeWidgetSyscalls(this.codeWidgetHook), languageSyscalls(), this.client.syncMode // In sync mode handle locally diff --git a/web/cm_plugins/fenced_code.ts b/web/cm_plugins/fenced_code.ts index 1c3b2e55..9b2fa4c7 100644 --- a/web/cm_plugins/fenced_code.ts +++ b/web/cm_plugins/fenced_code.ts @@ -27,7 +27,7 @@ class IFrameWidget extends WidgetType { const iframe = createWidgetSandboxIFrame( this.editor, this.bodyText, - this.codeWidgetCallback(this.bodyText), + this.codeWidgetCallback(this.bodyText, this.editor.currentPage!), (message) => { switch (message.type) { case "blur": @@ -38,16 +38,18 @@ class IFrameWidget extends WidgetType { break; case "reload": - this.codeWidgetCallback(this.bodyText).then( - (widgetContent: WidgetContent) => { - iframe.contentWindow!.postMessage({ - type: "html", - html: widgetContent.html, - script: widgetContent.script, - theme: document.getElementsByTagName("html")[0].dataset.theme, - }); - }, - ); + this.codeWidgetCallback(this.bodyText, this.editor.currentPage!) + .then( + (widgetContent: WidgetContent) => { + iframe.contentWindow!.postMessage({ + type: "html", + html: widgetContent.html, + script: widgetContent.script, + theme: + document.getElementsByTagName("html")[0].dataset.theme, + }); + }, + ); break; } }, diff --git a/web/hooks/code_widget.ts b/web/hooks/code_widget.ts index 6f9e17af..c4da4194 100644 --- a/web/hooks/code_widget.ts +++ b/web/hooks/code_widget.ts @@ -23,9 +23,12 @@ export class CodeWidgetHook implements Hook { if (!functionDef.codeWidget) { continue; } - this.codeWidgetCallbacks.set(functionDef.codeWidget, (bodyText) => { - return plug.invoke(name, [bodyText]); - }); + this.codeWidgetCallbacks.set( + functionDef.codeWidget, + (bodyText, pageName) => { + return plug.invoke(name, [bodyText, pageName]); + }, + ); } } } diff --git a/web/syscalls/widget.ts b/web/syscalls/code_widget.ts similarity index 55% rename from web/syscalls/widget.ts rename to web/syscalls/code_widget.ts index badfbc4b..1cb34e9c 100644 --- a/web/syscalls/widget.ts +++ b/web/syscalls/code_widget.ts @@ -1,23 +1,24 @@ import { CodeWidgetContent } from "$sb/types.ts"; import { SysCallMapping } from "../../plugos/system.ts"; -import { Client } from "../client.ts"; +import { CodeWidgetHook } from "../hooks/code_widget.ts"; -export function widgetSyscalls( - client: Client, +export function codeWidgetSyscalls( + codeWidgetHook: CodeWidgetHook, ): SysCallMapping { return { - "widget.render": ( + "codeWidget.render": ( _ctx, lang: string, body: string, + pageName: string, ): Promise => { - const langCallback = client.system.codeWidgetHook.codeWidgetCallbacks.get( + const langCallback = codeWidgetHook.codeWidgetCallbacks.get( lang, ); if (!langCallback) { throw new Error(`Code widget ${lang} not found`); } - return langCallback(body); + return langCallback(body, pageName); }, }; }