diff options
Diffstat (limited to 'src/ninep/screen.zig')
| -rw-r--r-- | src/ninep/screen.zig | 79 |
1 files changed, 19 insertions, 60 deletions
diff --git a/src/ninep/screen.zig b/src/ninep/screen.zig index 89ca369b..f72043d4 100644 --- a/src/ninep/screen.zig +++ b/src/ninep/screen.zig @@ -1,5 +1,5 @@ -//! /screen, /listeners and the snapshot handles that freeze a screen or a -//! terminal history between open and close. +//! /screen, /listeners and the snapshots that freeze a screen or a terminal +//! history between open and close (tree.zig's open records hold them). const std = @import("std"); const pardes = @import("../pardes.zig"); const panes = @import("../panes.zig"); @@ -11,21 +11,6 @@ const Req = tree.Req; const Reply = tree.Reply; const E = tree.E; -pub const Snapshot = struct { - node: u64 = 0, - bytes: ?[]const u8 = null, - /// /log only: this open waits for records after `bytes`, from `next`. - follow: bool = false, - next: u64 = 0, - /// How much of record `next` a short read already took. - part: u32 = 0, - /// /log only: how much of `bytes` this open has read. Reads walk it as a - /// stream and ignore their offset, since `exec 3<>log; echo follow >&3` - /// leaves the shared offset past the word it wrote. - pos: u64 = 0, -}; -pub const snapshot_slots = 32; - pub fn render(p: *Pardes) ![]u8 { var arena: std.heap.ArenaAllocator = .init(p.gpa); defer arena.deinit(); @@ -58,26 +43,13 @@ pub fn render(p: *Pardes) ![]u8 { return out.toOwnedSlice(); } -/// A screen freezes at open; a terminal body freezes at its first read. -pub fn openSnapshot(p: *Pardes, req: Req, of_screen: bool) Reply { - for (&p.fs.snapshots, 0..) |*slot, i| { - if (slot.node != 0) continue; - const bytes = if (of_screen) render(p) catch return Reply.fail(req.tag, E.NOMEM) else null; - slot.* = .{ .node = req.node, .bytes = bytes }; - return .{ .tag = req.tag, .handle = @intCast(i + 1) }; - } - return Reply.fail(req.tag, E.NFILE); -} - pub fn readSnapshot(p: *Pardes, req: Req, pane: ?*Pane) Reply { - if (req.handle == 0 or req.handle > p.fs.snapshots.len) return Reply.fail(req.tag, E.INVAL); - const snapshot = &p.fs.snapshots[req.handle - 1]; - if (snapshot.node == 0 or snapshot.node != req.node) return Reply.fail(req.tag, E.INVAL); - if (snapshot.bytes == null) { + const snapshot = &(tree.openOf(p, req) orelse return Reply.fail(req.tag, E.INVAL)).what.snapshot; + if (snapshot.* == null) { const terminal = pane orelse return Reply.fail(req.tag, E.INVAL); - snapshot.bytes = panes.Terminal.screenTextAlloc(terminal, p.gpa) catch return Reply.fail(req.tag, E.NOMEM); + snapshot.* = panes.Terminal.screenTextAlloc(terminal, p.gpa) catch return Reply.fail(req.tag, E.NOMEM); } - const bytes = snapshot.bytes.?; + const bytes = snapshot.*.?; const off = @min(req.off, bytes.len); const len = @min(bytes.len - off, req.size); const out = p.fs.stage(p.gpa); @@ -85,16 +57,6 @@ pub fn readSnapshot(p: *Pardes, req: Req, pane: ?*Pane) Reply { return .{ .tag = req.tag, .payload = .{ .staged = @intCast(len) } }; } -/// True when the handle named a snapshot, which is now released. -pub fn releaseSnapshot(p: *Pardes, req: Req) bool { - if (req.handle == 0 or req.handle > p.fs.snapshots.len) return false; - const snapshot = &p.fs.snapshots[req.handle - 1]; - if (snapshot.node != req.node) return false; - if (snapshot.bytes) |bytes| p.gpa.free(bytes); - snapshot.* = .{}; - return true; -} - const listeners_cap = 512; fn listenersText(p: *Pardes, buf: []u8) []const u8 { @@ -199,7 +161,7 @@ test "an empty terminal body snapshot stays empty while output continues" { const node = Node.of(serialOf(p), .body); const opened = call(p, .{ .tag = 1, .op = .open, .node = node }); try testing.expectEqualStrings("", call(p, .{ .tag = 2, .op = .read, .node = node, .handle = opened.reply.handle, .size = 32 }).bytes); - try testing.expect(p.fs.snapshots[opened.reply.handle - 1].bytes != null); + try testing.expect(p.fs.opens[opened.reply.handle - 1].what.snapshot != null); p.update(.{ .output = .{ .pane = 0, .bytes = "new output" } }); while (p.nextEffect()) |_| {} try testing.expectEqualStrings("", call(p, .{ .tag = 3, .op = .read, .node = node, .handle = opened.reply.handle, .size = 32 }).bytes); @@ -214,15 +176,15 @@ test "terminal body snapshots are lazy bounded and released after the pane close const p = try withTerm(gpa); defer p.deinit(); const node = Node.of(serialOf(p), .body); - var handles: [snapshot_slots]u32 = undefined; + var handles: [tree.open_slots]u32 = undefined; for (&handles) |*opened_handle| { const opened = call(p, .{ .tag = 1, .op = .open, .node = node }); try testing.expectEqual(Status.ok, opened.reply.status); opened_handle.* = opened.reply.handle; } - for (p.fs.snapshots) |snapshot| { - try testing.expectEqual(node, snapshot.node); - try testing.expect(snapshot.bytes == null); + for (p.fs.opens) |o| { + try testing.expectEqual(node, o.node); + try testing.expect(o.what.snapshot == null); } try testing.expectEqual(E.NFILE, call(p, .{ .tag = 2, .op = .open, .node = node }).errno()); const scratch = try th.newPane(p); @@ -235,26 +197,23 @@ test "terminal body snapshots are lazy bounded and released after the pane close const failed = call(p, .{ .tag = 3, .op = .read, .node = node, .handle = handles[0], .size = 32 }); p.gpa = gpa; try testing.expectEqual(E.NOMEM, failed.errno()); - try testing.expect(p.fs.snapshots[handles[0] - 1].bytes == null); + try testing.expect(p.fs.opens[handles[0] - 1].what.snapshot == null); const first = call(p, .{ .tag = 4, .op = .read, .node = node, .handle = handles[0], .size = 32 }); try testing.expectEqualStrings("latest output", first.bytes); - const saved = p.fs.snapshots[handles[0] - 1].bytes.?; + const saved = p.fs.opens[handles[0] - 1].what.snapshot.?; failing = std.testing.FailingAllocator.init(gpa, .{ .fail_index = 0 }); p.gpa = failing.allocator(); const second = call(p, .{ .tag = 5, .op = .read, .node = node, .handle = handles[0], .off = 7, .size = 32 }); p.gpa = gpa; try testing.expectEqualStrings("output", second.bytes); try testing.expect(!failing.has_induced_failure); - try testing.expectEqual(saved.ptr, p.fs.snapshots[handles[0] - 1].bytes.?.ptr); + try testing.expectEqual(saved.ptr, p.fs.opens[handles[0] - 1].what.snapshot.?.ptr); try testing.expectEqual(E.INVAL, call(p, .{ .tag = 6, .op = .read, .node = screen_node, .handle = handles[0], .size = 32 }).errno()); _ = call(p, .{ .tag = 7, .op = .release, .node = screen_node, .handle = handles[0] }); - try testing.expectEqual(node, p.fs.snapshots[handles[0] - 1].node); + try testing.expectEqual(node, p.fs.opens[handles[0] - 1].node); try p.removePane(0, null); for (handles) |opened_handle| _ = call(p, .{ .tag = 8, .op = .release, .node = node, .handle = opened_handle }); - for (p.fs.snapshots) |snapshot| { - try testing.expectEqual(@as(u64, 0), snapshot.node); - try testing.expect(snapshot.bytes == null); - } + for (p.fs.opens) |o| try testing.expectEqual(@as(u64, 0), o.node); } test "screen snapshots preserve rendered cells and styles until their handle is released" { @@ -263,7 +222,7 @@ test "screen snapshots preserve rendered cells and styles until their handle is defer p.deinit(); const opened = call(p, .{ .tag = 1, .op = .open, .node = screen_node }); try testing.expectEqual(Status.ok, opened.reply.status); - const snapshot = p.fs.snapshots[opened.reply.handle - 1].bytes.?; + const snapshot = p.fs.opens[opened.reply.handle - 1].what.snapshot.?; const original = try gpa.dupe(u8, snapshot); defer gpa.free(original); const parsed = try std.json.parseFromSlice(std.json.Value, gpa, original, .{}); @@ -276,7 +235,7 @@ test "screen snapshots preserve rendered cells and styles until their handle is _ = wr(p, Node.of(serialOf(p), .body), "changed\n"); const newer = call(p, .{ .tag = 2, .op = .open, .node = screen_node }); try testing.expectEqual(Status.ok, newer.reply.status); - try testing.expect(!std.mem.eql(u8, original, p.fs.snapshots[newer.reply.handle - 1].bytes.?)); + try testing.expect(!std.mem.eql(u8, original, p.fs.opens[newer.reply.handle - 1].what.snapshot.?)); var off: usize = 0; while (off < original.len) { const result = call(p, .{ .tag = 3, .op = .read, .node = screen_node, .handle = opened.reply.handle, .off = off, .size = 13 }); @@ -286,7 +245,7 @@ test "screen snapshots preserve rendered cells and styles until their handle is } _ = call(p, .{ .tag = 4, .op = .release, .node = screen_node, .handle = opened.reply.handle }); _ = call(p, .{ .tag = 5, .op = .release, .node = screen_node, .handle = newer.reply.handle }); - for (p.fs.snapshots) |slot| try testing.expect(slot.node == 0); + for (p.fs.opens) |o| try testing.expect(o.node == 0); } test "screen inspection preserves acknowledged presentation and the next real frame" { |
