diff --git a/src/cli/list_themes.zig b/src/cli/list_themes.zig index 45a80723e..42aff9d56 100644 --- a/src/cli/list_themes.zig +++ b/src/cli/list_themes.zig @@ -2,6 +2,7 @@ const std = @import("std"); const args = @import("args.zig"); const Action = @import("ghostty.zig").Action; const Config = @import("../config/Config.zig"); +const configpkg = @import("../config.zig"); const themepkg = @import("../config/theme.zig"); const tui = @import("tui.zig"); const global_state = &@import("../global.zig").state; @@ -196,6 +197,31 @@ pub fn run(gpa_alloc: std.mem.Allocator) !u8 { return 0; } +fn resolveAutoThemePath(alloc: std.mem.Allocator) ![]u8 { + const main_cfg_path = try configpkg.preferredDefaultFilePath(alloc); + defer alloc.free(main_cfg_path); + + const base_dir = std.fs.path.dirname(main_cfg_path) orelse return error.BadPathName; + return try std.fs.path.join(alloc, &.{ base_dir, "auto", "theme.ghostty" }); +} + +fn writeAutoThemeFile(alloc: std.mem.Allocator, theme_name: []const u8) !void { + const auto_path = try resolveAutoThemePath(alloc); + defer alloc.free(auto_path); + + if (std.fs.path.dirname(auto_path)) |dir| { + try std.fs.cwd().makePath(dir); + } + + var f = try std.fs.createFileAbsolute(auto_path, .{ .truncate = true }); + defer f.close(); + + var buf: [128]u8 = undefined; + var w = f.writer(&buf); + try w.interface.print("theme = {s}\n", .{theme_name}); + try w.interface.flush(); +} + const Event = union(enum) { key_press: vaxis.Key, mouse: vaxis.Mouse, @@ -487,6 +513,9 @@ const Preview = struct { self.should_quit = true; if (key.matchesAny(&.{ vaxis.Key.escape, vaxis.Key.enter, vaxis.Key.kp_enter }, .{})) self.mode = .normal; + if (key.matches('w', .{})) { + self.saveSelectedTheme(); + } }, } }, @@ -698,7 +727,7 @@ const Preview = struct { .help => { win.hideCursor(); const width = 60; - const height = 20; + const height = 22; const child = win.child( .{ .x_off = win.width / 2 -| width / 2, @@ -733,6 +762,7 @@ const Preview = struct { .{ .keys = "/", .help = "Start search." }, .{ .keys = "^X, ^/", .help = "Clear search." }, .{ .keys = "⏎", .help = "Save theme or close search window." }, + .{ .keys = "w", .help = "Write theme to auto config file." }, }; for (key_help, 0..) |help, captured_i| { @@ -786,8 +816,8 @@ const Preview = struct { .save => { const theme = self.themes[self.filtered.items[self.current]]; - const width = 90; - const height = 12; + const width = 92; + const height = 17; const child = win.child( .{ .x_off = win.width / 2 -| width / 2, @@ -809,6 +839,12 @@ const Preview = struct { try std.fmt.allocPrint(alloc, "theme = {s}", .{theme.theme}), "", "Save the configuration file and then reload it to apply the new theme.", + "", + "Or press 'w' to write an auto theme file to your system's preferred default config path.", + "Then add the following line to your Ghostty configuration and reload:", + "", + "config-file = ?auto/theme.ghostty", + "", "For more details on configuration and themes, visit the Ghostty documentation:", "", "https://ghostty.org/docs/config/reference", @@ -1657,6 +1693,18 @@ const Preview = struct { }); } } + + fn saveSelectedTheme(self: *Preview) void { + if (self.filtered.items.len == 0) + return; + + const idx = self.filtered.items[self.current]; + const theme = self.themes[idx]; + + writeAutoThemeFile(self.allocator, theme.theme) catch { + return; + }; + } }; fn color(config: Config, palette: usize) vaxis.Color {