From fda2f546f66d0bb1b30da0ef6aae77fe82803b1c Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Wed, 30 Sep 2026 11:22:41 -0300 Subject: DumpConfig prints each setting as the ctl word that sets it, reads unsupported for one the frontend lacks, and includes LocationsConfig The report meant to be feedable back as configuration, but several lines were not. Shell and Font each took three to six lines of "requested", "effective" and "pending". The transition read "Panel transition PanelSlide", with no Panel word. WindowOpacity and TaglineSize carried "(pending)" and "(build-time only)". A GUI-only toggle such as Ligatures was left out on the tty, and LocationsConfig was missing altogether. Now every line up to a blank one is a word and its value: - Shell ; - Font :; - one on/off line for each Panel word; - `unsupported` for a setting this frontend does not have; - LocationsConfig as it would be typed. After the blank line comes what is in effect but set by no word, phrased so that none of it starts with a ctl word. The test checks that each line before the blank one starts with a setting word. The GUI scripts that read the font lines (font_size.py, appearance_gallery.py) now read the new ones. Co-Authored-By: Claude Opus 5.5 --- src/Output.zig | 4 ++ src/builtins.zig | 3 +- src/config.zig | 167 +++++++++++++++++++++++-------------------------------- 3 files changed, 77 insertions(+), 97 deletions(-) (limited to 'src') diff --git a/src/Output.zig b/src/Output.zig index 0581be41..65f6bfe4 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -815,7 +815,11 @@ pub fn openConfig(p: *Pardes, id: usize) !void { errdefer out.deinit(); var dir_buf: [1024]u8 = undefined; const host_fs = comptime (pardes.platform != .web and pardes.platform != .esp32p4); + var located: std.Io.Writer.Allocating = .init(p.gpa); + defer located.deinit(); + try p.locations_config.write(&located.writer); try config.Runtime.writeReport(&out.writer, .{ + .locations = located.written(), .default_dump_dir = if (host_fs) (pardes.dump.defaultDirectory(&dir_buf) orelse "") else "", .startup_config_path = p.opts.startup_config_path, .platform = @tagName(pardes.platform), diff --git a/src/builtins.zig b/src/builtins.zig index c40b2e00..8fe49649 100644 --- a/src/builtins.zig +++ b/src/builtins.zig @@ -458,7 +458,8 @@ test "Ligatures is a setting only in the shell that shapes text" { .state = &p.settings, }); try std.testing.expectEqual(exists, std.mem.indexOf(u8, storage[0..out.end], "Ligatures off\n") != null); - try std.testing.expectEqual(exists, std.mem.indexOf(u8, storage[0..out.end], "Ligatures") != null); + // A GUI-only setting reads so elsewhere, as every one the shell lacks. + try std.testing.expectEqual(!exists, std.mem.indexOf(u8, storage[0..out.end], "Ligatures unsupported\n") != null); } comptime { diff --git a/src/config.zig b/src/config.zig index a70ae708..94b32b88 100644 --- a/src/config.zig +++ b/src/config.zig @@ -1275,6 +1275,8 @@ pub const Runtime = struct { native_images: bool, capabilities: Capabilities, state: *const Runtime, + /// The `LocationsConfig` argument in effect, as it would be typed. + locations: []const u8 = "", }; fn onOff(value: bool) []const u8 { @@ -1285,23 +1287,19 @@ pub const Runtime = struct { return if (text.len == 0) "(none)" else text; } - fn transitionSettingName(transition: animation.Transition) []const u8 { - if (transition == .off) return "off"; - return findAction(.{ .transition = transition }).?.word; - } - - /// Each line reads as the command that would set it: the word, then the - /// value you would type after it. No colons, no units — `WindowOpacity 70` - /// is both what DumpConfig prints and what you write back. + /// Each setting line reads as the command that would set it: the word, + /// then the value you would type after it (`unsupported` where this + /// shell has no such setting). No colons, no units: `WindowOpacity 70` + /// is both what DumpConfig prints and what you write back. What is in + /// effect but set by no word follows, after a blank line. pub fn writeReport(out: *std.Io.Writer, context: ReportContext) !void { const state = context.state; - var wrote_transition = false; for (settings) |setting| switch (setting.action) { .toggle => |field| { - // A toggle for what this shell does not draw (Ligatures in a - // terminal, whose text its emulator draws) is no setting here: - // it is not a builtin, so the report does not list it either. - if (!setting.enabled(context.capabilities)) continue; + if (!setting.enabled(context.capabilities)) { + try out.print("{s} unsupported\n", .{setting.word}); + continue; + } const value = switch (field) { inline else => |f| @field(state, @tagName(f)), }; @@ -1310,11 +1308,7 @@ pub const Runtime = struct { .theme => try out.print("{s} {s}\n", .{ setting.word, context.theme_name }), .window_opacity => { if (setting.enabled(context.capabilities)) - try out.print("{s} {d}{s}\n", .{ - setting.word, - state.window_opacity, - if (state.window_opacity_pending) " (pending)" else "", - }) + try out.print("{s} {d}\n", .{ setting.word, state.window_opacity }) else try out.print("{s} unsupported\n", .{setting.word}); }, @@ -1333,64 +1327,28 @@ pub const Runtime = struct { } }), .shell => { const chosen = state.shell.requested.get(); - try out.print( - "{s} requested (new panes) {s}{s}\n" ++ - "{s} effective (last spawn) {s}\n" ++ - "{s} pending {s}\n", - .{ - setting.word, - if (chosen.len == 0) context.compiled_default_shell else chosen, - if (chosen.len == 0) " (default)" else "", - setting.word, - shown(state.shell.effective.get()), - setting.word, - onOff(state.shell.pending), - }, - ); + try out.print("{s} {s}\n", .{ setting.word, if (chosen.len == 0) context.compiled_default_shell else chosen }); }, .font => if (!setting.enabled(context.capabilities)) try out.print("{s} unsupported\n", .{setting.word}) else { - if (state.font.requested_size_hundredths == 0) - try out.print("{s} requested size unchanged\n", .{setting.word}) - else - try out.print("{s} requested size {d}.{d:0>2}\n", .{ setting.word, state.font.requested_size_hundredths / 100, state.font.requested_size_hundredths % 100 }); - try out.print( - "{s} requested {s}\n" ++ - "{s} requested path {s}\n" ++ - "{s} effective {s}\n" ++ - "{s} pending {s}\n" ++ - "{s} effective size {d}.{d:0>2} {s}\n", - .{ - setting.word, - shown(state.font.requested_name.get()), - setting.word, - shown(state.font.requested_path.get()), - setting.word, - shown(state.font.effective_name.get()), - setting.word, - onOff(state.font.pending), - setting.word, - state.font.effective_size_hundredths / 100, - state.font.effective_size_hundredths % 100, - @tagName(state.font.effective_size_unit), - }, - ); + // As `Font` takes it, `name:size`: the one asked for, else + // the one in use. + const f = &state.font; + const name = if (f.requested_path.get().len > 0) f.requested_path.get() else if (f.requested_name.get().len > 0) f.requested_name.get() else f.effective_name.get(); + try out.print("{s} {s}", .{ setting.word, name }); + if (f.requested_size_hundredths != 0) try out.print(":{d}.{d:0>2}", .{ f.requested_size_hundredths / 100, f.requested_size_hundredths % 100 }); + try out.writeByte('\n'); }, .tagline_size => if (!context.capabilities.tagline_font_size) try out.print("{s} unsupported\n", .{setting.word}) - else if (!setting.enabled(context.capabilities)) - try out.print("{s} {d} (build-time only)\n", .{ setting.word, state.font.tagline_percent }) else try out.print("{s} {d}\n", .{ setting.word, state.font.tagline_percent }), - .transition => { - if (wrote_transition) continue; - wrote_transition = true; - if (!setting.enabled(context.capabilities)) - try out.writeAll("Panel transition unsupported\n") - else - try out.print("Panel transition {s}\n", .{transitionSettingName(state.panel_transition)}); - }, + // Each a switch of its own, the one in use on. + .transition => |transition| if (!setting.enabled(context.capabilities)) + try out.print("{s} unsupported\n", .{setting.word}) + else + try out.print("{s} {s}\n", .{ setting.word, onOff(state.panel_transition == transition) }), .scene => |effect| { if (!setting.enabled(context.capabilities)) { try out.print("{s} unsupported\n", .{setting.word}); @@ -1426,7 +1384,21 @@ pub const Runtime = struct { .inactive_dim => try out.print("{s} {d}\n", .{ setting.word, state.inactive_dim }), .grip_width => try out.print("{s} {d}\n", .{ setting.word, state.grip_width }), }; - + if (context.locations.len > 0) try out.print("LocationsConfig {s}\n", .{context.locations}); + + // In effect, and set by no word. + try out.writeByte('\n'); + try out.print("Last shell spawned: {s}\n", .{shown(state.shell.effective.get())}); + try out.print("Shell change pending: {s}\n", .{onOff(state.shell.pending)}); + if (find("Font").?.enabled(context.capabilities)) { + const f = &state.font; + try out.print("Font in use: {s} {d}.{d:0>2} {s}\n", .{ shown(f.effective_name.get()), f.effective_size_hundredths / 100, f.effective_size_hundredths % 100, @tagName(f.effective_size_unit) }); + try out.print("Font change pending: {s}\n", .{onOff(f.pending)}); + } + if (find("WindowOpacity").?.enabled(context.capabilities)) + try out.print("Window opacity change pending: {s}\n", .{onOff(state.window_opacity_pending)}); + if (context.capabilities.tagline_font_size and !find("TaglineSize").?.enabled(context.capabilities)) + try out.writeAll("Tagline size: build-time only\n"); if (context.startup_config_path) |path| try out.print("Startup config: {s}\n", .{path}) else @@ -1726,9 +1698,9 @@ pub const Runtime = struct { .chip_shadow => "ChipShadow on\n", .thumb_flash => "ThumbFlash on\n", }, - .shell => "Shell requested (new panes) fish\n", + .shell => "Shell fish\n", .tagline_size => "TaglineSize 73\n", - .window_opacity => "WindowOpacity 85 (pending)\n", + .window_opacity => "WindowOpacity 85\n", .window_blur => "WindowBlur 40\n", .dump_dir => "DumpDir ~/dumps\n", .message_ms => |which| switch (which) { @@ -1738,17 +1710,17 @@ pub const Runtime = struct { }, .transition => |transition| switch (transition) { .off => unreachable, - .slide => "Panel transition PanelSlide\n", - .zoom => "Panel transition PanelZoom\n", - .dissolve => "Panel transition PanelDissolve\n", - .ascii => "Panel transition PanelAscii\n", - .vertical => "Panel transition PanelVertical\n", - .edges => "Panel transition PanelEdges\n", - .fall => "Panel transition PanelFall\n", - .wave => "Panel transition PanelWave\n", - .curtain => "Panel transition PanelCurtain\n", - .scramble => "Panel transition PanelScramble\n", - .typewriter => "Panel transition PanelType\n", + .slide => "PanelSlide on\n", + .zoom => "PanelZoom on\n", + .dissolve => "PanelDissolve on\n", + .ascii => "PanelAscii on\n", + .vertical => "PanelVertical on\n", + .edges => "PanelEdges on\n", + .fall => "PanelFall on\n", + .wave => "PanelWave on\n", + .curtain => "PanelCurtain on\n", + .scramble => "PanelScramble on\n", + .typewriter => "PanelType on\n", }, .scene => |effect| switch (effect) { .crt => "Crt 2\n", @@ -1788,12 +1760,10 @@ pub const Runtime = struct { for ([_][]const u8{ "Theme acme\n", "WindowOpacity 85\n", - "Font requested size 18.50\n", - "Font requested Wanted Mono\n", - "Font requested path /fonts/wanted.ttf\n", - "Font effective Effective Mono\n", - "Font pending on\n", - "Font effective size 13.75 points\n", + "Font /fonts/wanted.ttf:18.50\n", + "Font in use: Effective Mono 13.75 points\n", + "Font change pending: on\n", + "Window opacity change pending: off\n", "TaglineSize 82\n", "Startup config: /tmp/pardes/init\n", "Platform: gui\n", @@ -1823,19 +1793,23 @@ pub const Runtime = struct { try std.testing.expect(std.mem.indexOf(u8, defaults_report, "WindowBlur unsupported\n") != null); try std.testing.expect(!find("WindowBlur").?.enabled(defaults_context.capabilities)); try std.testing.expect(find("WindowOpacity").?.enabled(context.capabilities)); - try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Shell requested (new panes) /bin/sh (default)\n") != null); - try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Shell effective (last spawn) (none)\n") != null); - try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Shell pending on\n") != null); + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Shell /bin/sh\n") != null); + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Last shell spawned: (none)\n") != null); + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Shell change pending: on\n") != null); try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Startup config: no per-user config path\n") != null); try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Font unsupported\n") != null); - try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Font requested") == null); - try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Panel transition off\n") != null); + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Font in use") == null); + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "PanelSlide off\n") != null); try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Crt unsupported\n") != null); try std.testing.expect(std.mem.indexOf(u8, defaults_report, "TaglineSize unsupported\n") != null); try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Look hover delay: off\n") != null); try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Native images: off\n") != null); - // A shell that does not shape text has no Ligatures setting to report. - try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Ligatures") == null); + // A setting this shell does not have reads so, as a line to write. + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Ligatures unsupported\n") != null); + // Every line before the blank one is a ctl word and its value. + const words = defaults_report[0..std.mem.indexOf(u8, defaults_report, "\n\n").?]; + var lines = std.mem.splitScalar(u8, words, '\n'); + while (lines.next()) |line| try std.testing.expect(find(line[0..std.mem.indexOfScalar(u8, line, ' ').?]) != null); defaults_context.platform = "web"; defaults_context.capabilities.panel_transitions = false; @@ -1843,8 +1817,9 @@ pub const Runtime = struct { out = .fixed(&storage); try writeReport(&out, defaults_context); const web_report = storage[0..out.end]; - try std.testing.expect(std.mem.indexOf(u8, web_report, "Panel transition unsupported\n") != null); - try std.testing.expect(std.mem.indexOf(u8, web_report, "TaglineSize 100 (build-time only)\n") != null); + try std.testing.expect(std.mem.indexOf(u8, web_report, "PanelSlide unsupported\n") != null); + try std.testing.expect(std.mem.indexOf(u8, web_report, "TaglineSize 100\n") != null); + try std.testing.expect(std.mem.indexOf(u8, web_report, "Tagline size: build-time only\n") != null); } }; -- cgit v1.3