A pretty printer for zig
zig

pretty structs

altagos.dev 85e44017 c195ec1c

verified
+94 -5
+40 -1
example/main.zig
··· 9 9 10 10 const Hello = enum { world, developer }; 11 11 12 + const Gender = enum(u8) { male, female, nonbinary, other, _ }; 13 + 14 + const Person = struct { 15 + age: u8, 16 + gender: ?Gender, 17 + }; 18 + 19 + const Nested = struct { 20 + a: ChildA, 21 + b: ChildB, 22 + }; 23 + 24 + const ChildA = struct { 25 + child: ChildC, 26 + }; 27 + 28 + const ChildB = struct { 29 + hello: Hello, 30 + }; 31 + 32 + const ChildC = struct { 33 + person: Person, 34 + }; 35 + 12 36 pub fn main(init: std.process.Init) !void { 13 37 _ = init; 14 38 ··· 20 44 print("Boolean false - {f}\n", .{pretty(false)}); 21 45 print( 22 46 "Boolean true always with type name - {f}\n", 23 - .{Pretty(bool, .{ .always_show_type_names = true, .type_value_seperator = ": " }).init(true)}, 47 + .{Pretty(bool, .{ .always_show_type_names = true, .type_value_sep = ": " }).init(true)}, 24 48 ); 25 49 26 50 print("\nUnsigned Integers\n", .{}); ··· 54 78 print("\nOptionals\n", .{}); 55 79 print("Pretty optional = null - {f}\n", .{pretty(opt_null)}); 56 80 print("Pretty optional = not null - {f}\n", .{pretty(opt_not_null)}); 81 + 82 + const person = Person{ .age = 13, .gender = null }; 83 + 84 + const nested = Nested{ 85 + .a = .{ .child = .{ .person = person } }, 86 + .b = .{ .hello = .world }, 87 + }; 88 + 89 + print("\nStructs\n", .{}); 90 + print("Pretty simple struct - {f}\n", .{pretty(person)}); 91 + print( 92 + "Pretty simple inlined struct - {f}\n", 93 + .{Pretty(Person, .{ .inline_structs = true }).init(person)}, 94 + ); 95 + print("Pretty nested struct - {f}\n", .{pretty(nested)}); 57 96 }
+54 -4
pretty.zig
··· 6 6 7 7 pub const Options = struct { 8 8 indent_width: comptime_int = 2, 9 + inline_structs: bool = false, 9 10 10 11 show_type_names: bool = true, 11 - always_show_type_names: bool = true, 12 + always_show_type_names: bool = false, 12 13 13 14 field_name_type_sep: []const u8 = ": ", 14 15 type_value_sep: []const u8 = " = ", ··· 28 29 const global = struct { 29 30 var tty: ?Io.Terminal = null; 30 31 }; 32 + const cctx: ComptimeContext = ComptimeContext{ .options = options }; 31 33 32 34 return struct { 33 35 value: T, ··· 46 48 global.tty.?.writer = w; 47 49 } 48 50 49 - const comp_ctx = ComptimeContext{ .options = options }; 50 - const run_ctx = RuntimeContext{ 51 + const rctx = RuntimeContext{ 51 52 .out = w, 52 53 .tty = global.tty.?, 53 54 }; 54 55 55 - return innerFmt(T, comp_ctx, run_ctx, this.value, .{}); 56 + return innerFmt(T, cctx, rctx, this.value, .{}); 56 57 } 57 58 }; 58 59 } ··· 128 129 => formatValue(rctx, value), 129 130 130 131 .optional => |opt| formatOptional(opt.child, cctx, rctx, value), 132 + .@"struct" => |st| formatStruct(T, st, cctx, rctx, value), 131 133 132 134 else => { 133 135 rctx.setColor(.red); ··· 184 186 formatNull(rctx); 185 187 } 186 188 189 + inline fn formatStruct( 190 + comptime T: type, 191 + comptime st: Type.Struct, 192 + comptime cctx: ComptimeContext, 193 + rctx: RuntimeContext, 194 + value: T, 195 + ) !void { 196 + const next_cctx = ComptimeContext{ 197 + .depth = cctx.depth + 1, 198 + .indent_level = cctx.indent_level + 1, 199 + .exited_comptime = cctx.exited_comptime, 200 + .options = cctx.options, 201 + }; 202 + 203 + if (cctx.options.inline_structs) { 204 + rctx.setColor(.dim); 205 + try rctx.write(".{ "); 206 + rctx.resetColor(); 207 + } 208 + 209 + comptime var index: comptime_int = 0; 210 + inline for (st.fields) |field| { 211 + indent(next_cctx, rctx); 212 + if (index != 0 and cctx.options.inline_structs) try rctx.write(", "); 213 + 214 + rctx.setColor(.green); 215 + try rctx.write("." ++ field.name ++ cctx.options.field_name_type_sep); 216 + rctx.resetColor(); 217 + 218 + try innerFmt(field.type, next_cctx, rctx, @field(value, field.name), .{}); 219 + 220 + index += 1; 221 + } 222 + 223 + if (cctx.options.inline_structs) { 224 + rctx.setColor(.dim); 225 + try rctx.write(" }"); 226 + rctx.resetColor(); 227 + } 228 + } 229 + 187 230 inline fn formatType(ctx: RuntimeContext, value: type) !void { 188 231 ctx.setColor(.bright_blue); 189 232 ctx.setColor(.bold); ··· 196 239 try ctx.print("{}", .{value}); 197 240 ctx.resetColor(); 198 241 } 242 + 243 + inline fn indent(comptime cctx: ComptimeContext, rctx: RuntimeContext) void { 244 + if (cctx.options.inline_structs) return; 245 + 246 + const text: [cctx.depth * cctx.options.indent_width]u8 = @splat(' '); 247 + rctx.write("\n" ++ text) catch {}; 248 + }