summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-08 05:18:55 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commit2826704c7f829b5b5375ed2bf7414b455d3b0735 (patch)
tree87d79168d297d1d599a81c82635580d073302111
parent4314f442048c6654b9179633539495836f7fae82 (diff)
downloadpardes-2826704c7f829b5b5375ed2bf7414b455d3b0735.tar.gz
pardes-2826704c7f829b5b5375ed2bf7414b455d3b0735.zip
new panes reject a too-short split parent: if the chosen parent would leave the new pane under 2 body rows, splitParent swaps in a qualifying pane (same column first), else the tallest pane anywhere; applied to Alt-n, look-dir, placeDoc and ttyForDir. New splitparent.snap.
-rw-r--r--src/pardes.zig43
-rw-r--r--test/snapshots/splitparent.golden99
-rw-r--r--test/snapshots/splitparent.snap27
3 files changed, 161 insertions, 8 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index c14154e5..0219d474 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -1203,9 +1203,10 @@ pub const Pardes = struct {
const free = p.freeSlot() orelse return;
const nt = p.newShell(free, "") catch return;
nt.greet = true;
- const f = p.layoutFindTerm(p.active).?;
+ const src = p.splitParent(p.active);
+ const f = p.layoutFindTerm(src).?;
p.layoutInsert(f.col, f.idx + 1, free);
- p.splitBelow(p.active, nt);
+ p.splitBelow(src, nt);
p.active = free;
return;
}
@@ -3973,6 +3974,26 @@ pub const Pardes = struct {
if (p.panes[sib]) |s| s.vweight += @as(f32, @floatFromInt(@max(1, p.rects[id].h)));
}
+ /// The parent a new pane splits from must be tall enough that splitBelow
+ /// leaves the NEW pane at least 2 body rows (the parent keeps tag+1 row,
+ /// the new pane needs tag+2). A too-short choice is swapped for a
+ /// qualifying pane (same column first, keeping the split local), else the
+ /// tallest pane anywhere.
+ fn splitParent(p: *Pardes, want: usize) usize {
+ const need = 2 * BOX_H + 3;
+ if (p.rects[want].h >= need) return want;
+ if (p.layoutFindTerm(want)) |f| for (0..p.col_n[f.col]) |k| {
+ if (p.rects[p.col_terms[f.col][k]].h >= need) return p.col_terms[f.col][k];
+ };
+ var tallest = want;
+ for (0..p.ncol) |c| for (0..p.col_n[c]) |k| {
+ const pid = p.col_terms[c][k];
+ if (p.rects[pid].h >= need) return pid;
+ if (p.rects[pid].h > p.rects[tallest].h) tallest = pid;
+ };
+ return tallest;
+ }
+
/// Open a window BELOW `src` (acme-style) without rebalancing the column:
/// shrink ONLY src to its content height (cursor row kept visible) and hand
/// the freed rows to `nw` — together they fill src's old slot and the other
@@ -4039,8 +4060,12 @@ pub const Pardes = struct {
const nt = p.newShell(free, dir) catch return null;
nt.greet = false;
const rc = if (p.ncol > 0) p.ncol - 1 else 0;
- if (p.col_n[rc] > 0) p.splitBelow(p.col_terms[rc][p.col_n[rc] - 1], nt);
- p.layoutInsert(rc, p.col_n[rc], free);
+ if (p.col_n[rc] > 0) {
+ const src = p.splitParent(p.col_terms[rc][p.col_n[rc] - 1]);
+ const f = p.layoutFindTerm(src).?;
+ p.splitBelow(src, nt);
+ p.layoutInsert(f.col, f.idx + 1, free);
+ } else p.layoutInsert(rc, p.col_n[rc], free);
return free;
}
@@ -4225,9 +4250,10 @@ pub const Pardes = struct {
const free = p.freeSlot() orelse return;
const nt = p.newShell(free, dir) catch return;
nt.greet = true;
- const f = p.layoutFindTerm(id).?;
+ const src = p.splitParent(id);
+ const f = p.layoutFindTerm(src).?;
p.layoutInsert(f.col, f.idx + 1, free);
- p.splitBelow(id, nt);
+ p.splitBelow(src, nt);
p.active = free;
},
.file => |target| {
@@ -4359,9 +4385,10 @@ pub const Pardes = struct {
};
};
if (src_id) |sid| {
- const sf = p.layoutFindTerm(sid).?;
+ const src = p.splitParent(sid);
+ const sf = p.layoutFindTerm(src).?;
p.layoutInsert(sf.col, sf.idx + 1, free);
- p.splitBelow(sid, nt);
+ p.splitBelow(src, nt);
p.active = free;
} else {
p.stackDocLeft(free, nt);
diff --git a/test/snapshots/splitparent.golden b/test/snapshots/splitparent.golden
new file mode 100644
index 00000000..b838cdad
--- /dev/null
+++ b/test/snapshots/splitparent.golden
@@ -0,0 +1,99 @@
+== snap shrunk grid=100x30 cursor=4,3
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/splitparent/cwd Del NOR /tmp/pardes-snap/splitparent/cwd Del
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+== snap swap-parent grid=100x30 cursor=4,7
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/splitparent/cwd Del NOR /tmp/pardes-snap/splitparent/cwd Del
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+|
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+== snap tallest grid=100x5 cursor=54,4
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/splitparent/cwd Del NOR /tmp/pardes-snap/splitparent/cwd Del
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+| NOR /tmp/pardes-snap/splitparent/cwd Del NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+== snap regrown grid=100x30 cursor=54,18
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/splitparent/cwd Del NOR /tmp/pardes-snap/splitparent/cwd Del
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+|
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+| NOR /tmp/pardes-snap/splitparent/cwd Del
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
diff --git a/test/snapshots/splitparent.snap b/test/snapshots/splitparent.snap
new file mode 100644
index 00000000..77a1fba1
--- /dev/null
+++ b/test/snapshots/splitparent.snap
@@ -0,0 +1,27 @@
+# a new pane never opens under a too-short parent: Alt-n from a tag-only pane
+# splits the tall sibling in its column instead; when NO pane could leave the
+# newcomer 2 body rows, the tallest one anywhere is split
+start 30 100 -n 3
+stable 700 20000
+# shrink pane 0 (top-left) to just its tagline
+press left 20 16
+drag left 20 2
+release left 20 2
+motion 40 25
+stable 500 8000
+snap shrunk
+# Alt-n from the tag-only pane: the new shell opens below the tall sibling
+# underneath it, not as another 1-row sliver
+key a-n
+stable 700 15000
+snap swap-parent
+# squeeze the grid until no pane is 5 rows tall, then Alt-n again: the
+# tallest pane (right column) is split even though the active one is left
+resize 5 100
+stable 700 15000
+key a-n
+stable 700 15000
+snap tallest
+resize 30 100
+stable 700 15000
+snap regrown