config: support only formatting changed fields

This commit is contained in:
Mitchell Hashimoto
2024-01-20 15:24:17 -08:00
parent dbb808ae93
commit 95a67e5f06

View File

@ -1,6 +1,8 @@
const formatter = @This(); const formatter = @This();
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator;
const Config = @import("Config.zig"); const Config = @import("Config.zig");
const Key = @import("key.zig").Key;
/// Returns a single entry formatter for the given field name and writer. /// Returns a single entry formatter for the given field name and writer.
pub fn entryFormatter( pub fn entryFormatter(
@ -126,8 +128,12 @@ pub fn formatEntry(
/// config in a file-like format. This uses more generous whitespace, /// config in a file-like format. This uses more generous whitespace,
/// can include comments, etc. /// can include comments, etc.
pub const FileFormatter = struct { pub const FileFormatter = struct {
alloc: Allocator,
config: *const Config, 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. /// Implements std.fmt so it can be used directly with std.fmt.
pub fn format( pub fn format(
self: FileFormatter, self: FileFormatter,
@ -138,14 +144,31 @@ pub const FileFormatter = struct {
_ = layout; _ = layout;
_ = opts; _ = 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| { inline for (@typeInfo(Config).Struct.fields) |field| {
if (field.name[0] == '_') continue; if (field.name[0] == '_') continue;
try formatEntry(
field.type, const value = @field(self.config, field.name);
field.name, const do_format = if (default) |d| format: {
@field(self.config, field.name), const key = @field(Key, field.name);
writer, 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(); defer buf.deinit();
// We just make sure this works without errors. We aren't asserting output. // 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}); try std.fmt.format(buf.writer(), "{}", .{fmt});
//std.log.warn("{s}", .{buf.items}); //std.log.warn("{s}", .{buf.items});