diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 14:37:29 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | d88e381793c6505bf3f2af43705bd2fa32f55ef6 (patch) | |
| tree | d4f3966c4eacf7fee43b6f18fc83f136676f835d /src/detached/client.zig | |
| parent | 7284b72396398213356577345151bd79e497d27c (diff) | |
| download | pardes-d88e381793c6505bf3f2af43705bd2fa32f55ef6.tar.gz pardes-d88e381793c6505bf3f2af43705bd2fa32f55ef6.zip | |
One Layer for tags, notices, headers and bodies; a taller tag is one layer of rows; wire v8
src/Layer.zig merges TagLayer and BodyLayer. `rows` (0 = no layer) and a
cursor at {x, y}. A tag of N rows is ONE layer of N grid rows: tagHit answers
the row as `line`, bodyHit keeps its meaning, and the per-line layer bases
(TAG_LINE_LAYER_BASE, HEADER_LINE_LAYER_BASE) are gone, not aliased.
Wire v8, the one bump: tag layers carry rows and cursor y, and the frame
carries the placed region list. v7 and v9 peers are refused in both
directions (server test over both, a new frontend test over both).
web: tag_layer_value 11 = rows, 12 = cursor y; app.mjs lays every row.
macOS: the Zig side compiles against Layer; pardes.h still sees one row
per tag layer (accepted, the macOS shell is ignored for now).
No visual change: snapshot goldens and the 17 GUI goldens byte-identical.
Shared files touched: pardes.zig, Messages.zig, gui.zig, macos.zig,
detached/client.zig, detached/server.zig, detached/wire.zig (plus web.zig,
app.mjs, edit.zig, look.zig). Not touched: mouse.zig, tagline.zig,
colors.zig, tty.zig, dump.zig, exec.zig, host_io.zig, panes.zig.
Diffstat (limited to 'src/detached/client.zig')
| -rw-r--r-- | src/detached/client.zig | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/src/detached/client.zig b/src/detached/client.zig index 4468c961..3347f609 100644 --- a/src/detached/client.zig +++ b/src/detached/client.zig @@ -103,8 +103,10 @@ pub const Client = struct { grid: std.ArrayListUnmanaged(pardes.Cell) = .empty, cursor: ?wire.Cursor = null, pointer_shape: pardes.Surface.PointerShape = .arrow, - body_layers: [pardes.MAX_PANES]pardes.BodyLayer = @splat(.{}), - tag_layers: [pardes.MAX_TAG_LAYERS]pardes.TagLayer = @splat(.{}), + body_layers: [pardes.MAX_PANES]pardes.Layer = @splat(.{}), + tag_layers: [pardes.MAX_TAG_LAYERS]pardes.Layer = @splat(.{}), + /// The session's placed regions, as its last frame gave them. + regions: std.ArrayListUnmanaged(pardes.Region) = .empty, in: std.ArrayListUnmanaged(u8) = .empty, out: std.ArrayListUnmanaged(u8) = .empty, /// Bytes of `in` belonging to the message `next` returned last. Compacted at @@ -182,6 +184,7 @@ pub const Client = struct { layer.* = .{}; } for (&c.tag_layers) |*layer| c.gpa.free(layer.cells); + c.regions.deinit(c.gpa); c.in.deinit(c.gpa); c.out.deinit(c.gpa); } @@ -319,7 +322,7 @@ pub const Client = struct { try c.reshape(f.cols, f.rows); } try f.apply(c.grid.items); - f.applyLayers(c.gpa, &c.body_layers, &c.tag_layers) catch |err| return switch (err) { + f.applyLayers(c.gpa, &c.body_layers, &c.tag_layers, &c.regions) catch |err| return switch (err) { error.OutOfMemory => error.Closed, else => @as(wire.Error, @errorCast(err)), }; @@ -995,6 +998,12 @@ test "detached session: a frontend that dies takes nothing with it" { } test "detached session: a frontend speaking another protocol is refused, loudly" { + // The protocol before this one (v7 carried one-row tags and no regions) + // and the one after. + for ([_]u16{ wire.version - 1, wire.version + 1 }) |claimed| try refusedHello(claimed); +} + +fn refusedHello(claimed: u16) !void { var h: Harness = undefined; try h.init(60, 16); defer h.deinit(); @@ -1006,7 +1015,7 @@ test "detached session: a frontend speaking another protocol is refused, loudly" defer _ = libc.close(fd); var buf: [64]u8 = undefined; const hello = try wire.encodeClient(&buf, .{ - .hello = .{ .version = wire.version + 1, .cols = 60, .rows = 16 }, + .hello = .{ .version = claimed, .cols = 60, .rows = 16 }, }); try testing.expectEqual(@as(isize, @intCast(hello.len)), libc.send(fd, hello.ptr, hello.len, nosignal)); @@ -1024,6 +1033,17 @@ test "detached session: a frontend speaking another protocol is refused, loudly" try testing.expect(!h.core.quit); } +test "detached frontend: a session speaking another protocol is not attached to" { + for ([_]u16{ wire.version - 1, wire.version + 1 }) |claimed| { + var c: Client = .{ .gpa = testing.allocator }; + defer c.deinit(); + var buf: [64]u8 = undefined; + try c.in.appendSlice(testing.allocator, try wire.encodeServer(&buf, .{ .welcome = .{ .version = claimed, .slot = 0, .cols = 60, .rows = 16 } })); + try testing.expectError(error.Ungreeted, c.next()); + try testing.expect(!c.attached()); + } +} + test "detached session: a peer that sends garbage is dropped, not obeyed" { var h: Harness = undefined; try h.init(60, 16); @@ -1281,7 +1301,7 @@ fn pumpUntilNotice(h: *Harness, c: *Client, want: []const u8) !bool { try c.wait(5); while (try c.next()) |_| {} for (&c.tag_layers) |*layer| { - if (layer.cols == 0 or layer.kind != .notice) continue; + if (layer.rows == 0 or layer.kind != .notice) continue; var n: usize = 0; for (layer.cells[0..layer.cols]) |cell| { const g = cell.grapheme(); |
