From 8b2a55f31169ede82e11a573ab655e72e7831fe7 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 23:11:08 -0300 Subject: A choice setting's refusal names what it takes, and /commands lists them Bare Placement and BootShell flip, which is pardes's convention for a word that chooses (Crt does too), but nothing said so, and "bad value in control message" never said what would do. A refused value now says `takes acme, pardes` (every switch and choice setting), /commands lists each such setting's values in a fourth field, and config.md and fs.md say that bare steps to the next. Motion and ShaderAnimation stepped nowhere bare and now step like the rest. Co-Authored-By: Claude Opus 5.5 --- src/config.zig | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) (limited to 'src/config.zig') diff --git a/src/config.zig b/src/config.zig index 24c48770..234d8cae 100644 --- a/src/config.zig +++ b/src/config.zig @@ -1104,20 +1104,12 @@ pub const Runtime = struct { } return state.post.set(null, path, null); }, - .shader_animation => { - const text = std.mem.trim(u8, argument orelse return false, " \t\r\n"); - state.shader_animation = std.meta.stringToEnum(ShaderAnimation, text) orelse return false; - }, + .shader_animation => state.shader_animation = stepped(ShaderAnimation, state.shader_animation, argument) orelse return false, // Bare, it steps to the next word, as a tag word should. .choice => |which| switch (which) { inline else => |field| { const now = &@field(state, @tagName(field)); - const T = @TypeOf(now.*); - const text = std.mem.trim(u8, argument orelse "", " \t\r\n"); - now.* = if (text.len == 0) - @enumFromInt((@as(usize, @intFromEnum(now.*)) + 1) % std.enums.values(T).len) - else - std.meta.stringToEnum(T, text) orelse return false; + now.* = stepped(@TypeOf(now.*), now.*, argument) orelse return false; }, }, .lift => { @@ -1129,10 +1121,7 @@ pub const Runtime = struct { else std.meta.stringToEnum(LiftStyle, text) orelse return false; }, - .motion => { - const text = std.mem.trim(u8, argument orelse return false, " \t\r\n"); - state.motion = std.meta.stringToEnum(animation.Motion.Flavour, text) orelse return false; - }, + .motion => state.motion = stepped(animation.Motion.Flavour, state.motion, argument) orelse return false, .inactive_dim => { const text = std.mem.trim(u8, argument orelse return false, " \t\r\n%"); const percent = std.fmt.parseInt(u8, text, 10) catch return false; @@ -1150,6 +1139,40 @@ pub const Runtime = struct { return true; } + /// The values a setting that chooses among words takes, for a refusal to + /// name; null for one that takes a number, a path or a name. Bare, each + /// of these flips (a two-valued one) or steps to its next value. + pub fn choices(action: Action) ?[]const u8 { + const words = struct { + fn of(comptime T: type) []const u8 { + comptime var out: []const u8 = ""; + inline for (std.meta.fieldNames(T), 0..) |name, i| out = out ++ (if (i > 0) ", " else "") ++ name; + return out; + } + }; + return switch (action) { + .toggle, .transition => "on, off", + .choice => |which| switch (which) { + inline else => |field| comptime words.of(@FieldType(Runtime, @tagName(field))), + }, + .lift => "on, " ++ comptime words.of(LiftStyle), + .motion => comptime words.of(animation.Motion.Flavour), + .scene => std.fmt.comptimePrint("on, off, 0-{d}", .{Post.max_level}), + .shader_animation => comptime words.of(ShaderAnimation), + else => null, + }; + } + + /// The value a choice word names, or bare, the one after `now`; null for + /// a word it does not take. + fn stepped(comptime T: type, now: T, argument: ?[]const u8) ?T { + const text = std.mem.trim(u8, argument orelse "", " \t\r\n"); + if (text.len > 0) return std.meta.stringToEnum(T, text); + const all = std.enums.values(T); + const at = std.mem.indexOfScalar(T, all, now) orelse 0; + return all[(at + 1) % all.len]; + } + /// What `on`, `off` or nothing after a switch word asks for: null flips /// it, as a bare tagline word does. fn switchedTo(argument: ?[]const u8) error{NotOnOrOff}!?bool { -- cgit v1.3