Files
plainleaf/web/space_lua_api.ts
T
Zef HemelandGitHub dc2987a3f9 Sync engine rearchitecture (#1516)
* Don't require auth for .ping
* Finally introducing loggers
* Remove file list caching from disk_space_primitives
I don't think this is required anymore with the sync model
* Simplification of space primitives and more tests
* More reliable online status
* Add .zed settings
* Remove selfUpdate argument from `writeFile` no longer used
- Add `sync` config schema and document sync options
- Move sync config handling to client boot logic
- Move BootConfig type to ui_types.ts
- Remove sync env vars from server
- Update documentation for sync and architecture
* Improve sync logic and proxy routing for full sync state
* Add BoxProxy for late-bound client and improve Lua boot
- Add isMobile syscall for editor
* Add concurrency to sync process and log indexing duration
* Better service worker lifecycle management
2025-09-12 14:43:57 +02:00

101 lines
2.9 KiB
TypeScript

import { luaBuildStandardEnv } from "../lib/space_lua/stdlib.ts";
import {
LuaBuiltinFunction,
LuaEnv,
LuaNativeJSFunction,
type LuaRuntimeError,
LuaStackFrame,
LuaTable,
} from "../lib/space_lua/runtime.ts";
import type { System } from "../lib/plugos/system.ts";
import { resolveASTReference } from "./space_lua.ts";
export function buildLuaEnv(system: System<any>) {
const env = new LuaEnv(luaBuildStandardEnv());
// Expose all syscalls to Lua
exposeSyscalls(env, system);
return env;
}
/**
* Exposes all registered syscalls to Lua, automatically converting Lua arguments to JS values
* If a syscall is prefixed with `lua:` it exposes the syscall as a native Lua function, skipping the argument conversion0
*/
export function exposeSyscalls(env: LuaEnv, system: System<any>) {
// Expose all syscalls to Lua
const nativeFs = new LuaStackFrame(env, null);
for (const syscallName of system.registeredSyscalls.keys()) {
const isLuaNativeSyscall = syscallName.startsWith("lua:");
let cleanSyscallName = syscallName;
if (isLuaNativeSyscall) {
cleanSyscallName = syscallName.slice("lua:".length);
}
const [ns, fn] = cleanSyscallName.split(".");
if (!env.has(ns)) {
env.set(ns, new LuaTable(), nativeFs);
}
const luaFn = isLuaNativeSyscall
? new LuaBuiltinFunction((_sf, ...args) => {
return system.localSyscall(syscallName, args);
})
: new LuaNativeJSFunction((...args) => {
return system.localSyscall(syscallName, args);
});
env.get(ns, nativeFs).set(fn, luaFn, nativeFs);
}
}
export async function buildThreadLocalEnv(
system: System<any>,
globalEnv: LuaEnv,
) {
const tl = new LuaEnv();
if (system.registeredSyscalls.has("editor.getCurrentPageMeta")) {
const currentPageMeta = await system.localSyscall(
"editor.getCurrentPageMeta",
[],
);
if (currentPageMeta) {
tl.setLocal("currentPage", currentPageMeta);
} else {
tl.setLocal("currentPage", {
name: await system.localSyscall("editor.getCurrentPage", []),
});
}
}
tl.setLocal("_GLOBAL", globalEnv);
return tl;
}
export async function handleLuaError(e: LuaRuntimeError, system: System<any>) {
console.error(
"Lua eval exception",
e.message,
e.sf?.astCtx,
);
if (e.sf?.astCtx && e.sf.astCtx.ref) {
// We got an error and actually know where it came from, let's navigate there to help debugging
await system.localSyscall(
"editor.flashNotification",
[
`Lua error: ${e.message}`,
"error",
],
);
const ref = resolveASTReference(e.sf.astCtx);
if (!ref) return;
await system.localSyscall(
"editor.flashNotification",
[
`Navigating to the place in the code where this error occurred in ${ref.path}`,
"info",
],
);
await system.localSyscall("editor.navigate", [ref]);
}
}