diff --git a/build.zig.zon b/build.zig.zon index 7d281a5..d61e402 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -8,35 +8,35 @@ .syntax = .{ .path = "src/syntax" }, .flags = .{ .url = "https://github.com/n0s4/flags/archive/372501d1576b5723829bcba98e41361132c7b618.tar.gz", - .hash = "flags-0.8.0-AAAAAJV0AACuGBBnpUnHqZzAhoGTp4ibFROBQQQZGRqx", + .hash = "1220ae181067a549c7a99cc0868193a7889b151381410419191ab1a79304f914336e", }, .dizzy = .{ .url = "https://github.com/neurocyte/dizzy/archive/455d18369cbb2a0458ba70be919cd378338d695e.tar.gz", - .hash = "dizzy-1.0.0-AAAAAM1wAAAiDbx_6RwcVEOBk8p2XOu8t9WPNc3K7kBK", + .hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362", }, .thespian = .{ - .url = "https://github.com/neurocyte/thespian/archive/e3921691dc5d949ee38719251d67841f88dbabfd.tar.gz", - .hash = "thespian-0.0.1-owFOjsnnBgDTBCdPHQhp3Ir3hLZI5pVLOrlIa8JtGJAb", + .url = "https://github.com/neurocyte/thespian/archive/78c9c1292c683478d8ac98d8318bc098442cc0b9.tar.gz", + .hash = "thespian-0.0.1-owFOjsnnBgBCsKhYw9XeHnQw0Um9SJQECEZ0aqomc04m", }, .themes = .{ .url = "https://github.com/neurocyte/flow-themes/releases/download/master-59bf204551bcb238faddd06779063570e7e6d431/flow-themes.tar.gz", - .hash = "N-V-__8AAM9UFwCaITo5LqgOpcfd4SXnFhuwJ4rEuZ253yt6", + .hash = "12209a213a392ea80ea5c7dde125e7161bb0278ac4b99db9df2b7af783710bcb09f7", }, .fuzzig = .{ .url = "https://github.com/fjebaker/fuzzig/archive/44c04733c7c0fee3db83672aaaaf4ed03e943156.tar.gz", - .hash = "fuzzig-0.1.1-AAAAALNIAQBmbHr-MPalGuR393Vem2pTQXI7_LXeNJgX", + .hash = "1220666c7afe30f6a51ae477f7755e9b6a5341723bfcb5de349817b5d0912b96f9ad", }, .vaxis = .{ - .url = "https://github.com/neurocyte/libvaxis/archive/386e554f275c82ebfde7f15765687aaa6e89f6f6.tar.gz", - .hash = "vaxis-0.1.0-BWNV_FneCADwINyXfMcWHjv_vpQR-VOzrGSmH6BEP40y", + .url = "https://github.com/neurocyte/libvaxis/archive/da7d26fa0e86c721414bdcb82ea46cf0b4da5b68.tar.gz", + .hash = "1220fe019c2901695c959873ef9b1736bd04197d377ad1c520eff8affd5204dd2bc2", }, .zeit = .{ .url = "https://github.com/rockorager/zeit/archive/8fd203f85f597f16e0a525c1f1ca1e0bffded809.tar.gz", - .hash = "zeit-0.0.0-AAAAACVbAgAiIzg1rccZU1qOfO_dKQKme7-37xmEQcqc", + .hash = "122022233835adc719535a8e7cefdd2902a67bbfb7ef198441ca9ce89c0593f488c2", }, .win32 = .{ .url = "https://github.com/marlersoft/zigwin32/archive/e8739b32a33ce48a3286aba31918b26a9dfc6ef0.tar.gz", - .hash = "zigwin32-25.0.28-preview-AAAAAEEl_AMhnKSs-lgEyjmUX5JVTpNQewd8A2Bbekwc", + .hash = "1220219ca4acfa5804ca39945f92554e93507b077c03605b7a4c1c0401f0c7121339", .lazy = true, }, }, diff --git a/src/tui/Fire.zig b/src/tui/Fire.zig deleted file mode 100644 index 4216dd6..0000000 --- a/src/tui/Fire.zig +++ /dev/null @@ -1,126 +0,0 @@ -const std = @import("std"); -const Plane = @import("renderer").Plane; -const Widget = @import("Widget.zig"); - -const px = "▀"; - -const Fire = @This(); - -allocator: std.mem.Allocator, -plane: Plane, -prng: std.Random.DefaultPrng, - -//scope cache - spread fire -spread_px: u8 = 0, -spread_rnd_idx: u8 = 0, -spread_dst: usize = 0, - -FIRE_H: u16, -FIRE_W: u16, -FIRE_SZ: usize, -FIRE_LAST_ROW: usize, - -screen_buf: []u8, - -const MAX_COLOR = 256; -const LAST_COLOR = MAX_COLOR - 1; - -pub fn init(allocator: std.mem.Allocator, plane: Plane) !Fire { - const pos = Widget.Box.from(plane); - const FIRE_H = @as(u16, @intCast(pos.h)) * 2; - const FIRE_W = @as(u16, @intCast(pos.w)); - var self: Fire = .{ - .allocator = allocator, - .plane = plane, - .prng = std.Random.DefaultPrng.init(blk: { - var seed: u64 = undefined; - try std.posix.getrandom(std.mem.asBytes(&seed)); - break :blk seed; - }), - .FIRE_H = FIRE_H, - .FIRE_W = FIRE_W, - .FIRE_SZ = @as(usize, @intCast(FIRE_H)) * FIRE_W, - .FIRE_LAST_ROW = @as(usize, @intCast(FIRE_H - 1)) * FIRE_W, - .screen_buf = try allocator.alloc(u8, @as(usize, @intCast(FIRE_H)) * FIRE_W), - }; - - var buf_idx: usize = 0; - while (buf_idx < self.FIRE_SZ) : (buf_idx += 1) { - self.screen_buf[buf_idx] = fire_black; - } - - // last row is white...white is "fire source" - buf_idx = 0; - while (buf_idx < self.FIRE_W) : (buf_idx += 1) { - self.screen_buf[self.FIRE_LAST_ROW + buf_idx] = fire_white; - } - return self; -} - -pub fn deinit(self: *Fire) void { - self.allocator.free(self.screen_buf); -} - -const fire_palette = [_]u8{ 0, 233, 234, 52, 53, 88, 89, 94, 95, 96, 130, 131, 132, 133, 172, 214, 215, 220, 220, 221, 3, 226, 227, 230, 195, 230 }; -const fire_black: u8 = 0; -const fire_white: u8 = fire_palette.len - 1; - -pub fn render(self: *Fire) void { - self.plane.home(); - var rand = self.prng.random(); - - //update fire buf - var doFire_x: u16 = 0; - while (doFire_x < self.FIRE_W) : (doFire_x += 1) { - var doFire_y: u16 = 0; - while (doFire_y < self.FIRE_H) : (doFire_y += 1) { - const doFire_idx = @as(usize, @intCast(doFire_y)) * self.FIRE_W + doFire_x; - - //spread fire - self.spread_px = self.screen_buf[doFire_idx]; - - //bounds checking - if ((self.spread_px == 0) and (doFire_idx >= self.FIRE_W)) { - self.screen_buf[doFire_idx - self.FIRE_W] = 0; - } else { - self.spread_rnd_idx = rand.intRangeAtMost(u8, 0, 3); - if (doFire_idx >= (self.spread_rnd_idx + 1)) { - self.spread_dst = doFire_idx - self.spread_rnd_idx + 1; - } else { - self.spread_dst = doFire_idx; - } - if (self.spread_dst >= self.FIRE_W) { - if (self.spread_px > (self.spread_rnd_idx & 1)) { - self.screen_buf[self.spread_dst - self.FIRE_W] = self.spread_px - (self.spread_rnd_idx & 1); - } else { - self.screen_buf[self.spread_dst - self.FIRE_W] = 0; - } - } - } - } - } - - //scope cache - fire 2 screen buffer - var frame_x: u16 = 0; - var frame_y: u16 = 0; - - // for each row - frame_y = 0; - while (frame_y < self.FIRE_H) : (frame_y += 2) { // 'paint' two rows at a time because of half height char - // for each col - frame_x = 0; - while (frame_x < self.FIRE_W) : (frame_x += 1) { - //each character rendered is actually to rows of 'pixels' - // - "hi" (current px row => fg char) - // - "low" (next row => bg color) - const px_hi = self.screen_buf[@as(usize, @intCast(frame_y)) * self.FIRE_W + frame_x]; - const px_lo = self.screen_buf[@as(usize, @intCast(frame_y + 1)) * self.FIRE_W + frame_x]; - - self.plane.set_fg_palindex(fire_palette[px_hi]) catch {}; - self.plane.set_bg_palindex(fire_palette[px_lo]) catch {}; - _ = self.plane.putstr(px) catch {}; - } - self.plane.cursor_move_yx(-1, 0) catch {}; - self.plane.cursor_move_rel(1, 0) catch {}; - } -} diff --git a/src/tui/home.zig b/src/tui/home.zig index f90e7f9..0686b18 100644 --- a/src/tui/home.zig +++ b/src/tui/home.zig @@ -1,8 +1,6 @@ const std = @import("std"); const build_options = @import("build_options"); const tp = @import("thespian"); -const log = @import("log"); -const cbor = @import("cbor"); const Plane = @import("renderer").Plane; const root = @import("root"); @@ -16,52 +14,6 @@ const keybind = @import("keybind"); const fonts = @import("fonts.zig"); -const style = struct { - title: []const u8 = root.application_title, - subtext: []const u8 = root.application_subtext, - - centered: bool = false, - - menu_commands: []const u8 = splice(if (build_options.gui) - \\find_file - \\create_new_file - \\open_file - \\open_recent_project - \\find_in_files - \\open_command_palette - \\select_task - \\add_task - \\open_config - \\open_gui_config - \\change_fontface - \\open_keybind_config - \\toggle_input_mode - \\change_theme - \\open_help - \\open_version_info - \\quit - else - \\find_file - \\create_new_file - \\open_file - \\open_recent_project - \\find_in_files - \\open_command_palette - \\select_task - \\add_task - \\open_config - \\open_keybind_config - \\toggle_input_mode - \\change_theme - \\open_help - \\open_version_info - \\quit - ), - - include_files: []const u8 = "", -}; -pub const Style = style; - allocator: std.mem.Allocator, plane: Plane, parent: Plane, @@ -69,24 +21,54 @@ fire: ?Fire = null, commands: Commands = undefined, menu: *Menu.State(*Self), menu_w: usize = 0, -menu_len: usize = 0, max_desc_len: usize = 0, input_namespace: []const u8, -home_style: style, -home_style_bufs: [][]const u8, - const Self = @This(); +const menu_commands = if (build_options.gui) &[_][]const u8{ + "find_file", + "create_new_file", + "open_file", + "open_recent_project", + "find_in_files", + "open_command_palette", + "select_task", + "add_task", + "open_config", + "open_gui_config", + "change_fontface", + "open_keybind_config", + "toggle_input_mode", + "change_theme", + "open_help", + "open_version_info", + "quit", +} else &[_][]const u8{ + "find_file", + "create_new_file", + "open_file", + "open_recent_project", + "find_in_files", + "open_command_palette", + "select_task", + "add_task", + "open_config", + "open_keybind_config", + "toggle_input_mode", + "change_theme", + "open_help", + "open_version_info", + "quit", +}; + pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget { - const logger = log.logger("home"); const self: *Self = try allocator.create(Self); var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*); errdefer n.deinit(); command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {}; const keybind_mode = tui.get_keybind_mode() orelse @panic("no active keybind mode"); - const home_style, const home_style_bufs = root.read_config(style, allocator); const w = Widget.to(self); self.* = .{ @@ -95,32 +77,15 @@ pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget { .plane = n, .menu = try Menu.create(*Self, allocator, w.plane.*, .{ .ctx = self, .on_render = menu_on_render }), .input_namespace = keybind.get_namespace(), - .home_style = home_style, - .home_style_bufs = home_style_bufs, }; try self.commands.init(self); - var it = std.mem.splitAny(u8, self.home_style.menu_commands, "\n "); - while (it.next()) |command_name| { - self.menu_len += 1; - const id = command.get_id(command_name) orelse { - logger.print("{s} is not defined", .{command_name}); - continue; - }; - const description = command.get_description(id) orelse { - logger.print("{s} has no description", .{command_name}); - continue; - }; - var hints = std.mem.splitScalar(u8, keybind_mode.keybind_hints.get(command_name) orelse "", ','); - const hint = hints.first(); - self.max_desc_len = @max(self.max_desc_len, description.len + hint.len + 5); - try self.add_menu_command(command_name, description, hint, self.menu); - } + self.get_max_desc_len(keybind_mode.keybind_hints); + inline for (menu_commands) |command_name| try self.add_menu_command(command_name, self.menu, keybind_mode.keybind_hints); self.position_menu(15, 9); return w; } pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { - root.free_config(self.allocator, self.home_style_bufs); self.menu.deinit(allocator); self.commands.deinit(); self.plane.deinit(); @@ -128,32 +93,36 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { allocator.destroy(self); } -fn add_menu_command(self: *Self, command_name: []const u8, description: []const u8, hint: []const u8, menu: anytype) !void { +fn get_max_desc_len(self: *Self, hints_map: anytype) void { + inline for (menu_commands) |command_name| { + const id = command.get_id(command_name) orelse @panic(command_name ++ " is not defined"); + const description = command.get_description(id) orelse @panic(command_name ++ " has no description"); + var hints = std.mem.splitScalar(u8, hints_map.get(command_name) orelse "", ','); + const hint = hints.first(); + self.max_desc_len = @max(self.max_desc_len, description.len + hint.len + 5); + } +} + +fn add_menu_command(self: *Self, comptime command_name: []const u8, menu: anytype, hints_map: anytype) !void { + const id = command.get_id(command_name) orelse @panic(command_name ++ " is not defined"); + const description = command.get_description(id) orelse @panic(command_name ++ " has no description"); + var hints = std.mem.splitScalar(u8, hints_map.get(command_name) orelse "", ','); + const hint = hints.first(); const label_len = description.len + hint.len; var buf: [64]u8 = undefined; - { - var fis = std.io.fixedBufferStream(&buf); - const writer = fis.writer(); - const leader = if (hint.len > 0) "." else " "; - _ = try writer.write(description); - _ = try writer.write(" "); + var fis = std.io.fixedBufferStream(&buf); + const writer = fis.writer(); + const leader = if (hint.len > 0) "." else " "; + _ = try writer.write(description); + _ = try writer.write(" "); + _ = try writer.write(leader); + _ = try writer.write(leader); + for (0..(self.max_desc_len - label_len - 5)) |_| _ = try writer.write(leader); - _ = try writer.write(leader); - for (0..(self.max_desc_len - label_len - 5)) |_| - _ = try writer.write(leader); - try writer.print(" :{s}", .{hint}); - const label = fis.getWritten(); - self.menu_w = @max(self.menu_w, label.len + 1); - } - - var value = std.ArrayList(u8).init(self.allocator); - defer value.deinit(); - const writer = value.writer(); - try cbor.writeValue(writer, description); - try cbor.writeValue(writer, hint); - try cbor.writeValue(writer, command_name); - - try menu.add_item_with_handler(value.items, menu_action); + try writer.print(" :{s}", .{hint}); + const label = fis.getWritten(); + try menu.add_item_with_handler(label, menu_action(command_name)); + self.menu_w = @max(self.menu_w, label.len + 1); } pub fn update(self: *Self) void { @@ -174,33 +143,7 @@ pub fn receive(_: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { return false; } -fn menu_on_render(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { - var description: []const u8 = undefined; - var hint: []const u8 = undefined; - var command_name: []const u8 = undefined; - var iter = button.opts.label; // label contains cbor - if (!(cbor.matchString(&iter, &description) catch false)) - description = "#ERROR#"; - if (!(cbor.matchString(&iter, &hint) catch false)) - hint = ""; - if (!(cbor.matchString(&iter, &command_name) catch false)) - command_name = ""; - - const label_len = description.len + hint.len; - var buf: [64]u8 = undefined; - const leader = blk: { - var fis = std.io.fixedBufferStream(&buf); - const writer = fis.writer(); - const leader = if (hint.len > 0) "." else " "; - _ = writer.write(" ") catch return false; - _ = writer.write(leader) catch return false; - _ = writer.write(leader) catch return false; - for (0..(self.max_desc_len - label_len - 5)) |_| - _ = writer.write(leader) catch return false; - writer.print(" ", .{}) catch return false; - break :blk fis.getWritten(); - }; - +fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { const style_base = theme.editor; const style_label = if (button.active) theme.editor_cursor else if (button.hover or selected) theme.editor_selection else style_base; if (button.active or button.hover or selected) { @@ -216,9 +159,8 @@ fn menu_on_render(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: button.plane.home(); } const style_text = if (tui.find_scope_style(theme, "keyword")) |sty| sty.style else style_label; - const style_leader = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor; const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_label; - + const sep = std.mem.indexOfScalar(u8, button.opts.label, ':') orelse button.opts.label.len; if (button.active) { button.plane.set_style(style_label); } else if (button.hover or selected) { @@ -227,35 +169,22 @@ fn menu_on_render(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: button.plane.set_style_bg_transparent(style_text); } const pointer = if (selected) "⏵" else " "; - _ = button.plane.print("{s}{s}", .{ pointer, description }) catch {}; - if (button.active or button.hover or selected) { - button.plane.set_style(style_leader); - } else { - button.plane.set_style_bg_transparent(style_leader); - } - _ = button.plane.print("{s}", .{leader}) catch {}; + _ = button.plane.print("{s}{s}", .{ pointer, button.opts.label[0..sep] }) catch {}; if (button.active or button.hover or selected) { button.plane.set_style(style_keybind); } else { button.plane.set_style_bg_transparent(style_keybind); } - _ = button.plane.print("{s}", .{hint}) catch {}; + _ = button.plane.print("{s}", .{button.opts.label[sep + 1 ..]}) catch {}; return false; } -fn menu_action(_: **Menu.State(*Self), button: *Button.State(*Menu.State(*Self))) void { - var description: []const u8 = undefined; - var hint: []const u8 = undefined; - var command_name: []const u8 = undefined; - var iter = button.opts.label; // label contains cbor - if (!(cbor.matchString(&iter, &description) catch false)) - description = "#ERROR#"; - if (!(cbor.matchString(&iter, &hint) catch false)) - hint = ""; - if (!(cbor.matchString(&iter, &command_name) catch false)) - command_name = ""; - - command.executeName(command_name, .{}) catch {}; +fn menu_action(comptime command_name: []const u8) *const fn (_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void { + return struct { + fn action(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void { + command.executeName(command_name, .{}) catch {}; + } + }.action; } pub fn render(self: *Self, theme: *const Widget.Theme) bool { @@ -270,35 +199,35 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool { const style_subtext = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor; if (self.plane.dim_x() > 120 and self.plane.dim_y() > 22) { - self.plane.cursor_move_yx(2, self.centerI(4, self.home_style.title.len * 8)) catch return false; - fonts.print_string_large(&self.plane, self.home_style.title, style_title) catch return false; + self.plane.cursor_move_yx(2, 4) catch return false; + fonts.print_string_large(&self.plane, root.application_title, style_title) catch return false; - self.plane.cursor_move_yx(10, self.centerI(8, self.home_style.subtext.len * 4)) catch return false; - fonts.print_string_medium(&self.plane, self.home_style.subtext, style_subtext) catch return false; + self.plane.cursor_move_yx(10, 8) catch return false; + fonts.print_string_medium(&self.plane, root.application_subtext, style_subtext) catch return false; - self.position_menu(self.v_center(15, self.menu_len, 15), self.center(10, self.menu_w)); + self.position_menu(15, 10); } else if (self.plane.dim_x() > 55 and self.plane.dim_y() > 16) { - self.plane.cursor_move_yx(2, self.centerI(4, self.home_style.title.len * 4)) catch return false; - fonts.print_string_medium(&self.plane, self.home_style.title, style_title) catch return false; + self.plane.cursor_move_yx(2, 4) catch return false; + fonts.print_string_medium(&self.plane, root.application_title, style_title) catch return false; self.plane.set_style_bg_transparent(style_subtext); - self.plane.cursor_move_yx(7, self.centerI(6, self.home_style.subtext.len)) catch return false; - _ = self.plane.print("{s}", .{self.home_style.subtext}) catch {}; + self.plane.cursor_move_yx(7, 6) catch return false; + _ = self.plane.print(root.application_subtext, .{}) catch {}; self.plane.set_style(theme.editor); - self.position_menu(self.v_center(9, self.menu_len, 9), self.center(8, self.menu_w)); + self.position_menu(9, 8); } else { self.plane.set_style_bg_transparent(style_title); - self.plane.cursor_move_yx(1, self.centerI(4, self.home_style.title.len)) catch return false; - _ = self.plane.print("{s}", .{self.home_style.title}) catch return false; + self.plane.cursor_move_yx(1, 4) catch return false; + _ = self.plane.print(root.application_title, .{}) catch return false; self.plane.set_style_bg_transparent(style_subtext); - self.plane.cursor_move_yx(3, self.centerI(6, self.home_style.subtext.len)) catch return false; - _ = self.plane.print("{s}", .{self.home_style.subtext}) catch {}; + self.plane.cursor_move_yx(3, 6) catch return false; + _ = self.plane.print(root.application_subtext, .{}) catch {}; self.plane.set_style(theme.editor); const x = @min(self.plane.dim_x() -| 32, 8); - self.position_menu(self.v_center(5, self.menu_len, 5), self.center(x, self.menu_w)); + self.position_menu(5, x); } const more = self.menu.render(theme); @@ -310,24 +239,6 @@ fn position_menu(self: *Self, y: usize, x: usize) void { self.menu.resize(.{ .y = box.y + y, .x = box.x + x, .w = self.menu_w }); } -fn center(self: *Self, non_centered: usize, w: usize) usize { - if (!self.home_style.centered) return non_centered; - const box = Widget.Box.from(self.plane); - const x = if (box.w > w) (box.w - w) / 2 else 0; - return box.x + x; -} - -fn centerI(self: *Self, non_centered: usize, w: usize) c_int { - return @intCast(self.center(non_centered, w)); -} - -fn v_center(self: *Self, non_centered: usize, h: usize, minoffset: usize) usize { - if (!self.home_style.centered) return non_centered; - const box = Widget.Box.from(self.plane); - const y = if (box.h > h) (box.h - h) / 2 else 0; - return box.y + @max(y, minoffset); -} - pub fn handle_resize(self: *Self, pos: Widget.Box) void { self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return; self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return; @@ -375,19 +286,125 @@ const cmds = struct { pub const home_sheeran_meta: Meta = .{}; }; -const Fire = @import("Fire.zig"); +const Fire = struct { + const px = "▀"; -fn splice(in: []const u8) []const u8 { - var out: []const u8 = ""; - var it = std.mem.splitAny(u8, in, "\n "); - var first = true; - while (it.next()) |item| { - if (first) { - first = false; - } else { - out = out ++ " "; + allocator: std.mem.Allocator, + plane: Plane, + prng: std.Random.DefaultPrng, + + //scope cache - spread fire + spread_px: u8 = 0, + spread_rnd_idx: u8 = 0, + spread_dst: usize = 0, + + FIRE_H: u16, + FIRE_W: u16, + FIRE_SZ: usize, + FIRE_LAST_ROW: usize, + + screen_buf: []u8, + + const MAX_COLOR = 256; + const LAST_COLOR = MAX_COLOR - 1; + + fn init(allocator: std.mem.Allocator, plane: Plane) !Fire { + const pos = Widget.Box.from(plane); + const FIRE_H = @as(u16, @intCast(pos.h)) * 2; + const FIRE_W = @as(u16, @intCast(pos.w)); + var self: Fire = .{ + .allocator = allocator, + .plane = plane, + .prng = std.Random.DefaultPrng.init(blk: { + var seed: u64 = undefined; + try std.posix.getrandom(std.mem.asBytes(&seed)); + break :blk seed; + }), + .FIRE_H = FIRE_H, + .FIRE_W = FIRE_W, + .FIRE_SZ = @as(usize, @intCast(FIRE_H)) * FIRE_W, + .FIRE_LAST_ROW = @as(usize, @intCast(FIRE_H - 1)) * FIRE_W, + .screen_buf = try allocator.alloc(u8, @as(usize, @intCast(FIRE_H)) * FIRE_W), + }; + + var buf_idx: usize = 0; + while (buf_idx < self.FIRE_SZ) : (buf_idx += 1) { + self.screen_buf[buf_idx] = fire_black; } - out = out ++ item; + + // last row is white...white is "fire source" + buf_idx = 0; + while (buf_idx < self.FIRE_W) : (buf_idx += 1) { + self.screen_buf[self.FIRE_LAST_ROW + buf_idx] = fire_white; + } + return self; } - return out; -} + + fn deinit(self: *Fire) void { + self.allocator.free(self.screen_buf); + } + + const fire_palette = [_]u8{ 0, 233, 234, 52, 53, 88, 89, 94, 95, 96, 130, 131, 132, 133, 172, 214, 215, 220, 220, 221, 3, 226, 227, 230, 195, 230 }; + const fire_black: u8 = 0; + const fire_white: u8 = fire_palette.len - 1; + + fn render(self: *Fire) void { + self.plane.home(); + var rand = self.prng.random(); + + //update fire buf + var doFire_x: u16 = 0; + while (doFire_x < self.FIRE_W) : (doFire_x += 1) { + var doFire_y: u16 = 0; + while (doFire_y < self.FIRE_H) : (doFire_y += 1) { + const doFire_idx = @as(usize, @intCast(doFire_y)) * self.FIRE_W + doFire_x; + + //spread fire + self.spread_px = self.screen_buf[doFire_idx]; + + //bounds checking + if ((self.spread_px == 0) and (doFire_idx >= self.FIRE_W)) { + self.screen_buf[doFire_idx - self.FIRE_W] = 0; + } else { + self.spread_rnd_idx = rand.intRangeAtMost(u8, 0, 3); + if (doFire_idx >= (self.spread_rnd_idx + 1)) { + self.spread_dst = doFire_idx - self.spread_rnd_idx + 1; + } else { + self.spread_dst = doFire_idx; + } + if (self.spread_dst >= self.FIRE_W) { + if (self.spread_px > (self.spread_rnd_idx & 1)) { + self.screen_buf[self.spread_dst - self.FIRE_W] = self.spread_px - (self.spread_rnd_idx & 1); + } else { + self.screen_buf[self.spread_dst - self.FIRE_W] = 0; + } + } + } + } + } + + //scope cache - fire 2 screen buffer + var frame_x: u16 = 0; + var frame_y: u16 = 0; + + // for each row + frame_y = 0; + while (frame_y < self.FIRE_H) : (frame_y += 2) { // 'paint' two rows at a time because of half height char + // for each col + frame_x = 0; + while (frame_x < self.FIRE_W) : (frame_x += 1) { + //each character rendered is actually to rows of 'pixels' + // - "hi" (current px row => fg char) + // - "low" (next row => bg color) + const px_hi = self.screen_buf[@as(usize, @intCast(frame_y)) * self.FIRE_W + frame_x]; + const px_lo = self.screen_buf[@as(usize, @intCast(frame_y + 1)) * self.FIRE_W + frame_x]; + + self.plane.set_fg_palindex(fire_palette[px_hi]) catch {}; + self.plane.set_bg_palindex(fire_palette[px_lo]) catch {}; + _ = self.plane.putstr(px) catch {}; + } + self.plane.cursor_move_yx(-1, 0) catch {}; + self.plane.cursor_move_rel(1, 0) catch {}; + } + } +}; diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index dafb048..51a360f 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -230,26 +230,6 @@ fn check_all_not_dirty(self: *const Self) command.Result { return tp.exit("unsaved changes"); } -fn open_style_config(self: *Self, Style: type) command.Result { - const file_name = try root.get_config_file_name(Style); - const style, const style_bufs: [][]const u8 = if (root.exists_config(Style)) blk: { - const style, const style_bufs = root.read_config(Style, self.allocator); - break :blk .{ style, style_bufs }; - } else .{ Style{}, &.{} }; - defer root.free_config(self.allocator, style_bufs); - var conf = std.ArrayList(u8).init(self.allocator); - defer conf.deinit(); - root.write_config_to_writer(Style, style, conf.writer()) catch {}; - tui.reset_drag_context(); - try self.create_editor(); - try command.executeName("open_scratch_buffer", command.fmt(.{ - file_name[0 .. file_name.len - ".json".len], - conf.items, - "conf", - })); - if (self.get_active_buffer()) |buffer| buffer.mark_not_ephemeral(); -} - const cmds = struct { pub const Target = Self; const Ctx = command.Context; @@ -434,15 +414,27 @@ const cmds = struct { pub const open_gui_config_meta: Meta = .{ .description = "Edit gui configuration" }; pub fn open_tabs_style_config(self: *Self, _: Ctx) Result { - try self.open_style_config(@import("status/tabs.zig").Style); + const Style = @import("status/tabs.zig").Style; + const file_name = try root.get_config_file_name(Style); + const tab_style, const tab_style_bufs: [][]const u8 = if (root.exists_config(Style)) blk: { + const tab_style, const tab_style_bufs = root.read_config(Style, self.allocator); + break :blk .{ tab_style, tab_style_bufs }; + } else .{ Style{}, &.{} }; + defer root.free_config(self.allocator, tab_style_bufs); + var conf = std.ArrayList(u8).init(self.allocator); + defer conf.deinit(); + root.write_config_to_writer(Style, tab_style, conf.writer()) catch {}; + tui.reset_drag_context(); + try self.create_editor(); + try command.executeName("open_scratch_buffer", command.fmt(.{ + file_name[0 .. file_name.len - ".json".len], + conf.items, + "conf", + })); + if (self.get_active_buffer()) |buffer| buffer.mark_not_ephemeral(); } pub const open_tabs_style_config_meta: Meta = .{ .description = "Edit tab style" }; - pub fn open_home_style_config(self: *Self, _: Ctx) Result { - try self.open_style_config(@import("home.zig").Style); - } - pub const open_home_style_config_meta: Meta = .{ .description = "Edit home screen" }; - pub fn create_scratch_buffer(self: *Self, ctx: Ctx) Result { const args = try ctx.args.clone(self.allocator); defer self.allocator.free(args.buf);