diff --git a/src/tui/fonts.zig b/src/tui/fonts.zig index c19685e..35ef2d6 100644 --- a/src/tui/fonts.zig +++ b/src/tui/fonts.zig @@ -242,6 +242,12 @@ pub fn get_digit(n: anytype, style_: DigitStyle) []const u8 { }; } +pub fn get_digit_ascii(char: []const u8, style_: DigitStyle) []const u8 { + if (char.len == 0) return " "; + if (char[0] > '9' or char[0] < '0') return char; + return get_digit(char[0] - '0', style_); +} + const digits_ascii: [10][]const u8 = .{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; const digits_digtl: [10][]const u8 = .{ "🯰", "🯱", "🯲", "🯳", "🯴", "🯵", "🯶", "🯷", "🯸", "🯹" }; const digits_subsc: [10][]const u8 = .{ "₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉" }; diff --git a/src/tui/status/blank.zig b/src/tui/status/blank.zig index f4bb74f..8901fd0 100644 --- a/src/tui/status/blank.zig +++ b/src/tui/status/blank.zig @@ -13,11 +13,17 @@ const Self = @This(); pub fn Create(comptime layout_: Widget.Layout) @import("widget.zig").CreateFunction { return struct { - fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { + fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) @import("widget.zig").CreateError!Widget { + const layout__ = if (layout_ == .static) blk: { + if (arg) |str_size| { + const size = std.fmt.parseInt(usize, str_size, 10) catch break :blk layout_; + break :blk Widget.Layout{ .static = size }; + } else break :blk layout_; + } else layout_; const self: *Self = try allocator.create(Self); self.* = .{ .plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent), - .layout_ = layout_, + .layout_ = layout__, .on_event = event_handler, }; return Widget.to(self); diff --git a/src/tui/status/clock.zig b/src/tui/status/clock.zig index f1d6d38..1945bca 100644 --- a/src/tui/status/clock.zig +++ b/src/tui/status/clock.zig @@ -18,7 +18,7 @@ tz: zeit.timezone.TimeZone, const Self = @This(); -pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { var env = std.process.getEnvMap(allocator) catch |e| { std.log.err("clock: std.process.getEnvMap failed with {any}", .{e}); return error.WidgetInitFailed; diff --git a/src/tui/status/diagstate.zig b/src/tui/status/diagstate.zig index 8a7f057..5ddb304 100644 --- a/src/tui/status/diagstate.zig +++ b/src/tui/status/diagstate.zig @@ -18,7 +18,7 @@ rendered: [:0]const u8 = "", const Self = @This(); -pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { return Button.create_widget(Self, allocator, parent, .{ .ctx = .{}, .label = "", diff --git a/src/tui/status/filestate.zig b/src/tui/status/filestate.zig index 1681f36..9ecc932 100644 --- a/src/tui/status/filestate.zig +++ b/src/tui/status/filestate.zig @@ -38,7 +38,7 @@ utf8_sanitized: bool = false, const project_icon = ""; const Self = @This(); -pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const btn = try Button.create(Self, allocator, parent, .{ .ctx = .{ .allocator = allocator, diff --git a/src/tui/status/keybindstate.zig b/src/tui/status/keybindstate.zig index ebf013a..1c2feee 100644 --- a/src/tui/status/keybindstate.zig +++ b/src/tui/status/keybindstate.zig @@ -11,7 +11,7 @@ plane: Plane, const Self = @This(); -pub fn create(allocator: std.mem.Allocator, parent: Plane, _: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: std.mem.Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const self: *Self = try allocator.create(Self); self.* = .{ .allocator = allocator, diff --git a/src/tui/status/keystate.zig b/src/tui/status/keystate.zig index 56b818f..ca674a8 100644 --- a/src/tui/status/keystate.zig +++ b/src/tui/status/keystate.zig @@ -29,7 +29,7 @@ const Self = @This(); const idle_msg = "🐶"; pub const width = idle_msg.len + 20; -pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const frame_rate = tp.env.get().num("frame-rate"); const self: *Self = try allocator.create(Self); self.* = .{ diff --git a/src/tui/status/linenumstate.zig b/src/tui/status/linenumstate.zig index 3d1c11a..b545e8e 100644 --- a/src/tui/status/linenumstate.zig +++ b/src/tui/status/linenumstate.zig @@ -9,6 +9,9 @@ const EventHandler = @import("EventHandler"); const Widget = @import("../Widget.zig"); const Button = @import("../Button.zig"); +const fonts = @import("../fonts.zig"); + +const DigitStyle = fonts.DigitStyle; const utf8_sanitized_warning = "  UTF"; @@ -19,12 +22,32 @@ buf: [256]u8 = undefined, rendered: [:0]const u8 = "", eol_mode: Buffer.EolMode = .lf, utf8_sanitized: bool = false, +padding: ?usize, +leader: ?Leader, +style: ?DigitStyle, +const Leader = enum { + space, + zero, +}; const Self = @This(); -pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) @import("widget.zig").CreateError!Widget { + const padding: ?usize, const leader: ?Leader, const style: ?DigitStyle = if (arg) |fmt| blk: { + var it = std.mem.splitScalar(u8, fmt, ','); + break :blk .{ + if (it.next()) |size| std.fmt.parseInt(usize, size, 10) catch null else null, + if (it.next()) |leader| std.meta.stringToEnum(Leader, leader) orelse null else null, + if (it.next()) |style| std.meta.stringToEnum(DigitStyle, style) orelse null else null, + }; + } else .{ null, null, null }; + return Button.create_widget(Self, allocator, parent, .{ - .ctx = .{}, + .ctx = .{ + .padding = padding, + .leader = leader, + .style = style, + }, .label = "", .on_click = on_click, .on_layout = layout, @@ -67,11 +90,30 @@ fn format(self: *Self) void { .lf => "", .crlf => " [␍␊]", }; - std.fmt.format(writer, "{s} Ln {d}, Col {d} ", .{ eol_mode, self.line + 1, self.column + 1 }) catch {}; + std.fmt.format(writer, "{s} Ln ", .{eol_mode}) catch {}; + self.format_count(writer, self.line + 1, self.padding orelse 0) catch {}; + std.fmt.format(writer, ", Col ", .{}) catch {}; + self.format_count(writer, self.column + 1, self.padding orelse 0) catch {}; + std.fmt.format(writer, " ", .{}) catch {}; self.rendered = @ptrCast(fbs.getWritten()); self.buf[self.rendered.len] = 0; } +fn format_count(self: *Self, writer: anytype, value: usize, width: usize) !void { + var buf: [64]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + const writer_ = fbs.writer(); + try std.fmt.format(writer_, "{d}", .{value}); + const value_str = fbs.getWritten(); + + const char: []const u8 = switch (self.leader orelse .space) { + .space => " ", + .zero => "0", + }; + for (0..(@max(value_str.len, width) - value_str.len)) |_| try writer.writeAll(fonts.get_digit_ascii(char, self.style orelse .ascii)); + for (value_str, 0..) |_, i| try writer.writeAll(fonts.get_digit_ascii(value_str[i .. i + 1], self.style orelse .ascii)); +} + pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message) error{Exit}!bool { var eol_mode: Buffer.EolModeTag = @intFromEnum(Buffer.EolMode.lf); if (try m.match(.{ "E", "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.extract(&self.column) })) { diff --git a/src/tui/status/minilog.zig b/src/tui/status/minilog.zig index 676103c..a2644fb 100644 --- a/src/tui/status/minilog.zig +++ b/src/tui/status/minilog.zig @@ -26,7 +26,7 @@ const Level = enum { err, }; -pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const self: *Self = try allocator.create(Self); self.* = .{ .plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent), diff --git a/src/tui/status/modestate.zig b/src/tui/status/modestate.zig index 4529c31..16ab14d 100644 --- a/src/tui/status/modestate.zig +++ b/src/tui/status/modestate.zig @@ -12,7 +12,7 @@ const Button = @import("../Button.zig"); const tui = @import("../tui.zig"); const CreateError = @import("widget.zig").CreateError; -pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) CreateError!Widget { return Button.create_widget(void, allocator, parent, .{ .ctx = {}, .label = tui.get_mode(), diff --git a/src/tui/status/modstate.zig b/src/tui/status/modstate.zig index 351a373..4555cef 100644 --- a/src/tui/status/modstate.zig +++ b/src/tui/status/modstate.zig @@ -19,7 +19,7 @@ const Self = @This(); pub const width = 8; -pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const self: *Self = try allocator.create(Self); self.* = .{ .plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent), diff --git a/src/tui/status/selectionstate.zig b/src/tui/status/selectionstate.zig index 8ac3d99..f606a5c 100644 --- a/src/tui/status/selectionstate.zig +++ b/src/tui/status/selectionstate.zig @@ -18,7 +18,7 @@ on_event: ?EventHandler, const Self = @This(); -pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const self: *Self = try allocator.create(Self); self.* = .{ .plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent), diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index d3a77c8..dbf5bf6 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -52,7 +52,7 @@ const @"style.config" = struct { }; pub const Style = @"style.config"; -pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget { +pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget { const self = try allocator.create(TabBar); self.* = try TabBar.init(allocator, parent, event_handler); return Widget.to(self); diff --git a/src/tui/status/widget.zig b/src/tui/status/widget.zig index 4b87b06..80ebc45 100644 --- a/src/tui/status/widget.zig +++ b/src/tui/status/widget.zig @@ -21,16 +21,24 @@ const widgets = std.static_string_map.StaticStringMap(CreateFunction).initCompti .{ "tabs", @import("tabs.zig").create }, }); pub const CreateError = error{ OutOfMemory, WidgetInitFailed }; -pub const CreateFunction = *const fn (allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!Widget; +pub const CreateFunction = *const fn (allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) CreateError!Widget; + +pub fn create(descriptor: []const u8, allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!?Widget { + var it = std.mem.splitScalar(u8, descriptor, ':'); + const name = it.next() orelse { + const logger = log.logger("statusbar"); + logger.print_err("config", "bad widget descriptor \"{s}\" (see log)", .{descriptor}); + return null; + }; + const arg = it.next(); -pub fn create(name: []const u8, allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!?Widget { const create_ = widgets.get(name) orelse { const logger = log.logger("statusbar"); logger.print_err("config", "unknown widget \"{s}\" (see log)", .{name}); log_widgets(logger); return null; }; - return try create_(allocator, parent, event_handler); + return try create_(allocator, parent, event_handler, arg); } fn log_widgets(logger: anytype) void {