summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Output.zig1
-rw-r--r--src/colors.zig8
-rw-r--r--src/config.zig8
-rw-r--r--src/ninep/ctl.zig39
4 files changed, 54 insertions, 2 deletions
diff --git a/src/Output.zig b/src/Output.zig
index 01797cbe..47fcc7e4 100644
--- a/src/Output.zig
+++ b/src/Output.zig
@@ -870,6 +870,7 @@ pub fn openConfig(p: *Pardes, id: usize) !void {
.startup_config_path = p.opts.startup_config_path,
.platform = @tagName(pardes.platform),
.theme_name = p.theme().name,
+ .theme_file = pardes.colors.loadedThemeFile(p),
.compiled_default_shell = config.defaultShell(),
.hover_delay_frames = config.look_preview_delay_frames,
.native_images = p.native_images,
diff --git a/src/colors.zig b/src/colors.zig
index c78043cc..8d541c13 100644
--- a/src/colors.zig
+++ b/src/colors.zig
@@ -735,6 +735,14 @@ pub fn requestThemeFile(p: *Pardes, id: usize, argument: []const u8) void {
p.emit(.{ .theme_file = .{ .generation = generation, .on = true } });
}
+/// The .zon a ThemeFile loaded, while it is the theme in effect: what
+/// /ctl and DumpConfig say in place of `Theme <name>`, since the name
+/// inside the file is no theme `Theme` knows.
+pub fn loadedThemeFile(p: *const Pardes) ?[]const u8 {
+ const path = p.theme_file_path.get();
+ return if (p.custom_theme != null and path.len > 0) path else null;
+}
+
pub const ThemeFileRequest = struct {
path: []const u8,
pane: u8,
diff --git a/src/config.zig b/src/config.zig
index 592281d3..a7377cfa 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -1267,6 +1267,9 @@ pub const Runtime = struct {
startup_config_path: ?[]const u8,
platform: []const u8,
theme_name: []const u8,
+ /// The ThemeFile in effect, said as `ThemeFile <path>` in place
+ /// of the theme's name.
+ theme_file: ?[]const u8 = null,
compiled_default_shell: []const u8,
hover_delay_frames: ?u16,
/// Where dumps go when `DumpDir` is unset; empty without a host
@@ -1305,7 +1308,10 @@ pub const Runtime = struct {
};
try out.print("{s} {s}\n", .{ setting.word, onOff(value) });
},
- .theme => try out.print("{s} {s}\n", .{ setting.word, context.theme_name }),
+ .theme => if (context.theme_file) |path|
+ try out.print("ThemeFile {s}\n", .{path})
+ else
+ try out.print("{s} {s}\n", .{ setting.word, context.theme_name }),
.window_opacity => {
if (setting.enabled(context.capabilities))
try out.print("{s} {d}\n", .{ setting.word, state.window_opacity })
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 902a9647..bc27f72b 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -554,7 +554,9 @@ pub fn writeSettingsOf(p: *Pardes, s: *const config.Runtime, w: *std.Io.Writer)
const word = setting.word;
switch (setting.action) {
.toggle => |field| try w.print("{s} {s}\n", .{ word, if (@field(s, @tagName(field))) "on" else "off" }),
- .theme => try w.print("{s} {s}\n", .{ word, if (s == &p.settings) p.theme().name else pardes.themes[s.theme].name }),
+ .theme => if (s == &p.settings) {
+ if (pardes.colors.loadedThemeFile(p)) |path| try w.print("ThemeFile {s}\n", .{path}) else try w.print("{s} {s}\n", .{ word, p.theme().name });
+ } else try w.print("{s} {s}\n", .{ word, pardes.themes[s.theme].name }),
.shell => {
const chosen = s.shell.requested.get();
try w.print("{s} {s}\n", .{ word, if (chosen.len > 0) chosen else config.defaultShell() });
@@ -1829,6 +1831,41 @@ test "an error's words give the errno a mount reads: EINVAL for what is malforme
}
}
+test "after a ThemeFile the root ctl and DumpConfig say ThemeFile and its path, which writes back" {
+ if (comptime !pardes.hosted) return;
+ const gpa = testing.allocator;
+ const p = try withFile(gpa, "x\n");
+ defer p.deinit();
+ const root_ctl = @intFromEnum(tree.TopFile.ctl);
+ const path = "/tmp/pardes-mine-theme.zon";
+ try testing.expectEqual(Status.ok, wr(p, root_ctl, "ThemeFile " ++ path ++ "\n").reply.status);
+ var custom = pardes.themes[0];
+ custom.name = "mine";
+ var encoded: std.Io.Writer.Allocating = .init(gpa);
+ defer encoded.deinit();
+ try std.zon.stringify.serialize(custom, .{}, &encoded.writer);
+ try testing.expect(pardes.colors.loadThemeFile(p, p.theme_file_generation, encoded.written(), false));
+ const settings = rd(p, root_ctl, 0, 1 << 16).bytes;
+ try testing.expect(std.mem.indexOf(u8, settings, "ThemeFile " ++ path ++ "\n") != null);
+ try testing.expect(std.mem.indexOf(u8, settings, "Theme mine") == null);
+ var storage: [16384]u8 = undefined;
+ var out: std.Io.Writer = .fixed(&storage);
+ try config.Runtime.writeReport(&out, .{
+ .startup_config_path = null,
+ .platform = @tagName(pardes.platform),
+ .theme_name = p.theme().name,
+ .theme_file = pardes.colors.loadedThemeFile(p),
+ .compiled_default_shell = config.defaultShell(),
+ .hover_delay_frames = null,
+ .native_images = false,
+ .capabilities = builtins.capabilities,
+ .state = &p.settings,
+ });
+ try testing.expect(std.mem.indexOf(u8, out.buffered(), "ThemeFile " ++ path ++ "\n") != null);
+ // Written back, it is the same request again, not "no theme mine".
+ try testing.expectEqual(Status.ok, wr(p, root_ctl, "ThemeFile " ++ path ++ "\n").reply.status);
+}
+
test "Joincol with no column to the right and Theme with no such theme say so" {
const gpa = testing.allocator;
const p = try withFile(gpa, "x\n");