diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 00:23:55 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | 4881c5d13c6a705a8c8bdb0181c33f9a500b5a74 (patch) | |
| tree | 31ee1398657b271d08830a1efad9e6d9f206aa68 /src/ninep/tree.zig | |
| parent | 15ddd805905f785f4dde463d4d6b91e1d2c41e26 (diff) | |
| download | pardes-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.zig | 49 |
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), } } |
