From 95a67e5f061bf10742002c4a0cea360e6172f929 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 20 Jan 2024 15:24:17 -0800 Subject: [PATCH] config: support only formatting changed fields --- src/config/formatter.zig | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/config/formatter.zig b/src/config/formatter.zig index 68bf5ee2e..2588ee196 100644 --- a/src/config/formatter.zig +++ b/src/config/formatter.zig @@ -1,6 +1,8 @@ const formatter = @This(); const std = @import("std"); +const Allocator = std.mem.Allocator; const Config = @import("Config.zig"); +const Key = @import("key.zig").Key; /// Returns a single entry formatter for the given field name and writer. pub fn entryFormatter( @@ -126,8 +128,12 @@ pub fn formatEntry( /// config in a file-like format. This uses more generous whitespace, /// can include comments, etc. pub const FileFormatter = struct { + alloc: Allocator, config: *const Config, + /// Only include changed values from the default. + changed: bool = false, + /// Implements std.fmt so it can be used directly with std.fmt. pub fn format( self: FileFormatter, @@ -138,14 +144,31 @@ pub const FileFormatter = struct { _ = layout; _ = opts; + // If we're change-tracking then we need the default config to + // compare against. + var default: ?Config = if (self.changed) + try Config.default(self.alloc) + else + null; + defer if (default) |*v| v.deinit(); + inline for (@typeInfo(Config).Struct.fields) |field| { if (field.name[0] == '_') continue; - try formatEntry( - field.type, - field.name, - @field(self.config, field.name), - writer, - ); + + const value = @field(self.config, field.name); + const do_format = if (default) |d| format: { + const key = @field(Key, field.name); + break :format d.changed(self.config, key); + } else true; + + if (do_format) { + try formatEntry( + field.type, + field.name, + value, + writer, + ); + } } } }; @@ -160,7 +183,28 @@ test "format default config" { defer buf.deinit(); // We just make sure this works without errors. We aren't asserting output. - const fmt: FileFormatter = .{ .config = &cfg }; + const fmt: FileFormatter = .{ .alloc = alloc, .config = &cfg }; + try std.fmt.format(buf.writer(), "{}", .{fmt}); + + //std.log.warn("{s}", .{buf.items}); +} + +test "format default config changed" { + const testing = std.testing; + const alloc = testing.allocator; + var cfg = try Config.default(alloc); + defer cfg.deinit(); + cfg.@"font-size" = 42; + + var buf = std.ArrayList(u8).init(alloc); + defer buf.deinit(); + + // We just make sure this works without errors. We aren't asserting output. + const fmt: FileFormatter = .{ + .alloc = alloc, + .config = &cfg, + .changed = true, + }; try std.fmt.format(buf.writer(), "{}", .{fmt}); //std.log.warn("{s}", .{buf.items});