Lua: inline directives improvements

pull/1110/head
Zef Hemel 2024-10-07 19:17:12 +02:00
parent 6c71862641
commit f74bab0aca
4 changed files with 61 additions and 86 deletions

View File

@ -1,4 +1,8 @@
import { clientStore, editor } from "@silverbulletmd/silverbullet/syscalls";
import {
clientStore,
codeWidget,
editor,
} from "@silverbulletmd/silverbullet/syscalls";
// Run on "editor:init"
export async function setEditorMode() {
@ -79,7 +83,8 @@ export async function customFlashMessage(_def: any, message: string) {
export async function reloadSystem() {
await editor.save();
await editor.reloadConfigAndCommands();
await editor.flashNotification("Reloaded system");
await codeWidget.refreshAll();
await editor.flashNotification("System and widgets reloaded!");
}
export async function findInPageCommand() {

View File

@ -1,6 +1,6 @@
import type { EditorState, Range } from "@codemirror/state";
import { syntaxTree } from "@codemirror/language";
import { Decoration, WidgetType } from "@codemirror/view";
import { Decoration } from "@codemirror/view";
import {
decoratorStateField,
invisibleDecoration,
@ -14,79 +14,7 @@ import type {
LuaFunctionCallStatement,
} from "$common/space_lua/ast.ts";
import { evalExpression } from "$common/space_lua/eval.ts";
import { luaToString } from "$common/space_lua/runtime.ts";
import { parse as parseMarkdown } from "$common/markdown_parser/parse_tree.ts";
import { extendedMarkdownLanguage } from "$common/markdown_parser/parser.ts";
import { renderMarkdownToHtml } from "../../plugs/markdown/markdown_render.ts";
import {
isLocalPath,
resolvePath,
} from "@silverbulletmd/silverbullet/lib/resolve";
class LuaDirectiveWidget extends WidgetType {
constructor(
readonly code: string,
private client: Client,
) {
super();
}
eq(other: LuaDirectiveWidget) {
return other.code === this.code;
}
// get estimatedHeight(): number {
// const cachedHeight = this.client.getCachedWidgetHeight(
// `content:${this.url}`,
// );
// return cachedHeight;
// }
toDOM() {
const span = document.createElement("span");
span.className = "sb-lua-directive";
try {
const parsedLua = parseLua(`_(${this.code})`) as LuaBlock;
const expr =
(parsedLua.statements[0] as LuaFunctionCallStatement).call.args[0];
Promise.resolve(evalExpression(expr, client.clientSystem.spaceLuaEnv.env))
.then((result) => {
const mdTree = parseMarkdown(
extendedMarkdownLanguage,
luaToString(result),
);
const html = renderMarkdownToHtml(mdTree, {
// Annotate every element with its position so we can use it to put
// the cursor there when the user clicks on the table.
annotationPositions: true,
translateUrls: (url) => {
if (isLocalPath(url)) {
url = resolvePath(
this.client.currentPage,
decodeURI(url),
);
}
return url;
},
preserveAttributes: true,
}, this.client.ui.viewState.allPages);
span.innerHTML = html;
}).catch((e) => {
console.error("Lua eval error", e);
span.innerText = `Lua error: ${e.message}`;
});
} catch (e: any) {
console.error("Lua parser error", e);
span.innerText = `Lua error: ${e.message}`;
}
span.innerText = "...";
return span;
}
}
import { MarkdownWidget } from "./markdown_widget.ts";
export function luaDirectivePlugin(client: Client) {
return decoratorStateField((state: EditorState) => {
@ -110,7 +38,35 @@ export function luaDirectivePlugin(client: Client) {
widgets.push(
Decoration.widget({
widget: new LuaDirectiveWidget(text, client),
widget: new MarkdownWidget(
node.from,
client,
`lua:${text}`,
text,
async (bodyText) => {
try {
const parsedLua = parseLua(`_(${bodyText})`) as LuaBlock;
const expr =
(parsedLua.statements[0] as LuaFunctionCallStatement).call
.args[0];
const result = await evalExpression(
expr,
client.clientSystem.spaceLuaEnv.env,
);
return {
markdown: "" + result,
};
} catch (e: any) {
console.error("Lua eval error", e);
return {
markdown: `**Lua error:** ${e.message}`,
};
}
},
"sb-lua-directive",
true,
),
}).range(node.to),
);
widgets.push(invisibleDecoration.range(node.from, node.to));

View File

@ -27,6 +27,7 @@ export class MarkdownWidget extends WidgetType {
readonly bodyText: string,
readonly codeWidgetCallback: CodeWidgetCallback,
readonly className: string,
private tryInline = false,
) {
super();
}
@ -91,6 +92,15 @@ export class MarkdownWidget extends WidgetType {
return;
}
if (this.tryInline) {
if (trimmedMarkdown.includes("\n")) {
// Heuristic that this is going to be a multi-line output and we should render this as a HTML block
div.style.display = "block";
} else {
div.style.display = "inline";
}
}
// Parse the markdown again after trimming
mdTree = parse(
extendedMarkdownLanguage,
@ -152,12 +162,16 @@ export class MarkdownWidget extends WidgetType {
if (!html) {
return "";
}
if (buttons.length === 0) {
return html;
} else {
return `<div class="button-bar">${
buttons.filter((button) => !button.widgetTarget).map((button, idx) =>
`<button data-button="${idx}" title="${button.description}">${button.svg}</button> `
).join("")
}</div><div class="content">${html}</div>`;
}
}
private attachListeners(div: HTMLElement, buttons?: CodeWidgetButton[]) {
div.addEventListener("mousedown", (e) => {

View File

@ -331,13 +331,13 @@
}
.sb-lua-directive {
background-color: rgba(151, 151, 151, 0.1);
border: 1px solid #dfdcdc;
border-radius: 5px;
background-color: rgb(233, 232, 232, 35%);
border: 1px #d3d3d373 solid;
/* box-shadow: #d1d1d1 0 0 4px; */
border-radius: 8px;
padding: 2px;
}
a.sb-wiki-link-page-missing,
.sb-wiki-link-page-missing>.sb-wiki-link-page {
border-radius: 5px;