refactor(nested config files): simplify and avoid duplicate code

Also, fix a small use after free bug.
This commit is contained in:
CJ van den Berg 2025-01-06 12:09:11 +01:00
parent 194fe70d6e
commit aa95e78a80
2 changed files with 45 additions and 80 deletions

View file

@ -83,20 +83,8 @@ fn start(args: StartArgs) tp.result {
fn init(allocator: Allocator) !*Self {
var self = try allocator.create(Self);
var conf_bufs: std.ArrayListUnmanaged([]const u8) = .{};
defer {
for (conf_bufs.items) |buf| {
allocator.free(buf);
}
conf_bufs.deinit(allocator);
}
var conf = blk: {
var maybe_buf: ?[]const u8 = null;
const conf = root.read_config(allocator, &maybe_buf);
if (maybe_buf) |buf| try conf_bufs.append(allocator, buf);
break :blk conf;
};
try loadConfigFiles(allocator, &conf_bufs, &conf, conf.config_files);
var conf, const conf_bufs = root.read_config(allocator);
defer root.free_config(allocator, conf_bufs);
const theme = get_theme_by_name(conf.theme) orelse get_theme_by_name("dark_modern") orelse return tp.exit("unknown theme");
conf.theme = theme.name;
@ -104,6 +92,7 @@ fn init(allocator: Allocator) !*Self {
conf.input_mode = try allocator.dupe(u8, conf.input_mode);
conf.top_bar = try allocator.dupe(u8, conf.top_bar);
conf.bottom_bar = try allocator.dupe(u8, conf.bottom_bar);
conf.config_files = try allocator.dupe(u8, conf.config_files);
if (build_options.gui) conf.enable_terminal_cursor = false;
const frame_rate: usize = @intCast(tp.env.get().num("frame-rate"));
@ -223,53 +212,6 @@ fn deinit(self: *Self) void {
self.allocator.destroy(self);
}
fn loadConfigFiles(
allocator: std.mem.Allocator,
conf_bufs: *std.ArrayListUnmanaged([]const u8),
final_conf: *config,
config_files: []const u8,
) error{OutOfMemory}!void {
if (config_files.len == 0) return;
var it = std.mem.splitScalar(u8, config_files, std.fs.path.delimiter);
while (it.next()) |path| {
var maybe_buf: ?[]const u8 = null;
const conf = root.read_config_at(allocator, &maybe_buf, path);
if (maybe_buf) |buf| try conf_bufs.append(allocator, buf);
if (conf.config_files.len > 0) {
// just disallow nested config for now as we'd have to establish some
// sort of priority
std.log.err("{s}: ignoring nested 'config_files'", .{path});
}
inline for (std.meta.fields(config)) |field| {
if (comptime std.mem.eql(u8, field.name, "config_files")) continue;
const new_value_ref = &@field(conf, field.name);
const default_value_ref: *const field.type = @alignCast(@ptrCast(field.default_value));
const is_default = switch (field.type) {
bool, usize => new_value_ref.* == default_value_ref.*,
[]const u8 => std.mem.eql(u8, new_value_ref.*, default_value_ref.*),
else => @compileError("unsupported type: " ++ @typeName(field.type)),
};
const value_spec: []const u8 = switch (field.type) {
bool, usize => "",
[]const u8 => "s",
else => @compileError("unsupported type: " ++ @typeName(field.type)),
};
if (!is_default) {
std.log.info("{s} override {s} with {" ++ value_spec ++ "}", .{
path,
field.name,
new_value_ref.*,
});
@field(final_conf, field.name) = new_value_ref.*;
}
}
}
}
fn listen_sigwinch(self: *Self) tp.result {
if (self.sigwinch_signal) |old| old.deinit();
self.sigwinch_signal = tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"})) catch |e| return tp.exit_error(e, @errorReturnTrace());