summaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-09 00:00:56 -0600
committert <t@tjp.lol>2026-06-09 08:52:47 -0600
commit97b10466d83d488ad2cb9e084159a445af74c845 (patch)
tree6bea7c23d00ff1178a43e631fc700f210cb7d85b /src/main.zig
parent104001d25c9c8cb5ec45ced1678f7c7b70888808 (diff)
event lifecycle
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/main.zig b/src/main.zig
index 7905347..34a687a 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -2,6 +2,7 @@ const std = @import("std");
const panto = @import("panto");
const lua_bridge = @import("lua_bridge.zig");
const lua_runtime = @import("lua_runtime.zig");
+const lua_event_bridge = @import("lua_event_bridge.zig");
const extension_loader = @import("extension_loader.zig");
const panto_home = @import("panto_home.zig");
const luarocks_runtime = @import("luarocks_runtime.zig");
@@ -24,6 +25,7 @@ const tui_theme = @import("tui_theme.zig");
const tui_component = @import("tui_component.zig");
const tui_engine = @import("tui_engine.zig");
const tui_components = @import("tui_components.zig");
+const tui_event = @import("tui_event.zig");
const tui_app = @import("tui_app.zig");
// Shorthand alias for the Lua C API. The bridge module owns the actual
@@ -43,6 +45,7 @@ test {
std.testing.refAllDecls(@This());
_ = lua_bridge;
_ = lua_runtime;
+ _ = lua_event_bridge;
_ = extension_loader;
_ = panto_home;
_ = luarocks_runtime;
@@ -61,6 +64,7 @@ test {
_ = tui_component;
_ = tui_engine;
_ = tui_components;
+ _ = tui_event;
_ = tui_app;
}
@@ -401,7 +405,7 @@ pub fn main(init: std.process.Init) !void {
try command_compaction.register(&cmd_registry);
// Append slash commands declared by Lua extensions via
- // `panto.register_command`. A name collision with a builtin (or
+ // `panto.ext.register_command`. A name collision with a builtin (or
// between two extensions) surfaces as `error.DuplicateCommand` and
// aborts startup, matching the tool-name collision policy.
for (rt.commandList()) |lua_cmd| {
@@ -485,6 +489,38 @@ pub fn main(init: std.process.Init) !void {
);
defer app.deinit();
+ // Wire the Lua extension UI event bridge to the App's event bus: this
+ // registers every `panto.ext.on(...)` handler (harvested at extension
+ // load time) into the bus, in registration order, so extensions can
+ // wrap/replace built-in components and a Lua `panto.ext.emit(...)` can
+ // drive the same bus. With no Lua handlers this is a no-op.
+ try rt.eventBridge().attachBus(app.eventBus());
+
+ // Install the override-release hook so a Lua-backed override that is
+ // SUPERSEDED by a later mid-stream swap (e.g. a `tool_details` handler
+ // replacing the `tool (?)` default's prior override) has its luaL_ref +
+ // RenderCache freed. Without this, each swapped Lua component would leak
+ // for the life of the runtime. The hook recognizes a bridged component by
+ // its vtable identity and ignores native components (see
+ // `EventBridge.releaseOverride`).
+ //
+ // TEARDOWN ORDERING CONTRACT (load-bearing — do not reorder these decls):
+ // `app` is declared AFTER `rt`, so `defer app.deinit()` runs BEFORE
+ // `defer rt.deinit()` (defers are LIFO). The bridge (owned by `rt`)
+ // therefore outlives the App's teardown. This matters because the
+ // release hook below points into the bridge: if the bridge were freed
+ // first, any later hook invocation would be a use-after-free.
+ // It is safe today because `App.deinit` frees only its own default
+ // `kind` boxes and NEVER invokes `override_release_fn` — the surviving
+ // (non-superseded) Lua overrides are freed by `EventBridge.deinit` when
+ // `rt.deinit()` runs. The hook fires only during live mid-stream swaps,
+ // while both App and bridge are alive. If you ever make `App.deinit`
+ // call the release hook, or move `rt` to outlive `app`, revisit this.
+ app.setOverrideRelease(
+ @ptrCast(rt.eventBridge()),
+ lua_event_bridge.EventBridge.releaseOverrideThunk,
+ );
+
const Flusher = struct {
fn flush(ctx: *anyopaque) void {
const fw: *std.Io.File.Writer = @ptrCast(@alignCast(ctx));