summaryrefslogtreecommitdiff
path: root/src/ninep/events.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 11:14:09 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commitc820afd8601ef14fda651c63f542476e12adcf11 (patch)
tree181aca8abdffa387f1eff3a9bd8f6acf109a5deb /src/ninep/events.zig
parentf18b1adc04dad68e115bb70c42e26472733daf1d (diff)
downloadpardes-c820afd8601ef14fda651c63f542476e12adcf11.tar.gz
pardes-c820afd8601ef14fda651c63f542476e12adcf11.zip
Nothing about a pane is logged before its new, and the boot terminal's new carries the session directory, not / and a rename
A pane named in the update that made it (Config's init file, a look renamed on open) logged `rename N <name>` before `new N`, so a follower met a serial it had never seen. The boot shell, started with no directory, was announced as `new 1 /` and renamed once its shell spoke. Now noteLog drops the rename of a pane not yet announced, since its new carries the name, and announces a pane first for any other record about it. A terminal whose shell has not said where it is is named by the session's directory, where it was started, and the shell saying so is no rename. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/events.zig')
-rw-r--r--src/ninep/events.zig38
1 files changed, 35 insertions, 3 deletions
diff --git a/src/ninep/events.zig b/src/ninep/events.zig
index 906e7a9a..c6505f52 100644
--- a/src/ninep/events.zig
+++ b/src/ninep/events.zig
@@ -153,10 +153,17 @@ fn bootFirst(p: *Pardes) void {
/// Records `<kind> <serial> <name>`.
pub fn noteLog(p: *Pardes, kind: LogKind, pane: *Pane) void {
+ // Nothing about a pane comes before its `new`: one not announced yet
+ // is announced first, and a rename of it is no record, as its `new`
+ // carries the name it has by then.
+ if (pane.fs.unannounced and kind != .new) {
+ if (kind == .rename) return;
+ announce(p);
+ }
var buf: [4 * 4096 + 64]u8 = undefined;
var name_buf: [4 * 4096]u8 = undefined;
// As /index shows it: a newline in the name is `\n`.
- const name = shown(pane_files.nameOf(pane), &name_buf);
+ const name = shown(pane_files.nameOf(p, pane), &name_buf);
pushLog(p, std.fmt.bufPrint(&buf, "{s} {d} {s}\n", .{ @tagName(kind), pane.serial, name }) catch return);
}
@@ -1011,7 +1018,7 @@ test "the log records whether or not anyone reads, and an open that follows wait
// Nobody holds /log open, and the pane is recorded anyway.
const early = try th.newPane(p);
- const early_line = try std.fmt.bufPrint(&expected, "new {d} {s}\n", .{ early, pane_files.nameOf(p.panes[p.paneBySerial(early).?].?) });
+ const early_line = try std.fmt.bufPrint(&expected, "new {d} {s}\n", .{ early, pane_files.nameOf(p, p.panes[p.paneBySerial(early).?].?) });
const early_owned = try gpa.dupe(u8, early_line);
defer gpa.free(early_owned);
@@ -1048,7 +1055,7 @@ test "the log records whether or not anyone reads, and an open that follows wait
const serial = try th.newPane(p);
const id = p.paneBySerial(serial).?;
try testing.expectEqualStrings(
- try std.fmt.bufPrint(&expected, "new {d} {s}\n", .{ serial, pane_files.nameOf(p.panes[id].?) }),
+ try std.fmt.bufPrint(&expected, "new {d} {s}\n", .{ serial, pane_files.nameOf(p, p.panes[id].?) }),
rdf.next(p, log, fh, frozen).bytes,
);
try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .name), "/tmp/logged.txt\n").reply.status);
@@ -1190,6 +1197,31 @@ test "a Restore gives columns fresh serials, past every serial the old session h
try testing.expect(pardes.layout.columnSerial(restored, 0) != first);
}
+test "a pane named before it is announced has its new under that name, and no rename before it" {
+ const p = try withFile(testing.allocator, "one\n");
+ defer p.deinit();
+ const pane = p.panes[0].?;
+ // As a pane Config makes and names in one update.
+ pane.fs.unannounced = true;
+ try pane_files.nameBuffer(p, 0, "/tmp/named-first.txt", false);
+ announce(p);
+ const log = try freezeLog(p);
+ defer p.gpa.free(log.bytes);
+ var want: [64]u8 = undefined;
+ try testing.expect(std.mem.endsWith(u8, log.bytes, try std.fmt.bufPrint(&want, "new {d} /tmp/named-first.txt\n", .{pane.serial})));
+ try testing.expect(std.mem.indexOf(u8, log.bytes, try std.fmt.bufPrint(&want, "rename {d} ", .{pane.serial})) == null);
+ // A shell given no directory is named by the session's from the first,
+ // and saying it is there is no rename.
+ const free = p.freeSlot().?;
+ const shell = try p.newShell(free, "");
+ try testing.expectEqualStrings(p.sessionDir(), pane_files.nameOf(p, shell));
+ announce(p);
+ p.setCwd(free, p.sessionDir());
+ const after = try freezeLog(p);
+ defer p.gpa.free(after.bytes);
+ try testing.expect(std.mem.indexOf(u8, after.bytes, try std.fmt.bufPrint(&want, "rename {d} ", .{shell.serial})) == null);
+}
+
test "opens of the log share the open records, and a closed one frees its record" {
const gpa = testing.allocator;
const p = try withFile(gpa, "x\n");