summaryrefslogtreecommitdiff
path: root/src/ninep/tree.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 12:26:33 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commitec89f340f239b31d6c9ef95e7e76696f9aa2005a (patch)
tree503aea2768cce021549abf216af53bfa7633fa66 /src/ninep/tree.zig
parentf6ccac42abf0f08159a78c9ca58ff9137ac18434 (diff)
downloadpardes-ec89f340f239b31d6c9ef95e7e76696f9aa2005a.tar.gz
pardes-ec89f340f239b31d6c9ef95e7e76696f9aa2005a.zip
Two opens writing one body are separate undo steps, however they interleave
The join mark a write left was the pane's, so another open's write joined the first open's step. Writing opens of body, data and xdata now get an open record, the mark names the open that set it, and another open's write starts its own step (the pane's one history: each turn the opens take is a step). Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/tree.zig')
-rw-r--r--src/ninep/tree.zig18
1 files changed, 12 insertions, 6 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig
index 4b52be51..66f73e9c 100644
--- a/src/ninep/tree.zig
+++ b/src/ninep/tree.zig
@@ -131,6 +131,9 @@ pub const Open = struct {
/// An open of a file that takes lines of commands (look, exec, a
/// ctl, tagexec): its `pending` and `results`.
lines,
+ /// An open writing a file pane's body, data or xdata: its writes are
+ /// one undo step (pane.zig `joined_by`), another open's its own.
+ writes,
} = .{ .snapshot = null },
/// What a write to a file of command lines left unfinished: a last line
/// with no newline yet, or an Edit block still open. A write through a
@@ -180,7 +183,7 @@ pub const Open = struct {
gpa.free(run.output);
gpa.free(run.line);
},
- .event, .pty_data, .ctl, .lines => {},
+ .event, .pty_data, .ctl, .lines, .writes => {},
}
o.pending.deinit(gpa);
if (o.replay) |r| gpa.free(r.bytes);
@@ -752,7 +755,8 @@ fn open(p: *Pardes, req: Req, target: Target) Reply {
pane_of = pn;
const reader = req.omode & 3 != 1; // OWRITE is the one mode that never reads
break :what switch (t.file) {
- .body => if (pn.isTerminal()) .{ .snapshot = null } else return .{ .tag = req.tag },
+ .body => if (pn.isTerminal()) .{ .snapshot = null } else if (req.omode & 3 == 0) return .{ .tag = req.tag } else .writes,
+ .data, .xdata => if (req.omode & 3 != 0) .writes else return .{ .tag = req.tag },
// Reads of these consume, so two readers would each see half
// the stream; the second is refused rather than robbed.
.event => if (reader and pn.fs.event_reader) return failText(req.tag, E.BUSY, e_in_use) else .{ .event = reader },
@@ -794,7 +798,7 @@ fn open(p: *Pardes, req: Req, target: Target) Reply {
pn.fs.event_reader = pn.fs.event_reader or reader;
},
.pty_data => pane_of.?.fs.pty_reader = true,
- .run, .ctl, .lines => {},
+ .run, .ctl, .lines, .writes => {},
}
return .{ .tag = req.tag, .handle = @intCast(i + 1) };
}
@@ -831,9 +835,11 @@ fn releaseHandle(p: *Pardes, req: Req) void {
p.panes[id].?.fs.tag_rewrite = false;
p.panes[id].?.fs.tag_held_newline = false;
};
- // The writes of one open are one undo step (pane.zig `joined`).
+ // The writes of one open are one undo step (pane.zig `joined`): its
+ // close ends that step.
if (t == .pane and (t.pane.file == .body or t.pane.file == .data or t.pane.file == .xdata)) if (p.paneBySerial(t.pane.serial)) |id| {
- p.panes[id].?.fs.joined = null;
+ const pf = &p.panes[id].?.fs;
+ if (pf.joined_by == 0 or pf.joined_by == req.handle) pf.joined = null;
};
// `: > limit` clears it for good once its open goes.
if (t == .pane and t.pane.file == .limit) if (p.paneBySerial(t.pane.serial)) |id| {
@@ -871,7 +877,7 @@ fn releaseHandle(p: *Pardes, req: Req) void {
.ctl => if (pn.fs.lock == req.handle) {
pn.fs.lock = null;
},
- .snapshot, .log, .lines => {},
+ .snapshot, .log, .lines, .writes => {},
};
o.deinit(p.gpa);
}