summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig56
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());
+}