diff --git a/res/example.lua b/res/example.lua index fd5a02e..4ff85ee 100644 --- a/res/example.lua +++ b/res/example.lua @@ -14,36 +14,51 @@ -- must be in the unsigned 32-bit integer range: 0 to 2^32-1. -- clear() -- Clear the buffer. -- } +-- +-- A function named `draw()` must be declared in the script. This is ran every frame. +-- -- ]] local SQUARE_WIDTH = 10 local SQUARE_HEIGHT = 5 -local SQUARE_X = 0 -local SQUARE_Y = 0 +local SQUARE_COUNT = 25 +local squares = {} -local SQUARE_VX = 1 -local SQUARE_VY = 1 +for i = 0, SQUARE_COUNT-1 do + local vx = 1 + local vy = 1 + if math.random(1, 2) == 2 then vx = -vx end + if math.random(1, 2) == 2 then vy = -vy end + squares[#squares+1] = { + x = math.random(1, ly.width - SQUARE_WIDTH), + y = math.random(1, ly.height - SQUARE_HEIGHT), + vx = vx, + vy = vy, + color = math.random(0xFFFFFF) + } +end local timer = os.clock() -local color = math.random(0xFFFFFF) 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 ly.clear() - SQUARE_X = SQUARE_X + SQUARE_VX - SQUARE_Y = SQUARE_Y + SQUARE_VY - for x = SQUARE_X, SQUARE_X + SQUARE_WIDTH do - for y = SQUARE_Y, SQUARE_Y + SQUARE_HEIGHT do - ly.putCell(string.byte(' '), 0, color, x, y) + for i, v in ipairs(squares) do + v.x = v.x + v.vx + v.y = v.y + v.vy + for x = v.x, v.x + SQUARE_WIDTH do + for y = v.y, v.y + SQUARE_HEIGHT do + ly.putCell(string.byte(' '), 0, v.color, x, y) + end end + if v.x <= 0 then v.vx = 1; v.color = math.random(0xFFFFFF) end + if v.x + SQUARE_WIDTH >= ly.width-1 then v.vx = -1; v.color = math.random(0xFFFFFF) end + if v.y <= 0 then v.vy = 1; v.color = math.random(0xFFFFFF) end + if v.y + SQUARE_HEIGHT >= ly.height-1 then v.vy = -1; v.color = math.random(0xFFFFFF) end end - if SQUARE_X <= 0 then SQUARE_VX = 1; color = math.random(0xFFFFFF) end - if SQUARE_X + SQUARE_WIDTH >= ly.width-1 then SQUARE_VX = -1; color = math.random(0xFFFFFF) end - if SQUARE_Y <= 0 then SQUARE_VY = 1; color = math.random(0xFFFFFF) end - if SQUARE_Y + SQUARE_HEIGHT >= ly.height-1 then SQUARE_VY = -1; color = math.random(0xFFFFFF) end timer = os.clock() end end diff --git a/src/animations/Lua.zig b/src/animations/Lua.zig index af93fc6..a793210 100644 --- a/src/animations/Lua.zig +++ b/src/animations/Lua.zig @@ -12,15 +12,18 @@ const LyLua = @embedFile("ly.lua"); const Lua = @This(); +allocator: Allocator, instance: ?Widget = null, lua: *zlua.Lua, log: *LogFile, terminal_buffer: *TerminalBuffer, width: usize, height: usize, +margin: usize, io: std.Io, lua_error: bool = false, +lua_str: ?[:0]const u8 = null, pub fn init( io: std.Io, @@ -28,14 +31,17 @@ pub fn init( log: *LogFile, buf: *TerminalBuffer, file: ?[]const u8, + margin: u8, ) !Lua { var self: Lua = .{ .lua = try zlua.Lua.init(alloc), + .allocator = alloc, .terminal_buffer = buf, .instance = null, .log = log, .width = 0, .height = 0, + .margin = margin, .io = io, }; @@ -53,11 +59,27 @@ pub fn init( defer alloc.free(zf); self.lua.doString(LyLua) 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.lua_error = true; }; + 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.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.lua_error = true; }; @@ -84,12 +106,24 @@ fn draw(self: *Lua) void { _ = 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; } @@ -99,6 +133,12 @@ fn draw(self: *Lua) void { // 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; }; @@ -107,6 +147,12 @@ fn draw(self: *Lua) void { _ = 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; }; @@ -115,6 +161,12 @@ fn draw(self: *Lua) void { _ = 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; }; @@ -123,6 +175,12 @@ fn draw(self: *Lua) void { _ = 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; }; @@ -138,6 +196,10 @@ fn draw(self: *Lua) void { 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(i, @divFloor(self.terminal_buffer.height, 2)) catch {}; + }; } } @@ -147,6 +209,12 @@ fn calculateTimeout(self: *Lua, _: *anyopaque) !?usize { _ = 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); @@ -154,7 +222,13 @@ fn calculateTimeout(self: *Lua, _: *anyopaque) !?usize { } 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 {}", .{lyType}); + 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); @@ -167,6 +241,8 @@ fn calculateTimeout(self: *Lua, _: *anyopaque) !?usize { } fn deinit(self: *Lua) void { + if (self.lua_str) |str| + self.allocator.free(str); self.lua.deinit(); } diff --git a/src/main.zig b/src/main.zig index 384d030..37f98c6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1106,6 +1106,7 @@ pub fn main(init: std.process.Init) !void { &state.log_file, &state.buffer, state.config.lua_animation_file, + state.config.edge_margin, ); animation = lua.widget(); },