From f630fd229d6dc82dc5c0e33f810d9fcdc8c55a90 Mon Sep 17 00:00:00 2001 From: Tabre Perez Date: Wed, 15 Jul 2026 12:56:53 -0500 Subject: [PATCH 1/2] feat: table widget uses "{f}" formatting of structs implementing a format method --- src/widgets/Table.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/widgets/Table.zig b/src/widgets/Table.zig index 38816b55..372bc1b2 100644 --- a/src/widgets/Table.zig +++ b/src/widgets/Table.zig @@ -354,7 +354,15 @@ pub fn drawTable( } }, else => { - break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); + if (alloc) |_alloc| { + if (comptime std.meta.hasFn(ItemT, "format")) { + break :nonStr try fmt.allocPrint(_alloc, "{f}", .{item}); + } else { + break :nonStr try fmt.allocPrint(_alloc, "{any}", .{item}); + } + } else { + break :nonStr fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); + } }, } }, From d63a23c593c9b82f0b2886840161fa1f1df983e9 Mon Sep 17 00:00:00 2001 From: TimBot Date: Thu, 16 Jul 2026 12:26:58 -0500 Subject: [PATCH 2/2] widgets: format optional table cell values Table cells can use a type's format() method with the {f} formatter, but optional payloads still fell back to {any} after unwrapping. This made optional custom values render differently from non-optional values.\n\nRoute both cases through a shared formatter and use it for optional payloads too. Add unit coverage for formatted table cell values without requiring terminal I/O. --- src/widgets/Table.zig | 51 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/widgets/Table.zig b/src/widgets/Table.zig index 372bc1b2..a9cc7169 100644 --- a/src/widgets/Table.zig +++ b/src/widgets/Table.zig @@ -349,20 +349,12 @@ pub fn drawTable( break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{s}", .{opt_item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); }, else => { - break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{opt_item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); + break :nonStr try formatCellValue(alloc, opt_item, DataT); }, } }, else => { - if (alloc) |_alloc| { - if (comptime std.meta.hasFn(ItemT, "format")) { - break :nonStr try fmt.allocPrint(_alloc, "{f}", .{item}); - } else { - break :nonStr try fmt.allocPrint(_alloc, "{any}", .{item}); - } - } else { - break :nonStr fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); - } + break :nonStr try formatCellValue(alloc, item, DataT); }, } }, @@ -392,6 +384,20 @@ pub fn drawTable( } } +fn formatCellValue( + alloc: ?mem.Allocator, + item: anytype, + comptime DataT: type, +) ![]const u8 { + if (alloc) |_alloc| { + if (comptime std.meta.hasFn(@TypeOf(item), "format")) { + return try fmt.allocPrint(_alloc, "{f}", .{item}); + } + return try fmt.allocPrint(_alloc, "{any}", .{item}); + } + return fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); +} + /// Calculate the Column Width of `col` using the provided Number of Headers (`num_hdrs`), Width Style (`style`), and Table Window (`table_win`). pub fn calcColWidth( col: u16, @@ -417,3 +423,28 @@ pub fn calcColWidth( }, }; } + +const FormatTestValue = struct { + value: u8, + + pub fn format(self: FormatTestValue, writer: anytype) !void { + try writer.print("formatted:{d}", .{self.value}); + } +}; + +test "formatCellValue uses format method" { + var arena: heap.ArenaAllocator = .init(std.testing.allocator); + defer arena.deinit(); + + const text = try formatCellValue(arena.allocator(), FormatTestValue{ .value = 42 }, struct { value: FormatTestValue }); + try std.testing.expectEqualStrings("formatted:42", text); +} + +test "formatCellValue uses format method for optional payloads" { + var arena: heap.ArenaAllocator = .init(std.testing.allocator); + defer arena.deinit(); + + const item: ?FormatTestValue = .{ .value = 7 }; + const text = try formatCellValue(arena.allocator(), item.?, struct { value: ?FormatTestValue }); + try std.testing.expectEqualStrings("formatted:7", text); +}