diff --git a/build.zig b/build.zig index a2879f4..803c559 100644 --- a/build.zig +++ b/build.zig @@ -252,6 +252,13 @@ pub fn build_exe( }, }); + const gui_config_mod = b.createModule(.{ + .root_source_file = b.path("src/gui_config.zig"), + .imports = &.{ + .{ .name = "cbor", .module = cbor_mod }, + }, + }); + const log_mod = b.createModule(.{ .root_source_file = b.path("src/log.zig"), .imports = &.{ @@ -324,6 +331,7 @@ pub fn build_exe( // TODO: we should be able to work without these modules .{ .name = "vaxis", .module = vaxis_mod }, .{ .name = "color", .module = color_mod }, + .{ .name = "gui_config", .module = gui_config_mod }, }, }); gui_mod.addIncludePath(b.path("src/win32")); diff --git a/src/gui_config.zig b/src/gui_config.zig new file mode 100644 index 0000000..d484d6e --- /dev/null +++ b/src/gui_config.zig @@ -0,0 +1,4 @@ +fontface: [] const u8 = "Cascadia Code", +fontsize: f32 = 17.5, + +config_files: []const u8 = "", diff --git a/src/main.zig b/src/main.zig index 390083b..6e05388 100644 --- a/src/main.zig +++ b/src/main.zig @@ -389,28 +389,26 @@ pub fn exit(status: u8) noreturn { std.posix.exit(status); } -const config = @import("config"); - pub fn free_config(allocator: std.mem.Allocator, bufs: [][]const u8) void { for (bufs) |buf| allocator.free(buf); } -pub fn read_config(allocator: std.mem.Allocator) struct { config, [][]const u8 } { +pub fn read_config(T: type, allocator: std.mem.Allocator) struct { T, [][]const u8 } { var bufs: [][]const u8 = &[_][]const u8{}; - const file_name = get_app_config_file_name(application_name) catch return .{ .{}, bufs }; - var conf: config = .{}; - read_config_file(allocator, &conf, &bufs, file_name); - read_nested_config_files(allocator, &conf, &bufs); + const file_name = get_app_config_file_name(application_name, @typeName(T)) catch return .{ .{}, bufs }; + var conf: T = .{}; + read_config_file(T, allocator, &conf, &bufs, file_name); + read_nested_config_files(T, allocator, &conf, &bufs); return .{ conf, bufs }; } -fn read_config_file(allocator: std.mem.Allocator, conf: *config, bufs: *[][]const u8, file_name: []const u8) void { - read_json_config_file(allocator, conf, bufs, file_name) catch |e| +fn read_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8, file_name: []const u8) void { + read_json_config_file(T, allocator, conf, bufs, file_name) catch |e| log.logger("config").print_err("read_config", "error reading config file: {any}", .{e}); return; } -fn read_json_config_file(allocator: std.mem.Allocator, conf: *config, bufs_: *[][]const u8, file_name: []const u8) !void { +fn read_json_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void { const cbor = @import("cbor"); var file = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch |e| switch (e) { error.FileNotFound => return, @@ -429,7 +427,7 @@ fn read_json_config_file(allocator: std.mem.Allocator, conf: *config, bufs_: *[] while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidConfig; - inline for (@typeInfo(config).Struct.fields) |field_info| + inline for (@typeInfo(T).Struct.fields) |field_info| if (comptime std.mem.eql(u8, "config_files", field_info.name)) { if (std.mem.eql(u8, field_name, field_info.name)) { var value: field_info.type = undefined; @@ -448,14 +446,14 @@ fn read_json_config_file(allocator: std.mem.Allocator, conf: *config, bufs_: *[] } } -fn read_nested_config_files(allocator: std.mem.Allocator, conf: *config, bufs: *[][]const u8) void { +fn read_nested_config_files(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8) void { if (conf.config_files.len == 0) return; var it = std.mem.splitScalar(u8, conf.config_files, std.fs.path.delimiter); - while (it.next()) |path| read_config_file(allocator, conf, bufs, path); + while (it.next()) |path| read_config_file(T, allocator, conf, bufs, path); } -pub fn write_config(conf: config, allocator: std.mem.Allocator) !void { - return write_json_file(config, conf, allocator, try get_app_config_file_name(application_name)); +pub fn write_config(conf: anytype, allocator: std.mem.Allocator) !void { + return write_json_file(@TypeOf(conf), conf, allocator, try get_app_config_file_name(application_name, @typeName(@TypeOf(conf)))); } fn write_json_file(comptime T: type, data: T, allocator: std.mem.Allocator, file_name: []const u8) !void { @@ -638,12 +636,15 @@ fn get_app_state_dir(appname: []const u8) ![]const u8 { return state_dir; } -fn get_app_config_file_name(appname: []const u8) ![]const u8 { +fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ![]const u8 { + return get_app_config_dir_file_name(appname, base_name ++ ".json"); +} + +fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ![]const u8 { const local = struct { var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined; var config_file: ?[]const u8 = null; }; - const config_file_name = "config.json"; const config_file = if (local.config_file) |file| file else @@ -652,8 +653,8 @@ fn get_app_config_file_name(appname: []const u8) ![]const u8 { return config_file; } -pub fn get_config_file_name() ![]const u8 { - return get_app_config_file_name(application_name); +pub fn get_config_file_name(T: type) ![]const u8 { + return get_app_config_file_name(application_name, @typeName(T)); } pub fn get_restore_file_name() ![]const u8 { diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 07737e9..e6630b5 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -378,7 +378,7 @@ const cmds = struct { pub const open_help_meta = .{ .description = "Open help" }; pub fn open_config(_: *Self, _: Ctx) Result { - const file_name = try root.get_config_file_name(); + const file_name = try root.get_config_file_name(@TypeOf(tui.current().config)); try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name } }); } pub const open_config_meta = .{ .description = "Edit configuration file" }; diff --git a/src/tui/tui.zig b/src/tui/tui.zig index ed4cc47..60d1843 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -83,7 +83,7 @@ fn start(args: StartArgs) tp.result { fn init(allocator: Allocator) !*Self { var self = try allocator.create(Self); - var conf, const conf_bufs = root.read_config(allocator); + var conf, const conf_bufs = root.read_config(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"); diff --git a/src/win32/gui.zig b/src/win32/gui.zig index 4d18564..1e19e2b 100644 --- a/src/win32/gui.zig +++ b/src/win32/gui.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const root = @import("root"); const c = @cImport({ @cInclude("ResourceNames.h"); @@ -10,6 +11,7 @@ const ddui = @import("ddui"); const cbor = @import("cbor"); const thespian = @import("thespian"); const vaxis = @import("vaxis"); +const gui_config = @import("gui_config"); const RGB = @import("color").RGB; const input = @import("input"); @@ -381,6 +383,7 @@ fn calcWindowPlacement() WindowPlacement { const CreateWindowArgs = struct { allocator: std.mem.Allocator, pid: thespian.pid, + conf: gui_config, }; pub fn start() !std.Thread { @@ -418,9 +421,12 @@ fn entry(pid: thespian.pid) !void { win32.GetLastError(), ); + const conf, _ = root.read_config(gui_config, arena_instance.allocator()); + var create_args = CreateWindowArgs{ .allocator = arena_instance.allocator(), .pid = pid, + .conf = conf, }; const hwnd = win32.CreateWindowExW( window_style_ex,