summaryrefslogtreecommitdiff
path: root/src/ninep/pane.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/pane.zig')
-rw-r--r--src/ninep/pane.zig29
1 files changed, 25 insertions, 4 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index 852a9ec0..9aada3ee 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -48,6 +48,11 @@ pub const State = struct {
/// follows sets it or, refused, leaves it as it was; with none, the
/// open's release empties it (tree.zig releaseHandle).
dot_truncated: bool = false,
+ /// The open whose writes to `sel` are being kept together (0: none) and
+ /// the text they have made so far: the next write of that open goes at
+ /// its end, as acme's wrselrange does.
+ wrsel_by: u32 = 0,
+ wrsel: Range = .{},
/// Opens of `event`, which hold the pane scripted.
readers: u16 = 0,
/// One of `readers` reads `event`; a second reading open is refused.
@@ -787,12 +792,20 @@ fn writeData(p: *Pardes, req: Req, pane: *Pane) Reply {
fn writeSel(p: *Pardes, req: Req, pane: *Pane) Reply {
if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text);
- const d = dotOf(pane);
+ const pf = &pane.fs;
+ // The same open's next write follows its last; any other replaces dot.
+ const going_on = req.handle != 0 and pf.wrsel_by == req.handle;
+ const d = if (going_on) State.Range{ .q0 = pf.wrsel.q1, .q1 = pf.wrsel.q1 } else dotOf(pane);
const q0: usize = d.q0;
const q1: usize = @max(q0, @as(usize, d.q1));
const take = spliceBody(p, pane, q0, q1, req.data) orelse
return Reply.fail(req.tag, E.NOMEM);
- setDot(pane, .{ .q0 = clip(q0 + take), .q1 = clip(q0 + take) });
+ // What was written is selected, as acme's wrsel leaves it: `cat sel`
+ // reads it back.
+ const start = if (going_on) pf.wrsel.q0 else clip(q0);
+ pf.wrsel = .{ .q0 = start, .q1 = clip(q0 + take) };
+ pf.wrsel_by = req.handle;
+ setDot(pane, pf.wrsel);
return .{ .tag = req.tag, .written = @intCast(take) };
}
@@ -1265,9 +1278,17 @@ test "sel reads the selection and writing sel replaces it" {
try testing.expectEqual(Status.ok, wr(p, sel, "ONE").reply.status);
try testing.expectEqualStrings("ONE\ntwo\n", p.panes[0].?.file.?.content);
+ // What was written is selected, as acme's wrsel leaves it.
+ try testing.expectEqualStrings("ONE", rd(p, sel, 0, 100).bytes);
+ // A write of another open replaces it; one open's writes run on.
_ = wr(p, sel, "!");
- try testing.expectEqualStrings("ONE!\ntwo\n", p.panes[0].?.file.?.content);
- try testing.expectEqual(@as(u64, 0), call(p, .{ .tag = 2, .op = .getattr, .node = sel }).reply.attr.size);
+ try testing.expectEqualStrings("!\ntwo\n", p.panes[0].?.file.?.content);
+ const hs = call(p, .{ .tag = 3, .op = .open, .node = sel, .omode = 1 }).reply.handle;
+ _ = call(p, .{ .tag = 4, .op = .write, .node = sel, .handle = hs, .data = "a" });
+ _ = call(p, .{ .tag = 5, .op = .write, .node = sel, .handle = hs, .data = "b" });
+ _ = call(p, .{ .tag = 6, .op = .release, .node = sel, .handle = hs, .opened = true });
+ try testing.expectEqualStrings("ab\ntwo\n", p.panes[0].?.file.?.content);
+ try testing.expectEqualStrings("ab", rd(p, sel, 0, 100).bytes);
}
test "the flag files read and write the state acme kept behind ctl verbs" {