const Lua = @This(); const std = @import("std"); const config = @import("config"); const zlua = @import("zlua"); const LuaUtils = @import("LuaUtils.zig"); const Bridge = @import("Bridge.zig"); const Fs = @import("Fs.zig"); const Input = @import("Input.zig"); const Api = @import("Api.zig"); const Hook = @import("Hook.zig"); const View = @import("View.zig"); const Output = @import("Output.zig"); const Remote = @import("Remote.zig"); const gpa = std.heap.c_allocator; state: *zlua.Lua, pub fn loadRuntimeDir(self: *zlua.Lua) !void { const path_dir = try std.fs.path.joinZ(gpa, &[_][]const u8{ config.runtime_path_prefix, "share", "mezzaluna", }); defer gpa.free(path_dir); { _ = try self.getGlobal("mez"); defer self.pop(1); _ = self.getField(-1, "path"); defer self.pop(1); _ = self.pushString(path_dir); self.setField(-2, "runtime"); } const path_full = try std.fs.path.joinZ(gpa, &[_][]const u8{ path_dir, "init.lua", }); defer gpa.free(path_full); self.doFile(path_full) catch { const err = try self.toString(-1); std.log.debug("Failed to run lua file: {s}", .{err}); }; } pub fn setBaseConfig(self: *zlua.Lua, path: []const u8) !void { _ = try self.getGlobal("mez"); defer self.pop(1); _ = self.getField(-1, "path"); defer self.pop(1); _ = self.pushString(path); self.setField(-2, "config"); } fn loadBaseConfig(self: *zlua.Lua) !void { const lua_path = "mez.path.base_config"; if (!Bridge.getNestedField(self, @constCast(lua_path[0..]))) { std.log.err("Base config path not found. Is your runtime dir setup?", .{}); return; } const path = self.toString(-1) catch |err| { std.log.err("Failed to pop the base config path from the lua stack. {}", .{err}); return; }; self.pop(-1); try self.doFile(path); } fn loadConfigDir(self: *zlua.Lua) !void { const lua_path = "mez.path.config"; if (!Bridge.getNestedField(self, @constCast(lua_path[0..]))) { std.log.err("Config path not found. Is your runtime dir setup?", .{}); return; } const path = self.toString(-1) catch |err| { std.log.err("Failed to pop the config path from the lua stack. {}", .{err}); return; }; self.pop(-1); try self.doFile(path); } pub fn openMezLibs(self: *zlua.Lua) void { self.newTable(); defer _ = self.setGlobal("mez"); { self.newTable(); defer _ = self.setField(-2, "path"); } { const fs_funcs = zlua.fnRegsFromType(Fs); LuaUtils.newLib(self, fs_funcs); self.setField(-2, "fs"); } { const input_funcs = zlua.fnRegsFromType(Input); LuaUtils.newLib(self, input_funcs); self.setField(-2, "input"); } { const hook_funcs = zlua.fnRegsFromType(Hook); LuaUtils.newLib(self, hook_funcs); self.setField(-2, "hook"); } { const api_funcs = zlua.fnRegsFromType(Api); LuaUtils.newLib(self, api_funcs); self.setField(-2, "api"); } { const view_funcs = zlua.fnRegsFromType(View); LuaUtils.newLib(self, view_funcs); self.setField(-2, "view"); } { const output_funcs = zlua.fnRegsFromType(Output); LuaUtils.newLib(self, output_funcs); self.setField(-2, "output"); } { const remote_funcs = zlua.fnRegsFromType(Remote); LuaUtils.newLib(self, remote_funcs); self.setField(-2, "remote"); } } pub const Config = struct { path: ?[]const u8, enabled: bool, }; pub fn init(self: *Lua, cfg: Config) !void { self.state = try zlua.Lua.init(gpa); errdefer self.state.deinit(); self.state.openLibs(); openMezLibs(self.state); if (!cfg.enabled) { try setBaseConfig(self.state, ""); } else if (cfg.path) |path| { defer gpa.free(path); try setBaseConfig(self.state, path); } loadRuntimeDir(self.state) catch |err| if (err == error.LuaRuntime) { std.log.warn("{s}", .{try self.state.toString(-1)}); }; loadBaseConfig(self.state) catch |err| if (err == error.LuaRuntime) { std.log.warn("{s}", .{try self.state.toString(-1)}); }; if (cfg.enabled) { loadConfigDir(self.state) catch |err| if (err == error.LuaRuntime) { std.log.warn("{s}", .{try self.state.toString(-1)}); }; } std.log.debug("Loaded lua", .{}); } pub fn deinit(self: *Lua) void { self.state.deinit(); }