feat(nested config files)
Adds a config_files option to config.json that allows the user to specify one or more config files to load in addition to the main config file. For me this allows me to keep my flow configuration in a shared dotfiles repository managed by git.
This commit is contained in:
parent
a6b29e4fe9
commit
194fe70d6e
3 changed files with 67 additions and 3 deletions
|
@ -22,3 +22,5 @@ top_bar: []const u8 = "",
|
|||
bottom_bar: []const u8 = "mode file log selection diagnostics keybind linenumber clock spacer",
|
||||
|
||||
lsp_request_timeout: usize = 10,
|
||||
|
||||
config_files: []const u8 = "",
|
||||
|
|
|
@ -393,6 +393,9 @@ const config = @import("config");
|
|||
|
||||
pub fn read_config(allocator: std.mem.Allocator, buf: *?[]const u8) config {
|
||||
const file_name = get_app_config_file_name(application_name) catch return .{};
|
||||
return read_config_at(allocator, buf, file_name);
|
||||
}
|
||||
pub fn read_config_at(allocator: std.mem.Allocator, buf: *?[]const u8, file_name: []const u8) config {
|
||||
return read_json_config_file(allocator, file_name, buf) catch |e| {
|
||||
log.logger("config").print_err("read_config", "error reading config file: {any}", .{e});
|
||||
return .{};
|
||||
|
|
|
@ -82,9 +82,21 @@ fn start(args: StartArgs) tp.result {
|
|||
|
||||
fn init(allocator: Allocator) !*Self {
|
||||
var self = try allocator.create(Self);
|
||||
var conf_buf: ?[]const u8 = null;
|
||||
var conf = root.read_config(allocator, &conf_buf);
|
||||
defer if (conf_buf) |buf| allocator.free(buf);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -211,6 +223,53 @@ 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());
|
||||
|
|
Loading…
Add table
Reference in a new issue