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.
This commit is contained in:
Zef Hemel
2025-10-06 17:22:10 +02:00
parent c3a6d7aaaf
commit dde3433b87
5 changed files with 62 additions and 18 deletions
+3 -2
View File
@@ -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<string> {
) {
// 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<string> {
}
} 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"));
+11 -3
View File
@@ -1,6 +1,6 @@
import { LuaTable, luaToString } from "../space_lua/runtime.ts";
export function defaultTransformer(v: any): Promise<string> {
export function defaultTransformer(v: any, k: string): Promise<string> {
if (v === undefined) {
return Promise.resolve("");
}
@@ -13,6 +13,14 @@ export function defaultTransformer(v: any): Promise<string> {
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<string> = defaultTransformer,
valueTransformer: (v: any, k: string) => Promise<string> = defaultTransformer,
): Promise<string> {
const headers = new Set<string>();
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("|") + "|");
+11
View File
@@ -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> | any } = {},
) => {
return jsonToMDTable(data, options.renderCell || refCellTransformer);
},
};
}
@@ -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"
+18 -1
View File
@@ -51,4 +51,21 @@ local tree = markdown.parseMarkdown(text)
local expandedTree = markdown.expandMarkdown(tree)
local rendered = markdown.renderParseTree(expandedTree)
print("Rendered markdown:", rendered)
```
```
### 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})}