From dde3433b87f907ae815c9ff17e02a9eb64e55cef Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Mon, 6 Oct 2025 17:22:10 +0200 Subject: [PATCH] Some tag page improvements: * More efficient * Now also exposes data objects New markdown.objectToTable syscall to turn a list of objects into a markdown table. --- client/codemirror/lua_widget.ts | 5 +-- client/markdown_renderer/result_render.ts | 14 +++++++-- client/plugos/syscalls/markdown.ts | 11 +++++++ .../Library/Std/Infrastructure/Tag Page.md | 31 ++++++++++++------- website/API/markdown.md | 19 +++++++++++- 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/client/codemirror/lua_widget.ts b/client/codemirror/lua_widget.ts index bd2dd259..085ee5ae 100644 --- a/client/codemirror/lua_widget.ts +++ b/client/codemirror/lua_widget.ts @@ -17,6 +17,7 @@ import { LuaStackFrame, LuaTable } from "../space_lua/runtime.ts"; import { isBlockMarkdown, jsonToMDTable, + refCellTransformer, } from "../markdown_renderer/result_render.ts"; import { activeWidgets } from "./code_widget.ts"; @@ -323,7 +324,7 @@ export function renderExpressionResult(result: any): Promise { ) { // If result is an array of objects, render as a markdown table try { - return jsonToMDTable(result); + return jsonToMDTable(result, refCellTransformer); } catch (e: any) { console.error( `Error rendering expression directive: ${e.message} for value ${ @@ -334,7 +335,7 @@ export function renderExpressionResult(result: any): Promise { } } else if (typeof result === "object" && result.constructor === Object) { // if result is a plain object, render as a markdown table - return jsonToMDTable([result]); + return jsonToMDTable([result], refCellTransformer); } else if (Array.isArray(result)) { // Not-object array, let's render it as a markdown list return Promise.resolve(result.map((item) => `- ${item}`).join("\n")); diff --git a/client/markdown_renderer/result_render.ts b/client/markdown_renderer/result_render.ts index 7171ea5a..1ddcfdc4 100644 --- a/client/markdown_renderer/result_render.ts +++ b/client/markdown_renderer/result_render.ts @@ -1,6 +1,6 @@ import { LuaTable, luaToString } from "../space_lua/runtime.ts"; -export function defaultTransformer(v: any): Promise { +export function defaultTransformer(v: any, k: string): Promise { if (v === undefined) { return Promise.resolve(""); } @@ -13,6 +13,14 @@ export function defaultTransformer(v: any): Promise { return Promise.resolve("" + v); } +export function refCellTransformer(v: any, k: string) { + if (k === "ref") { + return Promise.resolve(`[[${v}]]`); + } else { + return defaultTransformer(v, k); + } +} + /** * Escapes all pipes that would inadvertently delimit a markdown table column. * Does not escape columns that are used for aliasing in WikiLinks or Commands: @@ -51,7 +59,7 @@ function escapeRegularPipes(s: string) { // Nicely format an array of JSON objects as a Markdown table export async function jsonToMDTable( jsonArray: any[], - valueTransformer: (v: any) => Promise = defaultTransformer, + valueTransformer: (v: any, k: string) => Promise = defaultTransformer, ): Promise { const headers = new Set(); for (const entry of jsonArray) { @@ -86,7 +94,7 @@ export async function jsonToMDTable( for (const val of jsonArray) { const el = []; for (const prop of headerList) { - const s = await valueTransformer(val[prop]); + const s = await valueTransformer(val[prop], prop); el.push(s); } lines.push("|" + el.join("|") + "|"); diff --git a/client/plugos/syscalls/markdown.ts b/client/plugos/syscalls/markdown.ts index c9004d0c..d6fbcb4a 100644 --- a/client/plugos/syscalls/markdown.ts +++ b/client/plugos/syscalls/markdown.ts @@ -12,6 +12,10 @@ import { type MarkdownRenderOptions, renderMarkdownToHtml, } from "../../markdown_renderer/markdown_render.ts"; +import { + jsonToMDTable, + refCellTransformer, +} from "../../markdown_renderer/result_render.ts"; export function markdownSyscalls(client: Client): SysCallMapping { return { @@ -41,5 +45,12 @@ export function markdownSyscalls(client: Client): SysCallMapping { const mdTree = parse(extendedMarkdownLanguage, text); return renderMarkdownToHtml(mdTree, options); }, + "markdown.objectsToTable": ( + _ctx, + data: any[], + options: { renderCell?: (val: any, key) => Promise | any } = {}, + ) => { + return jsonToMDTable(data, options.renderCell || refCellTransformer); + }, }; } diff --git a/libraries/Library/Std/Infrastructure/Tag Page.md b/libraries/Library/Std/Infrastructure/Tag Page.md index 1ba10d43..322cdf51 100644 --- a/libraries/Library/Std/Infrastructure/Tag Page.md +++ b/libraries/Library/Std/Infrastructure/Tag Page.md @@ -16,37 +16,44 @@ pageEventHandlers.tagPage = function(e) -- Extract the tag name from the page name local tagName = e.data.name:sub(#"tag:" + 1) local text = "# Objects tagged with " .. tagName .. "\n" - local taggedPages = query[[ - from index.tag "page" + local allObjects = query[[ + from index.tag(tagName) order by ref - where table.includes(_.tags, tagName) + ]] + local taggedPages = query[[ + from allObjects where table.includes(_.itags, "page") ]] if #taggedPages > 0 then text = text .. "## Pages\n" .. template.each(taggedPages, templates.pageItem) end local taggedTasks = query[[ - from index.tag "task" - order by ref - where table.includes(_.tags, tagName) + from allObjects where table.includes(_.itags, "task") ]] if #taggedTasks > 0 then text = text .. "## Tasks\n" .. template.each(taggedTasks, templates.taskItem) end local taggedItems = query[[ - from index.tag "item" - order by ref - where table.includes(_.tags, tagName) + from allObjects where table.includes(_.itags, "item") ]] if #taggedItems > 0 then text = text .. "## Items\n" .. template.each(taggedItems, templates.itemItem) end + local taggedData = query[[ + from allObjects where table.includes(_.itags, "data") + ]] + if #taggedData > 0 then + text = text .. "## Data\n" + .. markdown.objectsToTable(taggedData) .. "\n" + end + if #taggedItems > 0 then + text = text .. "## Items\n" + .. template.each(taggedItems, templates.itemItem) + end local taggedParagraphs = query[[ - from index.tag "paragraph" - order by ref - where table.includes(_.tags, tagName) + from allObjects where table.includes(_.itags, "paragraph") ]] if #taggedParagraphs > 0 then text = text .. "## Paragraphs\n" diff --git a/website/API/markdown.md b/website/API/markdown.md index 0998f65d..f3999142 100644 --- a/website/API/markdown.md +++ b/website/API/markdown.md @@ -51,4 +51,21 @@ local tree = markdown.parseMarkdown(text) local expandedTree = markdown.expandMarkdown(tree) local rendered = markdown.renderParseTree(expandedTree) print("Rendered markdown:", rendered) -``` \ No newline at end of file +``` + +### markdown.objectsToTable(data, options?) +Transforms a list of tables into a markdown table. + +Supported options: +* `renderCell(val, key)` custom cell renderer + +Example: +${markdown.objectsToTable({{name="Pete", age=20}, {name="Jane", age=32}}, { + renderCell=function(v, k) + if k == "age" and v > 20 then + return "*" .. v .. "*" + else + return v + end +end})} +