diff options
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 56 |
1 files changed, 50 insertions, 6 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index ec406094..4bc5829b 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -4555,6 +4555,10 @@ pub const Pardes = struct { /// where the shell wrote the last dump (shell reports back after /// write_dump); shown in the topbar as `Restore <path>` last_dump: ?[]const u8 = null, + /// What a session word (Newcol, New, Exit) runs with when no pane is + /// there to run it: the window Delcol emptied. Never installed, made the + /// first time it is wanted. + stand_in: ?*Pane = null, /// a Restore builtin wants this dump loaded into the live session; the /// shell consumes it via takeRestore each frame (restore contents stay host-fed) restore_req: ?[]const u8 = null, @@ -4780,6 +4784,7 @@ pub const Pardes = struct { for (p.panes) |slot| if (slot) |pane| p.noteClosed(pane); p.saveRecent(); p.recent.deinit(p.recentGpa()); + if (p.stand_in) |pane| p.teardownPane(pane); look.cancelLookHover(p); if (p.repl_ask) |ask| p.gpa.free(ask.text); for (0..MAX_PANES) |id| p.dropPendingWrite(id); @@ -5024,7 +5029,8 @@ pub const Pardes = struct { } fn newScratch(p: *Pardes, from_id: usize, free: usize, kind: exec.NewPane) !*Pane { - const src = p.panes[from_id] orelse return error.MissingPane; + // None asking (an empty window): the session's, as pane/new's is. + const src_or = p.panes[from_id]; const content = try p.gpa.dupe(u8, ""); errdefer p.gpa.free(content); // A terminal that has not said where it is yet (the boot layout's) @@ -5032,10 +5038,10 @@ pub const Pardes = struct { // 9P's pane/new, and a New from a column's or the workspace's tag: // no pane asked for it, whichever last had the keyboard (acme's new // window has acme's directory). - const own = kind != .fs and !p.exec_header; - const dir = if (own) paneDir(src) else ""; + const src = if (kind != .fs and !p.exec_header) src_or else null; + const dir = if (src) |s| paneDir(s) else ""; const np = try panes.Output.open(p, free, if (dir.len == 0) p.sessionDir() else dir, .{ .cmd = .New }, "", content); - if (own) np.cwd = .{ .inherited = src }; + if (src) |s| np.cwd = .{ .inherited = s }; np.body.cur_pinned = true; return np; } @@ -5056,6 +5062,8 @@ pub const Pardes = struct { /// Newcol: an empty column right of the calling pane's, the keyboard /// on its tag, for the next pane made to fill. pub fn newColumn(p: *Pardes, from_id: usize) void { + // An empty window (Delcol took the last column): its first column. + if (layout.firstColumn(p)) |c| return tagline.enterHeader(p, c); const col = p.keyboardColumn(from_id) orelse return; // Said, not silently nothing: "no space" is 9ns's word for ENOSPC. const c = layout.insertColumn(p, col, false) orelse { @@ -5331,6 +5339,12 @@ pub const Pardes = struct { } } + /// The pane a session word runs with in an empty window. + pub fn standIn(p: *Pardes) ?*Pane { + if (p.stand_in == null) p.stand_in = panes.Terminal.createDoc(p.gpa, p.screen_w, p.screen_h) catch null; + return p.stand_in; + } + /// Drop a pane's parked bytes: its pty is gone, and the slot it occupied /// may be handed to a different pane next frame. fn dropPendingWrite(p: *Pardes, id: usize) void { @@ -6756,7 +6770,9 @@ pub const Pardes = struct { p.panes[closed] = null; } layout.dropColumn(p, col); - if (p.panes[p.active] == null) p.active = beside orelse p.anyPane() orelse return p.quitEmpty(); + // The last column gone, the window stays, empty but for the + // workspace tag, as acme's does; Newcol starts again from there. + if (p.panes[p.active] == null) p.active = beside orelse p.anyPane() orelse return tagline.enterHeader(p, null); } /// No pane is left: the session is over. @@ -6798,7 +6814,7 @@ pub const Pardes = struct { } /// Any live pane: the last resort when nothing took the closed one's place. - fn anyPane(p: *const Pardes) ?usize { + pub fn anyPane(p: *const Pardes) ?usize { for (p.panes, 0..) |slot, k| if (slot != null) return k; return null; } @@ -8517,3 +8533,31 @@ test "a Save the host could not do logs no save record" { p.perform(.{ .save_file = .{ .pane = 0 } }); try std.testing.expect(th.logHas(p, "\nsave ")); } + +test "Delcol on the last column leaves the window, drawn and typed into, and Newcol starts it again" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 24 }); + defer p.deinit(); + while (p.nextEffect()) |_| {} + while (p.ncol > 0) { + p.exec_column = 0; + _ = p.executeBuiltinLine(p.active, "Delcol"); + p.exec_column = null; + p.sync(); + } + try std.testing.expect(!p.quit); + try std.testing.expect(p.anyPane() == null); + // Drawn, and keys go to the workspace tag. + _ = try p.render(p.frame_arena.allocator()); + p.update(.{ .key = .{ .cp = 'x', .text = "x" } }); + p.update(.{ .key = .{ .cp = Key.enter } }); + p.sync(); + _ = try p.render(p.frame_arena.allocator()); + try std.testing.expect(!p.quit); + _ = p.executeBuiltinLine(p.active, "Newcol"); + p.sync(); + try std.testing.expectEqual(@as(usize, 1), p.ncol); + _ = p.executeBuiltinLine(p.active, "New"); + p.sync(); + try std.testing.expect(p.anyPane() != null); + _ = try p.render(p.frame_arena.allocator()); +} |
