From 7253668ec20b0a79e41930ec4ba9e189d605cc7e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 23 Mar 2026 09:11:18 -0700 Subject: [PATCH] config: move file formatter to dedicated file to prevent import bloat --- src/config.zig | 3 +- src/config/formatter.zig | 103 +------------------------------ src/config/formatter_file.zig | 110 ++++++++++++++++++++++++++++++++++ src/input/key.zig | 1 - 4 files changed, 113 insertions(+), 104 deletions(-) create mode 100644 src/config/formatter_file.zig diff --git a/src/config.zig b/src/config.zig index 314fb49ee..289b6a811 100644 --- a/src/config.zig +++ b/src/config.zig @@ -2,6 +2,7 @@ const builtin = @import("builtin"); const file_load = @import("config/file_load.zig"); const formatter = @import("config/formatter.zig"); +const formatter_file = @import("config/formatter_file.zig"); pub const Config = @import("config/Config.zig"); pub const conditional = @import("config/conditional.zig"); pub const io = @import("config/io.zig"); @@ -10,7 +11,7 @@ pub const edit = @import("config/edit.zig"); pub const url = @import("config/url.zig"); pub const ConditionalState = conditional.State; -pub const FileFormatter = formatter.FileFormatter; +pub const FileFormatter = formatter_file.FileFormatter; pub const entryFormatter = formatter.entryFormatter; pub const formatEntry = formatter.formatEntry; pub const preferredDefaultFilePath = file_load.preferredDefaultFilePath; diff --git a/src/config/formatter.zig b/src/config/formatter.zig index dcf99167d..00d946f88 100644 --- a/src/config/formatter.zig +++ b/src/config/formatter.zig @@ -1,8 +1,7 @@ const formatter = @This(); + const std = @import("std"); const Allocator = std.mem.Allocator; -const help_strings = @import("help_strings"); -const Config = @import("Config.zig"); const Key = @import("key.zig").Key; /// Returns a single entry formatter for the given field name and writer. @@ -125,106 +124,6 @@ pub fn formatEntry( @compileError("missing case for type"); } -/// FileFormatter is a formatter implementation that outputs the -/// config in a file-like format. This uses more generous whitespace, -/// can include comments, etc. -pub const FileFormatter = struct { - alloc: Allocator, - config: *const Config, - - /// Include comments for documentation of each key - docs: bool = false, - - /// 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, - writer: *std.Io.Writer, - ) std.Io.Writer.Error!void { - @setEvalBranchQuota(10_000); - - // If we're change-tracking then we need the default config to - // compare against. - var default: ?Config = if (self.changed) - Config.default(self.alloc) catch return error.WriteFailed - else - null; - defer if (default) |*v| v.deinit(); - - inline for (@typeInfo(Config).@"struct".fields) |field| { - if (field.name[0] == '_') continue; - - 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) { - const do_docs = self.docs and @hasDecl(help_strings.Config, field.name); - if (do_docs) { - const help = @field(help_strings.Config, field.name); - var lines = std.mem.splitScalar(u8, help, '\n'); - while (lines.next()) |line| { - try writer.print("# {s}\n", .{line}); - } - } - - formatEntry( - field.type, - field.name, - value, - writer, - ) catch return error.WriteFailed; - - if (do_docs) try writer.print("\n", .{}); - } - } - } -}; - -test "format default config" { - const testing = std.testing; - const alloc = testing.allocator; - var cfg = try Config.default(alloc); - defer cfg.deinit(); - - var buf: std.Io.Writer.Allocating = .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, - }; - try fmt.format(&buf.writer); - - //std.log.warn("{s}", .{buf.written()}); -} - -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.Io.Writer.Allocating = .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 fmt.format(&buf.writer); - - //std.log.warn("{s}", .{buf.written()}); -} - test "formatEntry bool" { const testing = std.testing; diff --git a/src/config/formatter_file.zig b/src/config/formatter_file.zig new file mode 100644 index 000000000..4bc44c0e5 --- /dev/null +++ b/src/config/formatter_file.zig @@ -0,0 +1,110 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const Config = @import("Config.zig"); +const Key = @import("key.zig").Key; +const help_strings = @import("help_strings"); +const formatter = @import("formatter.zig"); + +// IMPORTANT: This is in a seperate file from formatter.zig because it +// puts a build-time dependency on Config.zig which brings in too much +// into libghostty-vt tests which reference some formattable types. + +/// FileFormatter is a formatter implementation that outputs the +/// config in a file-like format. This uses more generous whitespace, +/// can include comments, etc. +pub const FileFormatter = struct { + alloc: Allocator, + config: *const Config, + + /// Include comments for documentation of each key + docs: bool = false, + + /// 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, + writer: *std.Io.Writer, + ) std.Io.Writer.Error!void { + @setEvalBranchQuota(10_000); + + // If we're change-tracking then we need the default config to + // compare against. + var default: ?Config = if (self.changed) + Config.default(self.alloc) catch return error.WriteFailed + else + null; + defer if (default) |*v| v.deinit(); + + inline for (@typeInfo(Config).@"struct".fields) |field| { + if (field.name[0] == '_') continue; + + 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) { + const do_docs = self.docs and @hasDecl(help_strings.Config, field.name); + if (do_docs) { + const help = @field(help_strings.Config, field.name); + var lines = std.mem.splitScalar(u8, help, '\n'); + while (lines.next()) |line| { + try writer.print("# {s}\n", .{line}); + } + } + + formatter.formatEntry( + field.type, + field.name, + value, + writer, + ) catch return error.WriteFailed; + + if (do_docs) try writer.print("\n", .{}); + } + } + } +}; + +test "format default config" { + const testing = std.testing; + const alloc = testing.allocator; + var cfg = try Config.default(alloc); + defer cfg.deinit(); + + var buf: std.Io.Writer.Allocating = .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, + }; + try fmt.format(&buf.writer); + + //std.log.warn("{s}", .{buf.written()}); +} + +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.Io.Writer.Allocating = .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 fmt.format(&buf.writer); + + //std.log.warn("{s}", .{buf.written()}); +} diff --git a/src/input/key.zig b/src/input/key.zig index a929a0323..9c04f01e0 100644 --- a/src/input/key.zig +++ b/src/input/key.zig @@ -2,7 +2,6 @@ const std = @import("std"); const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const cimgui = @import("dcimgui"); -const OptionAsAlt = @import("config.zig").OptionAsAlt; pub const Mods = @import("key_mods.zig").Mods; -- 2.51.2