From 95681ff7017b8a9e4c8f9fa6a7371d1233432f2f Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 14 Sep 2026 13:55:41 -0300 Subject: 9p: use cloud9 protocol sessions and transports --- src/config.zig | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 4 deletions(-) (limited to 'src/config.zig') diff --git a/src/config.zig b/src/config.zig index 282e63da..865e2474 100644 --- a/src/config.zig +++ b/src/config.zig @@ -98,6 +98,7 @@ pub const leader_path = paths: { table.set(.TaglineSize, null); } if (pardes.platform == .gui) table.set(.Pet, null); + if (builtins.capabilities.window_opacity) table.set(.WindowOpacity, null); if (builtins.capabilities.panel_transitions) { table.set(.PanelSlide, "as"); table.set(.PanelZoom, "az"); @@ -537,6 +538,8 @@ pub const Runtime = struct { focus_tint: bool = true, column_tags: bool = true, syntax_bold: bool = false, + window_opacity: u8 = 100, + window_opacity_pending: bool = true, pet: enum { off, cat, frog } = .off, // Effective values change only after a host acknowledges the request. @@ -625,6 +628,7 @@ pub const Runtime = struct { panel_transitions: bool, scene_shaders: bool, tagline_font_size: bool, + window_opacity: bool = false, }; pub const Capability = std.meta.FieldEnum(Capabilities); @@ -638,6 +642,7 @@ pub const Runtime = struct { theme, font, tagline_size, + window_opacity, transition: layout.Transition, scene: Scene, }; @@ -649,7 +654,7 @@ pub const Runtime = struct { pub fn takesArg(setting: Setting) bool { return switch (setting.action) { - .shell, .theme, .font, .tagline_size => true, + .shell, .theme, .font, .tagline_size, .window_opacity => true, else => false, }; } @@ -675,6 +680,7 @@ pub const Runtime = struct { .{ .word = "Shell", .action = .shell }, .{ .word = "Font", .action = .font, .availability = .font_picker }, .{ .word = "TaglineSize", .action = .tagline_size, .availability = .font_picker }, + .{ .word = "WindowOpacity", .action = .window_opacity, .availability = .window_opacity }, .{ .word = "PanelSlide", .action = .{ .transition = .slide }, .availability = .panel_transitions }, .{ .word = "PanelZoom", .action = .{ .transition = .zoom }, .availability = .panel_transitions }, .{ .word = "PanelDissolve", .action = .{ .transition = .dissolve }, .availability = .panel_transitions }, @@ -716,6 +722,8 @@ pub const Runtime = struct { switch (setting.action) { .font, .tagline_size => if (setting.availability != .font_picker) @compileError("native font settings must use the font-picker capability"), + .window_opacity => if (setting.availability != .window_opacity) + @compileError("window opacity must use the window-opacity capability"), .transition => if (setting.availability != .panel_transitions) @compileError("panel effects must use the panel-transition capability"), .scene => if (setting.availability != .scene_shaders) @@ -727,8 +735,8 @@ pub const Runtime = struct { for (std.enums.values(Toggle)) |field| if (actionCount(.{ .toggle = field }) != 1) @compileError("runtime toggle must occur exactly once: " ++ @tagName(field)); if (actionCount(.shell) != 1 or actionCount(.theme) != 1 or actionCount(.font) != 1 or - actionCount(.tagline_size) != 1) - @compileError("Shell, Theme, Font, and TaglineSize actions must each occur exactly once"); + actionCount(.tagline_size) != 1 or actionCount(.window_opacity) != 1) + @compileError("Shell, Theme, Font, TaglineSize, and WindowOpacity actions must each occur exactly once"); for (std.enums.values(layout.Transition)) |effect| { const expected: comptime_int = @intFromBool(effect != .off); if (actionCount(.{ .transition = effect }) != expected) @@ -764,6 +772,14 @@ pub const Runtime = struct { if (percent < tagline_percent_min or percent > tagline_percent_max) return false; state.font.tagline_percent = @intCast(percent); }, + .window_opacity => { + const text = std.mem.trim(u8, argument orelse return false, " \t\r\n"); + for (text) |byte| if (!std.ascii.isDigit(byte)) return false; + const percent = std.fmt.parseInt(u8, text, 10) catch return false; + if (percent > 100) return false; + state.window_opacity = percent; + state.window_opacity_pending = true; + }, .transition => |effect| state.toggleTransition(effect), .scene => |effect| switch (effect) { inline else => |field| { @@ -819,6 +835,16 @@ 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 }), + .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 "", + }) + else + try out.print("{s}: unsupported\n", .{setting.word}); + }, .shell => { const chosen = state.shell.requested.get(); try out.print( @@ -917,7 +943,7 @@ pub const Runtime = struct { for (settings[i + 1 ..]) |later| try std.testing.expect(!std.mem.eql(u8, setting.word, later.word)); try std.testing.expectEqual(switch (setting.action) { - .shell, .theme, .font, .tagline_size => true, + .shell, .theme, .font, .tagline_size, .window_opacity => true, else => false, }, setting.takesArg()); } @@ -954,6 +980,33 @@ pub const Runtime = struct { } } + test "window opacity defaults to opaque validates atomically and retries" { + const setting = find("WindowOpacity").?; + var state: Runtime = .{}; + try std.testing.expectEqual(@as(u8, 100), state.window_opacity); + try std.testing.expect(state.window_opacity_pending); + try std.testing.expect(setting.takesArg()); + try std.testing.expectEqual(Capability.window_opacity, setting.availability.?); + + for ([_][]const u8{ "0", " 85\n", "100" }, [_]u8{ 0, 85, 100 }) |argument, expected| { + state.window_opacity_pending = false; + try std.testing.expect(apply(&state, setting, argument)); + try std.testing.expectEqual(expected, state.window_opacity); + try std.testing.expect(state.window_opacity_pending); + } + + state.window_opacity = 85; + state.window_opacity_pending = false; + for ([_]?[]const u8{ null, "", " \t\n", "101", "-1", "+85", "85%", "0.5", "85.0", "85 20", "8_5", "0x55", "999999999999999999999" }) |argument| { + try std.testing.expect(!apply(&state, setting, argument)); + try std.testing.expectEqual(@as(u8, 85), state.window_opacity); + try std.testing.expect(!state.window_opacity_pending); + } + // Reissuing the same request still asks the host to apply it again. + try std.testing.expect(apply(&state, setting, "85")); + try std.testing.expect(state.window_opacity_pending); + } + test "font request tuple rejects atomically" { var state: Runtime = .{}; try std.testing.expect(requestFont(&state, "/fonts/old.ttf", "Old", 1200)); @@ -994,6 +1047,7 @@ pub const Runtime = struct { .panel_transitions = true, .scene_shaders = true, .tagline_font_size = true, + .window_opacity = true, }, .state = &state, }; @@ -1006,6 +1060,7 @@ pub const Runtime = struct { const argument: ?[]const u8 = switch (setting.action) { .shell => "fish", .tagline_size => "73", + .window_opacity => "85", else => null, }; try std.testing.expect(apply(&state, setting, argument)); @@ -1025,6 +1080,7 @@ pub const Runtime = struct { }, .shell => "Shell requested (new panes): fish\n", .tagline_size => "TaglineSize: 73%\n", + .window_opacity => "WindowOpacity: 85% (pending)\n", .transition => |transition| switch (transition) { .off => unreachable, .slide => "Panel transition: PanelSlide\n", @@ -1059,10 +1115,12 @@ pub const Runtime = struct { state.font.tagline_percent = 82; var out: std.Io.Writer = .fixed(&storage); + state.window_opacity_pending = false; try writeReport(&out, context); const report = storage[0..out.end]; 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", @@ -1095,6 +1153,9 @@ pub const Runtime = struct { out = .fixed(&storage); try writeReport(&out, defaults_context); const defaults_report = storage[0..out.end]; + try std.testing.expect(std.mem.indexOf(u8, defaults_report, "WindowOpacity: unsupported\n") != null); + try std.testing.expect(!find("WindowOpacity").?.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); -- cgit v1.3