diff options
Diffstat (limited to 'src/ninep/pane.zig')
| -rw-r--r-- | src/ninep/pane.zig | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig index 902f4f2a..e7b72c88 100644 --- a/src/ninep/pane.zig +++ b/src/ninep/pane.zig @@ -41,6 +41,9 @@ pub const State = struct { /// rather than act at the address before it, which acme would do. addr_failed: bool = false, limit: ?Range = null, + /// The limit a truncation cleared, kept until the write that follows it + /// on that open (a shell's `>`): a write that fails puts it back. + limit_truncated: ?Range = null, /// Opens of `event`, which hold the pane scripted. readers: u16 = 0, /// One of `readers` reads `event`; a second reading open is refused. @@ -523,8 +526,13 @@ fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply { }; const range = r orelse { if (file == .addr) pf.addr_failed = true; + if (file == .limit) if (pf.limit_truncated) |kept| { + pf.limit = kept; + pf.limit_truncated = null; + }; return tree.failText(req.tag, E.INVAL, a.err); }; + if (file == .limit) pf.limit_truncated = null; switch (file) { .addr => { pf.addr = range; @@ -684,7 +692,10 @@ pub fn truncate(p: *Pardes, pane: *Pane, file: PaneFile) tree.Status { // is evaluated from where the last one left off, as with `>>`. // `0` (or `,`) is how to start over. See State.addr. .addr => {}, - .limit => pf.limit = null, + .limit => { + pf.limit_truncated = pf.limit; + pf.limit = null; + }, .dot => if (fileOf(pane) != null) setDot(pane, .{}), else => {}, } @@ -1236,3 +1247,18 @@ test "addresses are in runes: a combining mark and a lone \\r are places of thei _ = wr(p, addr_node, "#4,#5"); try testing.expectEqualStrings("\r", rd(p, Node.of(serial, .xdata), 0, 100).bytes); } + +test "a limit write that fails keeps the limit a truncation cleared before it" { + const gpa = testing.allocator; + const p = try withFile(gpa, "one two\n"); + defer p.deinit(); + const limit = Node.of(serialOf(p), .limit); + _ = wr(p, limit, "#0,#3"); + _ = call(p, .{ .tag = 1, .op = .setattr, .node = limit, .truncate = true }); + try testing.expectEqual(Status.err, wr(p, limit, "/nomatch/").reply.status); + try testing.expectEqualStrings(" 0 3 ", rd(p, limit, 0, 100).bytes); + // A truncation with no write after it clears it. + _ = call(p, .{ .tag = 2, .op = .setattr, .node = limit, .truncate = true }); + _ = call(p, .{ .tag = 3, .op = .release, .node = limit }); + try testing.expectEqualStrings("", rd(p, limit, 0, 100).bytes); +} |
