review pt 1

This commit is contained in:
RadsammyT 2026-06-15 18:01:44 -04:00
commit cc14fff5c6
No known key found for this signature in database
5 changed files with 160 additions and 161 deletions

View file

@ -74,18 +74,16 @@ pub fn build(b: *std.Build) !void {
const zlua = b.dependency("zlua", .{
.target = target,
.optimize = optimize,
.lang = .luajit
.lang = .luajit,
});
exe.root_module.addImport("zlua", zlua.module("zlua"));
const ly_ui = b.dependency("ly_ui", .{
.target = target,
.optimize = optimize,
.enable_x11_support = enable_x11_support,
.fallback_uid_min = fallback_uid_min,
.fallback_uid_max = fallback_uid_max
.fallback_uid_max = fallback_uid_max,
});
exe.root_module.addImport("ly-ui", ly_ui.module("ly-ui"));

View file

@ -23,6 +23,9 @@ local SQUARE_WIDTH = 10
local SQUARE_HEIGHT = 5
local SQUARE_COUNT = 25
local FPS = 120
local squares = {}
for i = 0, SQUARE_COUNT-1 do
@ -44,7 +47,7 @@ local timer = os.clock()
function draw()
-- Rather than progressing the animation by frame, do it based on
-- seconds, like from os.clock().
if timer + 0.025 < os.clock() then
if timer + (1/FPS) < os.clock() then
ly.clear()
for i, v in ipairs(squares) do
v.x = v.x + v.vx

View file

@ -5,10 +5,11 @@ const Widget = ly_ui.Widget;
const TerminalBuffer = ly_ui.TerminalBuffer;
const Cell = ly_ui.Cell;
const Allocator = std.mem.Allocator;
const InfoLine = @import("../components/InfoLine.zig");
const zlua = @import("zlua");
const LyLua = @embedFile("ly.lua");
const ly_lua = @embedFile("ly.lua");
const Lua = @This();
@ -21,8 +22,14 @@ width: usize,
height: usize,
margin: usize,
io: std.Io,
animation_delay: u16,
info_line: *InfoLine,
fg: u32,
bg: u32,
lua_error: bool = false,
lua_error_logged: bool = false,
lua_str: ?[:0]const u8 = null,
pub fn init(
@ -30,8 +37,12 @@ pub fn init(
alloc: Allocator,
log: *LogFile,
buf: *TerminalBuffer,
file: ?[]const u8,
file: []const u8,
margin: u8,
animation_delay: u16,
info_line: *InfoLine,
fg: u32,
bg: u32,
) !Lua {
var self: Lua = .{
.lua = try zlua.Lua.init(alloc),
@ -43,6 +54,10 @@ pub fn init(
.height = 0,
.margin = margin,
.io = io,
.animation_delay = animation_delay,
.info_line = info_line,
.fg = fg,
.bg = bg,
};
// exclude IO and debug libraries
@ -52,42 +67,179 @@ pub fn init(
self.lua.openOS();
self.lua.openString();
self.lua.openTable();
self.lua.openString();
if (file) |f| {
const zf = std.mem.concatWithSentinel(alloc, u8, &[1][]const u8{f}, 0) catch unreachable;
file_loading: {
const zf = std.mem.concatWithSentinel(alloc, u8, &[1][]const u8{file}, 0) catch |e| {
self.log.err(self.io, "lua", "failed to allocate file path: {}", .{e}) catch unreachable;
self.lua_str = "failed to allocate file path!";
self.lua_error = true;
break :file_loading;
};
defer alloc.free(zf);
self.lua.doString(LyLua) catch {
self.lua.doString(ly_lua) catch {
const errorStr = self.lua.toString(-1) catch unreachable;
self.lua_str = try self.allocator.dupeSentinel(u8, errorStr, 0);
self.log.err(self.io, "Lua", "Lua Error: {s}", .{errorStr}) catch unreachable;
self.log.err(self.io, "lua", "lua error: {s}", .{errorStr}) catch unreachable;
self.lua_error = true;
break :file_loading;
};
if (self.terminal_buffer.height != self.height or
self.terminal_buffer.width != self.width)
{
self.width = self.terminal_buffer.width;
self.height = self.terminal_buffer.height;
_ = self.lua.getGlobal("ly");
_ = self.lua.pushString("width");
self.lua.pushInteger(@intCast(self.terminal_buffer.width));
self.lua.setTable(-3);
_ = self.lua.pushString("height");
self.lua.pushInteger(@intCast(self.terminal_buffer.height));
self.lua.setTable(-3);
self.lua.setGlobal("ly");
}
self.propogateTerminalBounds();
self.lua.doFile(zf) catch {
const errorStr = self.lua.toString(-1) catch unreachable;
self.lua_str = try self.allocator.dupeSentinel(u8, errorStr, 0);
self.log.err(self.io, "Lua", "Lua Error: {s}", .{errorStr}) catch unreachable;
self.log.err(self.io, "lua", "lua error: {s}", .{errorStr}) catch unreachable;
self.lua_error = true;
break :file_loading;
};
}
return self;
}
fn draw(self: *Lua) void {
self.propogateTerminalBounds();
if (self.lua_error) {
// Ly's Red Screen of Omega-Death:tm:
const cell = Cell.init(0x2588, 0x00ff0000, 0x00ff0000);
for (0..self.terminal_buffer.height) |y|
for (0..self.terminal_buffer.width) |x|
cell.put(x, y) catch {};
if (self.lua_str) |str|
for (str, 0..) |c, i| {
Cell.init(c, 0x00FFFFFF, 0).put(
@divFloor(self.width, 2) - @divFloor(str.len, 2) + i,
self.margin + 5,
) catch {};
};
if (!self.lua_error_logged) {
self.info_line.addMessage("lua animation failed", self.bg, self.fg) catch {};
self.lua_error_logged = true;
}
return;
}
_ = self.lua.getGlobal("draw");
self.lua.protectedCall(.{}) catch {
const errorStr = self.lua.toString(-1) catch unreachable;
self.lua_str = std.mem.concatWithSentinel(
self.allocator,
u8,
&[_][]const u8{ "Cannot call draw(): ", errorStr },
0,
) catch unreachable;
self.log.err(self.io, "Lua", "Error (Cannot call draw()): {s}", .{errorStr}) catch unreachable;
self.lua_error = true;
};
const bufferType = self.lua.getGlobal("_BUFFER");
if (bufferType != .table) {
self.log.err(self.io, "Lua", "global '_BUFFER' must be a table: got {}", .{bufferType}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"global '_BUFFER' must be a table: got {}",
.{bufferType},
0,
) catch unreachable;
self.lua_error = true;
return;
}
self.lua.pushNil();
while (self.lua.next(-2)) {
// expect the key to be an int
// expect the value to be a table
const pos = self.lua.toInteger(-2) catch {
self.log.err(self.io, "Lua", "pos: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"pos: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
_ = self.lua.pushString("char");
_ = self.lua.getTable(-2);
const char = self.lua.toInteger(-1) catch {
self.log.err(self.io, "Lua", "char: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"char: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
self.lua.pop(1);
_ = self.lua.pushString("fg");
_ = self.lua.getTable(-2);
const fg = self.lua.toInteger(-1) catch {
self.log.err(self.io, "Lua", "fg: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"fg: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
self.lua.pop(1);
_ = self.lua.pushString("bg");
_ = self.lua.getTable(-2);
const bg = self.lua.toInteger(-1) catch {
self.log.err(self.io, "Lua", "bg: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"bg: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
self.lua.pop(1);
self.lua.pop(1);
if (pos < 0) continue; // do not draw cells that underflow
TerminalBuffer.setCell(
@rem(@as(usize, @intCast(pos)), self.width),
@divFloor(@as(usize, @bitCast(pos)), self.width),
.init(
@intCast(char),
@intCast(@as(i32, @truncate(fg))),
@intCast(@as(i32, @truncate(bg))),
),
) catch {};
}
}
fn calculateTimeout(self: *Lua, _: *anyopaque) !?usize {
return self.animation_delay;
}
fn deinit(self: *Lua) void {
if (self.lua_str) |str| self.allocator.free(str);
self.lua.deinit();
}
pub fn widget(self: *Lua) *Widget {
if (self.instance) |*inst| return inst;
self.instance = Widget.init(
"Lua",
null,
self,
deinit,
null, //realloc
draw, //draw
null, //update
null,
calculateTimeout, //calculateTimeout
);
return &self.instance.?;
}
fn propogateTerminalBounds(self: *Lua) void {
if (self.terminal_buffer.height != self.height or
self.terminal_buffer.width != self.width)
{
@ -102,162 +254,4 @@ fn draw(self: *Lua) void {
self.lua.setTable(-3);
self.lua.setGlobal("ly");
}
if (!self.lua_error) {
_ = self.lua.getGlobal("draw");
self.lua.protectedCall(.{}) catch {
const errorStr = self.lua.toString(-1) catch unreachable;
self.lua_str = std.mem.concatWithSentinel(
self.allocator,
u8,
&[_][]const u8{ "Cannot call draw(): ", errorStr },
0,
) catch unreachable;
self.log.err(self.io, "Lua", "Error (Cannot call draw()): {s}", .{errorStr}) catch unreachable;
self.lua_error = true;
};
const bufferType = self.lua.getGlobal("_BUFFER");
if (bufferType != .table) {
self.log.err(self.io, "Lua", "global '_BUFFER' must be a table: got {}", .{bufferType}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"global '_BUFFER' must be a table: got {}",
.{bufferType},
0,
) catch unreachable;
self.lua_error = true;
return;
}
self.lua.pushNil();
while (self.lua.next(-2)) {
// expect the key to be an int
// expect the value to be a table
const pos = self.lua.toInteger(-2) catch {
self.log.err(self.io, "Lua", "pos: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"pos: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
_ = self.lua.pushString("char");
_ = self.lua.getTable(-2);
const char = self.lua.toInteger(-1) catch {
self.log.err(self.io, "Lua", "char: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"char: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
self.lua.pop(1);
_ = self.lua.pushString("fg");
_ = self.lua.getTable(-2);
const fg = self.lua.toInteger(-1) catch {
self.log.err(self.io, "Lua", "fg: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"fg: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
self.lua.pop(1);
_ = self.lua.pushString("bg");
_ = self.lua.getTable(-2);
const bg = self.lua.toInteger(-1) catch {
self.log.err(self.io, "Lua", "bg: cannot convert to integer", .{}) catch {};
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"bg: cannot convert to integer",
.{},
0,
) catch unreachable;
self.lua_error = true;
return;
};
self.lua.pop(1);
self.lua.pop(1);
if (pos < 0) continue; // do not draw cells that underflow
Cell.init(@intCast(char), @intCast(@as(i32, @truncate(fg))), @intCast(@as(i32, @truncate(bg))))
.put(@rem(@as(usize, @intCast(pos)), self.width), @divFloor(@as(usize, @bitCast(pos)), self.width)) catch {};
}
} else {
// Ly's Red Screen of Omega-Death:tm:
const cell = Cell.init(0x2588, 0x00ff0000, 0x00ff0000);
for (0..self.terminal_buffer.height) |y|
for (0..self.terminal_buffer.width) |x|
cell.put(x, y) catch {};
if (self.lua_str) |str|
for (str, 0..) |c, i| {
Cell.init(c, 0x00FFFFFF, 0).put(@divFloor(self.width, 2) - @divFloor(str.len, 2) + i, self.margin + 5) catch {};
};
}
}
fn calculateTimeout(self: *Lua, _: *anyopaque) !?usize {
if (self.lua_error) return null;
const lyType = self.lua.getGlobal("ly"); // +1
_ = self.lua.pushString("frame_delay"); // + 1
if (lyType != .table) {
try self.log.err(self.io, "Lua", "global 'ly' must be a table: got {}", .{lyType});
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"global 'ly' must be a table: got {}",
.{lyType},
0,
) catch unreachable;
self.lua_error = true;
self.lua.pop(-1);
self.lua.pop(-1);
return null;
}
const frameDelayType = self.lua.getTable(-2); // neut
if (frameDelayType != .number) {
try self.log.err(self.io, "Lua", "'ly.frame_delay' must be a number: got {}", .{frameDelayType});
self.lua_str = std.fmt.allocPrintSentinel(
self.allocator,
"'ly.frameDelayType' must be a table: got {}",
.{frameDelayType},
0,
) catch unreachable;
self.lua_error = true;
self.lua.pop(-1);
self.lua.pop(-1);
return null;
}
const timeout = try self.lua.toNumeric(usize, -1);
self.lua.pop(-1); // pop number from stack
self.lua.pop(-1); // pop table 'ly' from stack
return timeout;
}
fn deinit(self: *Lua) void {
if (self.lua_str) |str|
self.allocator.free(str);
self.lua.deinit();
}
pub fn widget(self: *Lua) *Widget {
if (self.instance) |*inst| return inst;
self.instance = Widget.init(
"Lua",
null,
self,
deinit, //deinit
null, //realloc
draw, //draw
null, //update
null,
calculateTimeout, //calculateTimeout
);
return &self.instance.?;
}

View file

@ -74,7 +74,7 @@ lang: []const u8 = "en",
login_cmd: ?[]const u8 = null,
login_defs_path: []const u8 = "/etc/login.defs",
logout_cmd: ?[]const u8 = null,
lua_animation_file: ?[]const u8 = null,
lua_animation_file: []const u8 = build_options.config_directory ++ "/ly/example.lua",
ly_log: ?[]const u8 = "/var/log/ly.log",
margin_box_h: u8 = 2,
margin_box_v: u8 = 1,

View file

@ -1107,6 +1107,10 @@ pub fn main(init: std.process.Init) !void {
&state.buffer,
state.config.lua_animation_file,
state.config.edge_margin,
state.config.animation_frame_delay,
&state.info_line,
state.config.error_fg,
state.config.error_bg,
);
animation = lua.widget();
},