diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 19:57:44 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | b6200709aa5e42f7a3d3702489301c71da8cd65d (patch) | |
| tree | 0042cad5c71f4cac613028fa20757c4dd1a5e3a7 /src | |
| parent | 63983ab4b235fb2b6617e8d055e644e0e986d8fd (diff) | |
| download | pardes-b6200709aa5e42f7a3d3702489301c71da8cd65d.tar.gz pardes-b6200709aa5e42f7a3d3702489301c71da8cd65d.zip | |
DumpConfig writes a setting this shell cannot show as a "# Word unsupported" comment, GripWidth among them on the tty, so the whole report writes back to /ctl
The report said it could be written back as is, but "Lift unsupported"
and the tty's "GripWidth 100" were each refused by the root ctl, and
"DumpDir (none)" would have named a directory "(none)". Those lines are
now comments, and a test writes every line of the report back.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.zig | 49 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 23 |
2 files changed, 54 insertions, 18 deletions
diff --git a/src/config.zig b/src/config.zig index a17e2fd2..6bb4d6e4 100644 --- a/src/config.zig +++ b/src/config.zig @@ -1307,8 +1307,8 @@ pub const Runtime = struct { } /// 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` + /// then the value you would type after it (a `# Word unsupported` + /// comment 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 { @@ -1316,7 +1316,7 @@ pub const Runtime = struct { for (settings) |setting| switch (setting.action) { .toggle => |field| { if (!setting.enabled(context.capabilities)) { - try out.print("{s} unsupported\n", .{setting.word}); + try out.print("# {s} unsupported\n", .{setting.word}); continue; } const value = switch (field) { @@ -1332,17 +1332,17 @@ pub const Runtime = struct { if (setting.enabled(context.capabilities)) try out.print("{s} {d}\n", .{ setting.word, state.window_opacity }) else - try out.print("{s} unsupported\n", .{setting.word}); + try out.print("# {s} unsupported\n", .{setting.word}); }, .window_blur => { if (setting.enabled(context.capabilities)) try out.print("{s} {d}\n", .{ setting.word, state.window_blur }) else - try out.print("{s} unsupported\n", .{setting.word}); + try out.print("# {s} unsupported\n", .{setting.word}); }, .dump_dir => { const dir = if (state.dump_dir.len > 0) state.dump_dir.get() else context.default_dump_dir; - try out.print("{s} {s}\n", .{ setting.word, if (dir.len > 0) dir else "(none)" }); + if (dir.len > 0) try out.print("{s} {s}\n", .{ setting.word, dir }) else try out.print("# {s} (none)\n", .{setting.word}); }, .message_ms => |which| try out.print("{s} {d}\n", .{ setting.word, switch (which) { inline else => |w| @field(state, "message_" ++ @tagName(w) ++ "_ms"), @@ -1352,28 +1352,34 @@ pub const Runtime = struct { 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}) + try out.print("# {s} unsupported\n", .{setting.word}) else { // 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(); + // None known yet (no font loaded): a comment, as `Font` + // alone is no line a ctl takes. + if (name.len == 0) { + try out.print("# {s} (none yet)\n", .{setting.word}); + continue; + } 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}) + try out.print("# {s} unsupported\n", .{setting.word}) else try out.print("{s} {d}\n", .{ setting.word, state.font.tagline_percent }), // 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}) + 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}); + try out.print("# {s} unsupported\n", .{setting.word}); continue; } const level = state.post.level(effect); @@ -1381,7 +1387,7 @@ pub const Runtime = struct { }, .shader => { if (!setting.enabled(context.capabilities)) { - try out.print("{s} unsupported\n", .{setting.word}); + try out.print("# {s} unsupported\n", .{setting.word}); continue; } var files: usize = 0; @@ -1394,17 +1400,20 @@ pub const Runtime = struct { .shader_animation => if (setting.enabled(context.capabilities)) try out.print("{s} {s}\n", .{ setting.word, @tagName(state.shader_animation) }) else - try out.print("{s} unsupported\n", .{setting.word}), + try out.print("# {s} unsupported\n", .{setting.word}), .choice => |which| switch (which) { inline else => |field| try out.print("{s} {s}\n", .{ setting.word, @tagName(@field(state, @tagName(field))) }), }, .lift => if (setting.enabled(context.capabilities)) try out.print("{s} {s}\n", .{ setting.word, @tagName(state.lift) }) else - try out.print("{s} unsupported\n", .{setting.word}), + try out.print("# {s} unsupported\n", .{setting.word}), .motion => try out.print("{s} {s}\n", .{ setting.word, @tagName(state.motion) }), .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 }), + .grip_width => if (setting.enabled(context.capabilities)) + try out.print("{s} {d}\n", .{ setting.word, state.grip_width }) + else + try out.print("# {s} unsupported\n", .{setting.word}), }; if (context.locations.len > 0) try out.print("LocationsConfig {s}\n", .{context.locations}); @@ -1827,12 +1836,16 @@ pub const Runtime = struct { 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 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. + // A setting this shell does not have reads so, as a comment. + 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, or a + // comment naming one. 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); + while (lines.next()) |line| { + const word = if (std.mem.startsWith(u8, line, "# ")) line[2..] else line; + try std.testing.expect(find(word[0..std.mem.indexOfScalar(u8, word, ' ').?]) != null); + } // ...and every one after it a `#` line, which runs as nothing. var info = std.mem.splitScalar(u8, std.mem.trimEnd(u8, defaults_report[words.len + 2 ..], "\n"), '\n'); while (info.next()) |line| try std.testing.expect(std.mem.startsWith(u8, line, "# ")); diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 2cd865de..eff8003b 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -1836,6 +1836,29 @@ test "an error's words give the errno a mount reads: EINVAL for what is malforme } } +test "DumpConfig's whole report writes back to the root ctl, line by line, with no error" { + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + const root_ctl = @intFromEnum(tree.TopFile.ctl); + try testing.expectEqual(Status.ok, wr(p, root_ctl, "DumpConfig\n").reply.status); + const report = for (p.panes) |slot| { + const pane = slot orelse continue; + const f = pane.file orelse continue; + const o = f.output orelse continue; + if (std.meta.eql(o.from, panes.Output.Origin{ .cmd = .DumpConfig })) break try testing.allocator.dupe(u8, f.content); + } else return error.NoDumpConfigPane; + defer testing.allocator.free(report); + // What this shell cannot show is a comment, never a value it refuses. + if (pardes.platform == .tty) try testing.expect(std.mem.indexOf(u8, report, "# GripWidth unsupported\n") != null); + var lines = std.mem.splitScalar(u8, report, '\n'); + while (lines.next()) |line| { + if (line.len == 0) continue; + const r = wr(p, root_ctl, line); + if (r.reply.status != .ok) std.debug.print("refused: {s}: {s}\n", .{ line, r.reply.ename }); + try testing.expectEqual(Status.ok, r.reply.status); + } +} + 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; |
