summaryrefslogtreecommitdiff
path: root/src/ninep/tree.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 00:23:55 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit4881c5d13c6a705a8c8bdb0181c33f9a500b5a74 (patch)
tree31ee1398657b271d08830a1efad9e6d9f206aa68 /src/ninep/tree.zig
parent15ddd805905f785f4dde463d4d6b91e1d2c41e26 (diff)
downloadpardes-4881c5d13c6a705a8c8bdb0181c33f9a500b5a74.tar.gz
pardes-4881c5d13c6a705a8c8bdb0181c33f9a500b5a74.zip
Columns are named by stable serials over 9P, as panes are
/col/<n> named a column by its index, which shifts when a column left of it closes: exactly what scripts trip on. A column is now /col/<serial>, its serial kept while it lives and never reused; /layout lines give serial and index (`<serial> <index> ...`), active names the serial, /index's last field is the column's serial, and the log says newcol and delcol with serials. Docs, the skill and the tree's README say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/tree.zig')
-rw-r--r--src/ninep/tree.zig49
1 files changed, 27 insertions, 22 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig
index 9459be4f..3be75960 100644
--- a/src/ninep/tree.zig
+++ b/src/ninep/tree.zig
@@ -19,6 +19,7 @@ pub const pane = @import("pane.zig");
pub const addr = @import("addr.zig");
pub const ctl = @import("ctl.zig");
pub const cols = @import("cols.zig");
+const layout = pardes.layout;
pub const pty = @import("pty.zig");
pub const sources = @import("sources.zig");
pub const screen = @import("screen.zig");
@@ -268,8 +269,9 @@ pub const PaneFile = enum(u5) {
}
};
-/// /col/<n> and its tag: a column is named by its index, which a serial
-/// never is (serials are 32 bits; this bit is past them).
+/// /col/<serial> and its tag: a column is named by its serial, which stays
+/// while it lives as a pane's does; this bit, past a pane serial's 32, keeps
+/// the two apart.
pub const ColFile = enum(u5) { dir = 0, tag = 1 };
const col_bit: u59 = 1 << 58;
@@ -282,8 +284,8 @@ pub const Node = packed struct(u64) {
return @bitCast(Node{ .file = @intFromEnum(file), .serial = serial });
}
- pub fn ofCol(index: usize, file: ColFile) u64 {
- return @bitCast(Node{ .file = @intFromEnum(file), .serial = col_bit | @as(u59, @intCast(index)) });
+ pub fn ofCol(serial: u32, file: ColFile) u64 {
+ return @bitCast(Node{ .file = @intFromEnum(file), .serial = col_bit | @as(u59, serial) });
}
pub fn target(node: u64) ?Target {
@@ -292,7 +294,7 @@ pub const Node = packed struct(u64) {
return .{ .top = std.enums.fromInt(TopFile, n.file) orelse return null };
}
if (n.serial & col_bit != 0) return .{ .col = .{
- .index = std.math.cast(u32, n.serial & ~col_bit) orelse return null,
+ .serial = std.math.cast(u32, n.serial & ~col_bit) orelse return null,
.file = std.enums.fromInt(ColFile, n.file) orelse return null,
} };
return .{ .pane = .{
@@ -305,7 +307,7 @@ pub const Node = packed struct(u64) {
pub const Target = union(enum) {
top: TopFile,
pane: struct { serial: u32, file: PaneFile },
- col: struct { index: u32, file: ColFile },
+ col: struct { serial: u32, file: ColFile },
};
/// Opening /pane/new makes a pane and reading the open fid answers its
@@ -450,13 +452,13 @@ fn attrOf(p: *Pardes, target: Target) ?Reply.Attr {
.append = f == .tag,
},
.col => |c| {
- if (c.index >= p.ncol) return null;
+ if (layout.columnBySerial(p, c.serial) == null) return null;
return .{
- .name = if (c.file == .dir) (std.fmt.bufPrint(&p.fs.node_name, "{d}", .{c.index}) catch unreachable) else "tag",
- .node = Node.ofCol(c.index, c.file),
+ .name = if (c.file == .dir) (std.fmt.bufPrint(&p.fs.node_name, "{d}", .{c.serial}) catch unreachable) else "tag",
+ .node = Node.ofCol(c.serial, c.file),
.dir = c.file == .dir,
.mode = if (c.file == .dir) 0o755 else 0o666,
- .size = if (c.file == .tag) cols.headerText(p, c.index).?.len + 1 else 0,
+ .size = if (c.file == .tag) cols.headerText(p, c.serial).?.len + 1 else 0,
.mtime = p.fs.started,
.append = c.file == .tag,
};
@@ -548,18 +550,20 @@ fn lookup(p: *Pardes, req: Req, target: Target) Reply {
if (serial == 0) return Reply.fail(req.tag, E.NOENT);
break :pane Node.of(serial, .dir);
},
- // A column is its index, in decimal digits.
+ // A column is its serial, in decimal digits and never 0.
.col => col: {
- if (name.len > 4) return Reply.fail(req.tag, E.NOENT);
+ if (name.len > 10) return Reply.fail(req.tag, E.NOENT);
for (name) |c| if (c < '0' or c > '9') return Reply.fail(req.tag, E.NOENT);
- break :col Node.ofCol(std.fmt.parseInt(u32, name, 10) catch return Reply.fail(req.tag, E.NOENT), .dir);
+ const serial = std.fmt.parseInt(u32, name, 10) catch return Reply.fail(req.tag, E.NOENT);
+ if (serial == 0) return Reply.fail(req.tag, E.NOENT);
+ break :col Node.ofCol(serial, .dir);
},
else => return Reply.fail(req.tag, E.NOTDIR),
},
.col => |c| col: {
if (c.file != .dir) return Reply.fail(req.tag, E.NOTDIR);
if (!std.mem.eql(u8, name, "tag")) return Reply.fail(req.tag, E.NOENT);
- break :col Node.ofCol(c.index, .tag);
+ break :col Node.ofCol(c.serial, .tag);
},
.pane => |t| pane: {
_ = p.paneBySerial(t.serial) orelse return Reply.fail(req.tag, E.NOENT);
@@ -626,14 +630,15 @@ fn readdir(p: *Pardes, req: Req, target: Target) Reply {
continue;
}
var buf: [16]u8 = undefined;
- stageDirent(out, p.gpa, Node.ofCol(c, .dir), true, std.fmt.bufPrint(&buf, "{d}", .{c}) catch unreachable);
+ const serial = layout.columnSerial(p, c);
+ stageDirent(out, p.gpa, Node.ofCol(serial, .dir), true, std.fmt.bufPrint(&buf, "{d}", .{serial}) catch unreachable);
},
else => return Reply.fail(req.tag, E.NOTDIR),
},
.col => |c| {
- if (c.index >= p.ncol) return Reply.fail(req.tag, E.NOENT);
+ if (layout.columnBySerial(p, c.serial) == null) return Reply.fail(req.tag, E.NOENT);
if (c.file != .dir) return Reply.fail(req.tag, E.NOTDIR);
- if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, Node.ofCol(c.index, .tag), false, "tag");
+ if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, Node.ofCol(c.serial, .tag), false, "tag");
},
.pane => |t| {
const id = p.paneBySerial(t.serial) orelse return Reply.fail(req.tag, E.NOENT);
@@ -668,7 +673,7 @@ fn open(p: *Pardes, req: Req, target: Target) Reply {
.log => .{ .log = .{} },
else => return .{ .tag = req.tag },
},
- .col => |c| return if (c.index < p.ncol) .{ .tag = req.tag } else Reply.fail(req.tag, E.NOENT),
+ .col => |c| return if (layout.columnBySerial(p, c.serial) != null) .{ .tag = req.tag } else Reply.fail(req.tag, E.NOENT),
.pane => |t| what: {
const pn = p.panes[p.paneBySerial(t.serial) orelse return Reply.fail(req.tag, E.NOENT)].?;
if (t.file.inPty() and !pn.isTerminal()) return Reply.fail(req.tag, E.NOENT);
@@ -749,7 +754,7 @@ fn releaseHandle(p: *Pardes, req: Req) void {
p.panes[id].?.fs.tag_rewrite = false;
p.panes[id].?.fs.tag_held_newline = false;
};
- if (t == .col and t.col.file == .tag) cols.released(p, t.col.index);
+ if (t == .col and t.col.file == .tag) cols.released(p, t.col.serial);
if (t == .top and t.top == .tag) cols.released(p, null);
const o = openOf(p, req) orelse return;
const of: ?*Pane = if (t == .pane) (if (p.paneBySerial(t.pane.serial)) |id| p.panes[id] else null) else null;
@@ -786,7 +791,7 @@ fn setattr(p: *Pardes, req: Req, target: Target) Reply {
return failText(req.tag, E.INVAL, pane.e_addr_failed);
if (pane.truncate(p, p.panes[id].?, t.file) != .ok) return Reply.fail(req.tag, E.NOMEM);
},
- .col => |c| if (c.file == .tag and cols.truncate(p, c.index) != .ok) return Reply.fail(req.tag, E.NOENT),
+ .col => |c| if (c.file == .tag and cols.truncate(p, c.serial) != .ok) return Reply.fail(req.tag, E.NOENT),
.top => |f| if (f == .tag and cols.truncate(p, null) != .ok) return Reply.fail(req.tag, E.NOMEM),
};
return .{ .tag = req.tag, .attr = attrOf(p, target) orelse return Reply.fail(req.tag, E.NOENT) };
@@ -877,7 +882,7 @@ fn readFile(p: *Pardes, req: Req, target: Target) Reply {
if (t.file.inPty() and !pn.isTerminal()) return Reply.fail(req.tag, E.NOENT);
return pane.read(p, req, id, pn, t.file);
},
- .col => |c| return if (c.file == .tag) cols.read(p, req, c.index) else Reply.fail(req.tag, E.PERM),
+ .col => |c| return if (c.file == .tag) cols.read(p, req, c.serial) else Reply.fail(req.tag, E.PERM),
}
}
@@ -897,7 +902,7 @@ fn write(p: *Pardes, req: Req, target: Target) Reply {
if (t.file.inPty() and !pn.isTerminal()) return Reply.fail(req.tag, E.NOENT);
return pane.write(p, req, id, pn, t.file);
},
- .col => |c| return if (c.file == .tag) cols.write(p, req, c.index) else Reply.fail(req.tag, E.PERM),
+ .col => |c| return if (c.file == .tag) cols.write(p, req, c.serial) else Reply.fail(req.tag, E.PERM),
}
}