silverbullet/web/cm_plugins/lua_directive.ts

92 lines
2.9 KiB
TypeScript
Raw Normal View History

import type { EditorState, Range } from "@codemirror/state";
import { syntaxTree } from "@codemirror/language";
2024-10-08 01:17:12 +08:00
import { Decoration } from "@codemirror/view";
import {
decoratorStateField,
invisibleDecoration,
isCursorInRange,
shouldRenderWidgets,
} from "./util.ts";
import type { Client } from "../client.ts";
2024-10-07 15:08:36 +08:00
import { parse as parseLua } from "$common/space_lua/parse.ts";
2024-10-05 21:38:28 +08:00
import type {
LuaBlock,
LuaFunctionCallStatement,
} from "$common/space_lua/ast.ts";
import { evalExpression } from "$common/space_lua/eval.ts";
2024-10-13 21:14:22 +08:00
import { luaValueToJS } from "$common/space_lua/runtime.ts";
2024-10-09 01:53:09 +08:00
import { LuaRuntimeError } from "$common/space_lua/runtime.ts";
import { encodePageRef } from "@silverbulletmd/silverbullet/lib/page_ref";
import { resolveASTReference } from "$common/space_lua.ts";
2024-10-13 21:14:22 +08:00
import { LuaWidget } from "./lua_widget.ts";
export function luaDirectivePlugin(client: Client) {
return decoratorStateField((state: EditorState) => {
const widgets: Range<Decoration>[] = [];
if (!shouldRenderWidgets(client)) {
console.info("Not rendering widgets");
return Decoration.set([]);
}
syntaxTree(state).iterate({
enter: (node) => {
if (node.name !== "LuaDirective") {
return;
}
if (isCursorInRange(state, [node.from, node.to])) {
return;
}
const text = state.sliceDoc(node.from + 2, node.to - 1);
widgets.push(
Decoration.widget({
2024-10-13 21:14:22 +08:00
widget: new LuaWidget(
2024-10-08 01:17:12 +08:00
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];
2024-10-13 21:14:22 +08:00
return luaValueToJS(
await evalExpression(
expr,
client.clientSystem.spaceLuaEnv.env,
),
2024-10-08 01:17:12 +08:00
);
} catch (e: any) {
2024-10-09 01:53:09 +08:00
if (e instanceof LuaRuntimeError) {
if (e.context.ref) {
const source = resolveASTReference(e.context);
if (source) {
// We know the origin node of the error, let's reference it
return {
markdown: `**Lua error:** ${e.message} (Origin: [[${
encodePageRef(source)
}]])`,
};
}
}
}
2024-10-08 01:17:12 +08:00
return {
markdown: `**Lua error:** ${e.message}`,
};
}
},
),
}).range(node.to),
);
widgets.push(invisibleDecoration.range(node.from, node.to));
},
});
return Decoration.set(widgets, true);
});
}