summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig24
1 files changed, 20 insertions, 4 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index c8be3bad..e62ff605 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -281,7 +281,12 @@ fn checkBuiltin(p: *Pardes, req: Req, line: []const u8, scope: builtins.Scope) ?
break :probe probe.apply(setting, if (arg.len > 0) arg else null);
},
};
- return if (takes) null else refuse(p, req, "bad value in control message", line);
+ if (takes) return null;
+ var why: [104]u8 = undefined;
+ return refuse(p, req, if (config.Runtime.choices(setting.action)) |values|
+ std.fmt.bufPrint(&why, "bad value in control message; takes {s}", .{values}) catch "bad value in control message"
+ else
+ "bad value in control message", line);
}
/// Runs a checked control message at pane `id`, as a click on its word
@@ -407,11 +412,20 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply {
/// itself, so a new builtin is listed the moment it exists.
fn writeCommands(w: *std.Io.Writer) !void {
for (std.enums.values(Builtin)) |b| {
- try w.print("{s}{s} {s}\n", .{
+ try w.print("{s}{s} {s}", .{
@tagName(b),
if (builtins.registry.takesArg(b)) " arg" else "",
if (builtins.registry.scope(b) == .session) "root" else "pane",
});
+ // A setting that chooses among words: the words, comma-joined. Bare,
+ // it steps to the next of them (a two-valued one flips).
+ if (config.Runtime.find(@tagName(b))) |setting| if (config.Runtime.choices(setting.action)) |values| {
+ try w.writeByte(' ');
+ var parts = std.mem.splitSequence(u8, values, ", ");
+ var first = true;
+ while (parts.next()) |v| : (first = false) try w.print("{s}{s}", .{ if (first) "" else ",", v });
+ };
+ try w.writeByte('\n');
}
}
@@ -623,10 +637,11 @@ test "commands lists every builtin with its argument and the ctl that takes it"
const b = std.meta.stringToEnum(Builtin, words.next().?).?;
if (builtins.registry.takesArg(b)) try testing.expectEqualStrings("arg", words.next().?);
try testing.expectEqualStrings(if (builtins.registry.scope(b) == .session) "root" else "pane", words.next().?);
+ if (config.Runtime.find(@tagName(b))) |s| if (config.Runtime.choices(s.action) != null) try testing.expect(words.next() != null);
try testing.expect(words.next() == null);
}
try testing.expectEqual(std.enums.values(Builtin).len, lines);
- for ([_][]const u8{ "\nDel arg pane\n", "\nNewcol root\n", "\nSave arg pane\n", "\nVerbose arg root\n", "\nUndo pane\n", "\nRedo pane\n" }) |row|
+ for ([_][]const u8{ "\nDel arg pane\n", "\nNewcol root\n", "\nSave arg pane\n", "\nVerbose arg root on,off\n", "\nPlacement arg root acme,pardes\n", "\nUndo pane\n", "\nRedo pane\n" }) |row|
try testing.expect(std.mem.indexOf(u8, listed.bytes, row) != null);
}
@@ -752,7 +767,8 @@ test "the root ctl reads the settings as a write takes them, and takes the sessi
try testing.expectEqualStrings("not a session control message \"Del\": write it to pane/<n>/ctl", wr(p, root_ctl, "Del").reply.ename);
try testing.expectEqualStrings("unknown control message \"Nonsense 1\"", wr(p, root_ctl, "Nonsense 1").reply.ename);
- try testing.expectEqualStrings("bad value in control message \"Verbose maybe\"", wr(p, root_ctl, "Verbose maybe").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes on, off \"Verbose maybe\"", wr(p, root_ctl, "Verbose maybe").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes acme, pardes \"Placement east\"", wr(p, root_ctl, "Placement east").reply.ename);
const no_theme = wr(p, root_ctl, "Theme no-such-theme").reply.ename;
try testing.expectStringStartsWith(no_theme, "bad value in control message; like it: n");
try testing.expect(std.mem.endsWith(u8, no_theme, "; ThemeSel lists all \"Theme no-such-theme\""));