diff options
Diffstat (limited to 'src/ninep')
| -rw-r--r-- | src/ninep/ctl.zig | 27 | ||||
| -rw-r--r-- | src/ninep/tree.zig | 18 |
2 files changed, 31 insertions, 14 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index e47dec16..4afc82dc 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -12,6 +12,7 @@ const panes = @import("../panes.zig"); const config = @import("../config.zig"); const fs = @import("../fs.zig"); const tagline = @import("../tagline.zig"); +const layout = @import("../layout.zig"); const builtins = @import("../builtins.zig"); const exec_line = @import("../exec.zig"); const tree = @import("tree.zig"); @@ -162,7 +163,9 @@ pub fn paneText(p: *Pardes, pane: *Pane, buf: []u8) []const u8 { }) catch return w.buffered(); const font = p.settings.font.effective_name.get(); writeQuoted(&w, if (font.len == 0) "default" else font) catch return w.buffered(); - w.print(" {d:>11} {s} ", .{ config.tab_width, if (p.panes[p.active] == pane) "current" else "notcurrent" }) catch {}; + // While a column's or the workspace's tag has the keyboard, no pane does. + const current = p.panes[p.active] == pane and !p.header_focus; + w.print(" {d:>11} {s} ", .{ config.tab_width, if (current) "current" else "notcurrent" }) catch {}; return w.buffered(); } @@ -333,10 +336,15 @@ pub fn readCommands(p: *Pardes, req: Req) Reply { // ---- /focus ---- /// The pane with the keyboard, which a write of a serial moves, the way -/// writing `current` to rio's wctl does (rio(4)). +/// writing `current` to rio's wctl does (rio(4)). While a column's or the +/// workspace's tag has it, no pane does, and this reads empty. A write +/// gives the keyboard and nothing else: a folded pane stays folded, as +/// rio keeps `current` apart from `unhide`. pub fn readFocus(p: *Pardes, req: Req) Reply { + const out = p.fs.stage(p.gpa); + if (p.header_focus) return tree.stagedReply(p, req); const pane = p.panes[p.active] orelse return tree.stagedReply(p, req); - p.fs.stage(p.gpa).print(p.gpa, "{d}\n", .{pane.serial}) catch return Reply.fail(req.tag, E.NOMEM); + out.print(p.gpa, "{d}\n", .{pane.serial}) catch return Reply.fail(req.tag, E.NOMEM); return tree.stagedReply(p, req); } @@ -506,8 +514,11 @@ test "focus reads the pane with the keyboard, and a serial written to it moves t try testing.expectEqual(@as(u64, rd(p, focus, 0, 64).bytes.len), call(p, .{ .tag = 1, .op = .getattr, .node = focus }).reply.attr.size); try testing.expect(std.mem.endsWith(u8, rd(p, Node.of(first, .ctl), 0, 4096).bytes, " notcurrent ")); - // A header had the keyboard: the write takes it back to the pane. + // A header has the keyboard: no pane does, and a write takes it back. tagline.enterHeader(p, null); + try testing.expectEqualStrings("", rd(p, focus, 0, 64).bytes); + try testing.expectEqual(@as(u64, 0), call(p, .{ .tag = 1, .op = .getattr, .node = focus }).reply.attr.size); + try testing.expect(std.mem.endsWith(u8, rd(p, Node.of(second, .ctl), 0, 4096).bytes, " notcurrent ")); try testing.expectEqual(Status.ok, wr(p, focus, try std.fmt.bufPrint(&line, "{d}\n", .{first})).reply.status); try testing.expect(!p.header_focus); try testing.expectEqual(p.paneBySerial(first).?, p.active); @@ -518,6 +529,14 @@ test "focus reads the pane with the keyboard, and a serial written to it moves t try testing.expectEqual(E.NOENT, wr(p, focus, "99999").errno()); for ([_][]const u8{ "", "two", "-1", "1 2" }) |bad| try testing.expectEqual(E.INVAL, wr(p, focus, bad).errno()); try testing.expectEqual(p.paneBySerial(first).?, p.active); + + // Focus gives the keyboard only: a folded pane stays folded. + const folded = p.paneBySerial(second).?; + layout.toggleCollapse(p, folded); + try testing.expect(p.panes[folded].?.collapsed); + try testing.expectEqual(Status.ok, wr(p, focus, try std.fmt.bufPrint(&line, "{d}", .{second})).reply.status); + try testing.expectEqual(folded, p.active); + try testing.expect(p.panes[folded].?.collapsed); } test "the pane ctl takes acme's verbs and the pane's builtins, and refuses the rest in Plan 9's words" { diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index 27ad02c8..e9c6b8ea 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -438,6 +438,7 @@ fn topSize(p: *Pardes, f: TopFile) u64 { .ctl => ctl.rootLen(p), .commands => ctl.commandsLen(), .focus => focus: { + if (p.header_focus) break :focus 0; const pn = p.panes[p.active] orelse break :focus 0; var digits: [16]u8 = undefined; break :focus (std.fmt.bufPrint(&digits, "{d}\n", .{pn.serial}) catch unreachable).len; @@ -516,14 +517,12 @@ fn readdir(p: *Pardes, req: Req, target: Target) Reply { switch (target) { .top => |f| switch (f) { .root => { - inline for (.{ TopFile.README, TopFile.index, TopFile.status, TopFile.look, TopFile.exec, TopFile.log, TopFile.screen, TopFile.listeners, TopFile.pane }) |t| { + // The guide, then what describes the session, then the + // files that act, then the directories. + inline for (.{ TopFile.README, TopFile.index, TopFile.status, TopFile.focus, TopFile.ctl, TopFile.commands, TopFile.look, TopFile.exec, TopFile.log, TopFile.screen, TopFile.listeners, TopFile.pane }) |t| { if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, @intFromEnum(t), t.dir(), t.fileName()); } if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, fs.os_root, true, "os"); - // After the first ten, which older clients list by position. - inline for (.{ TopFile.focus, TopFile.ctl, TopFile.commands }) |t| { - if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, @intFromEnum(t), t.dir(), t.fileName()); - } sources.stage(p, out, "", &skip); }, .pane => { @@ -901,13 +900,12 @@ test "readdir lists the root and a pane directory without creating anything" { @memcpy(top_bytes[0..top_reply.bytes.len], top_reply.bytes); const top = th.dirents(top_bytes[0..top_reply.bytes.len], &buf); try testing.expect(top.len >= 10); - for ([_][]const u8{ "README", "index", "status", "look", "exec", "log", "screen", "listeners", "pane", "os" }, 0..) |name, i| { + for ([_][]const u8{ "README", "index", "status", "focus", "ctl", "commands", "look", "exec", "log", "screen", "listeners", "pane", "os" }, 0..) |name, i| { try testing.expectEqualStrings(name, top[i].name); - try testing.expectEqual(i >= 8, top[i].dir); + try testing.expectEqual(i >= 11, top[i].dir); } - try testing.expectEqual(@intFromEnum(TopFile.pane), top[8].node); - try testing.expectEqual(fs.os_root, top[9].node); - try testing.expectEqualStrings("focus", top[10].name); + try testing.expectEqual(@intFromEnum(TopFile.pane), top[11].node); + try testing.expectEqual(fs.os_root, top[12].node); var idbuf: [16]u8 = undefined; try testing.expect(th.nameAt(top, try std.fmt.bufPrint(&idbuf, "{d}", .{serial})) == null); try testing.expect(th.nameAt(top, "self") == null); |
