summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/tags.md9
-rw-r--r--src/draw.zig11
-rw-r--r--src/gui/gui.zig9
-rw-r--r--src/layout.zig17
-rw-r--r--src/mouse.zig59
-rw-r--r--src/pardes.zig5
-rw-r--r--src/tutor.txt9
-rw-r--r--test/snapshots/builtins.golden1
-rw-r--r--test/snapshots/lookrange.golden1
-rw-r--r--test/snapshots/lsprelpath.golden1
-rw-r--r--test/snapshots/rsearch.golden17
-rw-r--r--test/snapshots/rsearch.snap9
-rw-r--r--test/snapshots/shrinktag.snap37
-rw-r--r--test/snapshots/splitparent.snap9
-rw-r--r--test/snapshots/tagbottom.golden4
-rw-r--r--test/snapshots/tagbottom.snap18
-rw-r--r--test/snapshots/windowops.golden3
-rw-r--r--test/snapshots/windowops.snap13
18 files changed, 149 insertions, 83 deletions
diff --git a/docs/tags.md b/docs/tags.md
index 885eb22f..c1034cb4 100644
--- a/docs/tags.md
+++ b/docs/tags.md
@@ -30,6 +30,15 @@ edge will land, beside the rule as a border drag's rail does. Only columns
between the old and new positions shift. Each column keeps its width, panes and
command text.
+Two panes in a column are resized as acme's windows are, by the grip: drag
+a pane's grip up or down its own column and its top follows, the pane above
+taking or giving the rows, either one down to its tag alone (acme's
+coldragwin keeps a window its tag line); drop it in another column and the
+pane moves there. In the GUI the 2 px rule between two panes also drags
+their seam. No row of text is a handle: a pane's last row takes a click like
+any other, and a terminal, which draws no rule, resizes by the grip. A
+column's right edge still drags its width.
+
When Look opens the first document and its source column is too narrow for
a new column, it splits below the originating pane, just like `Tty`, instead
of inserting at the top of the leftmost column. The originating terminal is
diff --git a/src/draw.zig b/src/draw.zig
index fb770b60..4ad1a1fe 100644
--- a/src/draw.zig
+++ b/src/draw.zig
@@ -504,15 +504,8 @@ pub fn render(p: *Pardes, arena: std.mem.Allocator) !*Surface {
s.addRegion(.{ .kind = .guide, .rect = .{ .x = p.hover_col, .y = p.topBarHeight(), .w = 1, .h = s.rows -| p.topBarHeight() } });
}
}
- for (0..p.ncol) |cc| {
- if (p.hover_col < p.col_x[cc] or p.hover_col >= p.col_x[cc] + p.col_w[cc]) continue;
- // the same seam the h-handle hit test picks (see there)
- if (mouse.seamIdxAt(p, cc, p.hover_row) != null) {
- var col = p.col_x[cc];
- while (col < p.col_x[cc] + p.col_w[cc]) : (col += 1) s.overlayDash(col, p.hover_row, "╌");
- s.addRegion(.{ .kind = .guide, .rect = .{ .x = p.col_x[cc], .y = p.hover_row, .w = p.col_w[cc], .h = 1 } });
- }
- }
+ // No hint over a pane's last row: a row of text is no handle; two
+ // panes resize by the rule between them or by the grip.
for (0..p.ncol -| 1) |cn| {
if (p.hover_col != p.col_x[cn] + p.col_w[cn] -| 1) continue;
if (mouse.seamIdxAt(p, cn, p.hover_row) != null) continue;
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 141a802a..ab281cb6 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -1972,7 +1972,11 @@ fn glyphForCodepoint(g: *const Gui, cp: u32) FaceGlyph {
}
const CellLayout = struct { w: f32, h: f32, x_off: f32, y_off: f32 };
-const MouseCell = struct { col: u16, row: u16, body_hit: ?pardes.Mouse.BodyHit = null, tag_hit: ?pardes.TagHit = null };
+const MouseCell = struct { col: u16, row: u16, body_hit: ?pardes.Mouse.BodyHit = null, tag_hit: ?pardes.TagHit = null, rule_above: bool = false };
+
+/// How near a row's top edge a press is on the rule drawn there between two
+/// panes: the rule's 2 px and a pixel either side.
+const rule_grab_px: f32 = 3;
const WindowGeometry = struct {
window_w: f32,
window_h: f32,
@@ -3420,6 +3424,7 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
.row = mc.row,
.tag_hit = mc.tag_hit,
.body_hit = mc.body_hit,
+ .rule_above = mc.rule_above,
.ctrl = (c.SDL_GetModState() & c.SDL_KMOD_CTRL) != 0,
},
});
@@ -3720,6 +3725,8 @@ fn gridCellAtDimensions(
) MouseCell {
const row: u16 = @intFromFloat(@min(@floor(@max(y, 0) / @max(body_h, 1)), 10_000));
var point: MouseCell = .{ .col = @intFromFloat(@min(@floor(@max(x, 0) / @max(body_w, 1)), 10_000)), .row = row };
+ // On the rule over this row, which is where two panes meet if they do.
+ point.rule_above = row > 0 and @max(y, 0) - @as(f32, @floatFromInt(row)) * @max(body_h, 1) < rule_grab_px;
if (core) |p| if (p.presentation.pointerFractional(p.screen_w, p.screen_h, x / @max(body_w, 1), y / @max(body_h, 1))) |mapped| {
for (p.surface.tagLayers()) |*layer| {
if (layer.tagHit(mapped.x * body_w, mapped.y * body_h, body_w, body_h, tagline_w, @floatFromInt(p.row_metrics.tagline_h))) |hit| {
diff --git a/src/layout.zig b/src/layout.zig
index 6de7a912..25c95d30 100644
--- a/src/layout.zig
+++ b/src/layout.zig
@@ -162,8 +162,15 @@ pub fn targetColumn(p: *Pardes, cur_x: u16) usize {
}
pub fn splitRowForExtent(y: u16, h: u16, cur_y: u16) ?u16 {
+ return splitRowFor(y, h, cur_y, null);
+}
+
+/// As `splitRowForExtent`, each pane keeping at least `least` rows when
+/// given: a pane dragged by its grip within its own column is how a
+/// terminal resizes, and acme lets either window keep only its tag.
+fn splitRowFor(y: u16, h: u16, cur_y: u16, least: ?u16) ?u16 {
if (h < 2) return null;
- const min_each: u16 = if (h >= config.MINH * 2) config.MINH else 1;
+ const min_each: u16 = least orelse if (h >= config.MINH * 2) config.MINH else 1;
const lo = y +| min_each;
const hi = y + h - min_each;
if (lo > hi) return y + h / 2;
@@ -176,7 +183,11 @@ pub fn movePlacement(p: *Pardes, id: usize, cur_x: u16, cur_y: u16) ?MovePlaceme
if (tc == src.col and p.col_n[src.col] == 1) return null;
if (tc == src.col) {
const sr = p.rects[id];
- if (cur_y >= sr.y and cur_y < sr.y + sr.h) return null;
+ // Dropped on itself it stays, unless dragged down from its top with
+ // a pane above: its top moves down there, the pane above taking the
+ // rows, as acme's window dragged by its button does. With no rule
+ // between panes, that is how a terminal resizes them.
+ if (cur_y >= sr.y and cur_y < sr.y + sr.h and (src.idx == 0 or cur_y <= sr.y)) return null;
}
var heights: [MAX_PANES]u16 = @splat(0);
for (0..p.ncol) |c| {
@@ -196,7 +207,7 @@ pub fn movePlacement(p: *Pardes, id: usize, cur_x: u16, cur_y: u16) ?MovePlaceme
const pid = p.col_panes[tc][k];
if (pid == id) continue;
const h = heights[pid];
- const row = splitRowForExtent(y, h, cur_y) orelse {
+ const row = splitRowFor(y, h, cur_y, if (tc == src.col) BOX_H else null) orelse {
y +|= h;
continue;
};
diff --git a/src/mouse.zig b/src/mouse.zig
index 36786612..1ca53017 100644
--- a/src/mouse.zig
+++ b/src/mouse.zig
@@ -97,13 +97,50 @@ fn cornerFixture(gpa: std.mem.Allocator) !*Pardes {
return p;
}
+test "a pane's last row of text is no resize handle; the rule over the next pane is" {
+ if (platform == .web) return;
+ const p = try cornerFixture(std.testing.allocator);
+ defer p.deinit();
+ const seam = seamRowOf(p, 1, 0);
+ const inside = p.col_x[1] + p.col_w[1] / 2;
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = inside, .row = seam } });
+ try std.testing.expect(p.drag != .border_h);
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = inside, .row = seam } });
+ try std.testing.expect(nudgeRightSeam(p, 2) == seam + 2);
+}
+
+test "a pane's grip dragged up or down its own column moves its top, down to a tag alone above" {
+ if (platform == .web) return;
+ const p = try cornerFixture(std.testing.allocator);
+ defer p.deinit();
+ const upper = p.col_panes[1][0];
+ const lower = p.col_panes[1][1];
+ const grip_x = p.rects[lower].x;
+ // Up, past the pane above's first row: it keeps one row, its tag.
+ const top = p.rects[upper].y;
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = grip_x, .row = p.rects[lower].y } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .drag, .col = grip_x, .row = top } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = grip_x, .row = top } });
+ p.sync();
+ try std.testing.expectEqual(@as(u16, 1), p.rects[upper].h);
+ try std.testing.expectEqual(lower, p.col_panes[1][1]);
+ // Down, inside itself: its top follows, the pane above taking the rows.
+ const to = p.rects[lower].y + 6;
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = grip_x, .row = p.rects[lower].y } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .drag, .col = grip_x, .row = to } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = grip_x, .row = to } });
+ p.sync();
+ try std.testing.expectEqual(to, p.rects[lower].y);
+}
+
fn nudgeRightSeam(p: *Pardes, delta: i32) u16 {
const from = seamRowOf(p, 1, 0);
const inside = p.col_x[1] + p.col_w[1] / 2;
const to: u16 = @intCast(@as(i32, from) + delta);
- p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = inside, .row = from } });
- p.update(.{ .mouse = .{ .button = .left, .kind = .drag, .col = inside, .row = to } });
- p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = inside, .row = to } });
+ // On the rule a pixel frontend draws over the lower pane's first row.
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = inside, .row = from + 1, .rule_above = true } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .drag, .col = inside, .row = to + 1 } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = inside, .row = to + 1 } });
p.sync();
return seamRowOf(p, 1, 0);
}
@@ -437,13 +474,17 @@ pub fn handleMouse(p: *Pardes, m: Mouse) void {
return;
}
}
- for (0..p.ncol) |cc| {
+ // Two panes are resized on the rule between them, never on a
+ // row of text; with no rule, by the grip, as acme moves a
+ // window by its button.
+ if (m.rule_above and mrow > 0) for (0..p.ncol) |cc| {
if (mcol < p.col_x[cc] or mcol >= p.col_x[cc] + p.col_w[cc]) continue;
- if (seamIdxAt(p, cc, mrow)) |k| {
- p.drag = .{ .border_h = .{ .col = cc, .top_idx = k, .cur_y = mrow } };
+ const seam = if (p.settings.tag_bottom) mrow else mrow - 1;
+ if (seamIdxAt(p, cc, seam)) |k| {
+ p.drag = .{ .border_h = .{ .col = cc, .top_idx = k, .cur_y = seam } };
return;
}
- }
+ };
const id = hovered orelse return;
const r = p.rects[id];
const pane = p.panes[id] orelse return;
@@ -597,7 +638,9 @@ pub fn dragUpdate(p: *Pardes, mcol: u16, mrow: u16, body_hit: ?Mouse.BodyHit) vo
if (k + 1 < p.col_n[cc]) {
const a = p.rects[p.col_panes[cc][k]];
const b = p.rects[p.col_panes[cc][k + 1]];
- d.cur_y = clampBorderRow(a.y, a.h, b.h, mrow, p.settings.tag_bottom);
+ // Held by the rule over the lower pane: the seam is the row above.
+ const seam = if (p.settings.tag_bottom) mrow else mrow -| 1;
+ d.cur_y = clampBorderRow(a.y, a.h, b.h, seam, p.settings.tag_bottom);
} else d.cur_y = mrow;
},
.column_move => |*d| d.cur_x = mcol,
diff --git a/src/pardes.zig b/src/pardes.zig
index ea03b3eb..8dbe6744 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -3483,6 +3483,11 @@ pub const Mouse = struct {
ctrl: bool = false,
body_hit: ?BodyHit = null,
tag_hit: ?TagHit = null,
+ /// A pixel frontend's press on the rule it draws at the top of this row,
+ /// which is where two panes meet if they do: the one grab that resizes
+ /// them there. A row of text never is one; a terminal, with no rule,
+ /// resizes by the grip.
+ rule_above: bool = false,
};
pub const Key = struct {
diff --git a/src/tutor.txt b/src/tutor.txt
index 0893415e..c59deeae 100644
--- a/src/tutor.txt
+++ b/src/tutor.txt
@@ -132,6 +132,15 @@
DelAbove close it, giving the space to the pane above (Del k)
DelBelow close it, giving the space to the pane below (Del j)
+ RESIZE, AS ACME MOVES A WINDOW
+ the grip (the box left of a pane's tag) drag it: drop it in another
+ column to move the pane there, or up or down its own
+ column to move its top, the pane above taking or giving
+ the rows -- down to its tag alone
+ the rule in the GUI, the line between two panes drags their seam
+ a column's right edge drags the column's width
+ A pane's last row is text like any other, never a handle.
+
A new file opens in a new COLUMN only if both panes would still get
100 columns of width. Otherwise it stacks in the one you are in.
diff --git a/test/snapshots/builtins.golden b/test/snapshots/builtins.golden
index 00f53a1b..f40d563e 100644
--- a/test/snapshots/builtins.golden
+++ b/test/snapshots/builtins.golden
@@ -27,7 +27,6 @@
|16:
== snap tutor-from-index grid=120x67 cursor=7,16
|10: 1 pardes builtins under SPC h Tutor
-|14: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|15: /Tutor Save Tty Collapse Del
|16: 1
|17: 2 PARDES TUTOR
diff --git a/test/snapshots/lookrange.golden b/test/snapshots/lookrange.golden
index 7d802b0b..f070a953 100644
--- a/test/snapshots/lookrange.golden
+++ b/test/snapshots/lookrange.golden
@@ -62,7 +62,6 @@
|12: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-9 #f5f7ee,#3c614a, 10-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
|14: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
== snap stale grid=150x31 cursor=10,16
-|6: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
== style stale grid=150x31
|10: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
|11: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
diff --git a/test/snapshots/lsprelpath.golden b/test/snapshots/lsprelpath.golden
index c8121b5a..4cc687ab 100644
--- a/test/snapshots/lsprelpath.golden
+++ b/test/snapshots/lsprelpath.golden
@@ -117,4 +117,3 @@
|33: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
|34: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
== snap clicked grid=100x35 cursor=16,16
-|12: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
diff --git a/test/snapshots/rsearch.golden b/test/snapshots/rsearch.golden
index efbd81c9..89c4f7bd 100644
--- a/test/snapshots/rsearch.golden
+++ b/test/snapshots/rsearch.golden
@@ -18,13 +18,11 @@
|15: 4 count_x again
|16: 5
== snap select grid=210x31 cursor=14,10
-|10: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|16: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Collapse Del LocationsConfig
|17: 1 code.txt:4:1-8
|18: 2 pick two words
|19: 3
== snap path-open grid=210x31 cursor=16,22
-|10: 4 pick two words
|19: /tmp/pardes-snap/rsearch/cwd/sub/dep.txt Save Tty Collapse Del
|20: 1 d1
|21: 2 d2
@@ -36,13 +34,8 @@
== snap step2 grid=210x31 cursor=13,9
== snap step3 grid=210x31 cursor=13,9
== snap selclick grid=210x31 cursor=14,10
-|11:
-|12:
-|13:
-|14:
-|15: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Collapse Del LocationsConfig
-== snap outside grid=210x31 cursor=14,10
-|10: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Collapse Del LocationsConfig
-|11: 1 code.txt:4:10-14
-|12: 2 pick two words
-|13: 3
+== snap outside grid=210x31 cursor=20,10
+|25: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Collapse Del LocationsConfig
+|26: 1 code.txt:4:10-14
+|27: 2 pick two words
+|28: 3
diff --git a/test/snapshots/rsearch.snap b/test/snapshots/rsearch.snap
index 0ce257bd..8c81db1d 100644
--- a/test/snapshots/rsearch.snap
+++ b/test/snapshots/rsearch.snap
@@ -74,13 +74,8 @@ press right 10 10
release right 10 10
stable 700 15000
snap step3
-# acme sized code.txt to its four lines, so line 4 is on its last row, and a
-# pane's last row is its resize handle: a press there would drag the seam, not
-# sweep text. Drag that handle down four rows first.
-press left 40 11
-drag left 40 15
-release left 40 15
-stable 700 15000
+# acme sized code.txt to its four lines, so line 4 is on its last row: a
+# pane's last row is text like any other, never a resize handle.
# A LEFT sweep over `pick two` (line 4, cols 8..15) and then a right CLICK
# INSIDE it: the click takes the whole selection — the search is for the
# two-word span (`4:1-8`), which the file-ish word expansion could never
diff --git a/test/snapshots/shrinktag.snap b/test/snapshots/shrinktag.snap
index f17c402f..31edad14 100644
--- a/test/snapshots/shrinktag.snap
+++ b/test/snapshots/shrinktag.snap
@@ -1,6 +1,8 @@
-# a pane can shrink to just its tagline: border-drag the handle to the tag row
-# (0 body rows), the gutter box still grabs a move, and dragging back down
-# restores the body intact (the hidden pane's pty/vt is never resized)
+# a pane can shrink to just its tagline: the pane below dragged by its grip up
+# to the tag row (0 body rows) -- a terminal has no rule between panes, so
+# the grip is the handle, as acme's button is -- the gutter box still grabs a
+# move, and dragging back down restores the body intact (the hidden pane's
+# pty/vt is never resized)
file w.txt x
start 31 100 -n 3
wait 8000 w.txt
@@ -16,16 +18,15 @@ key esc
settle 100
stable 400 5000
snap before
-# drag pane 0's bottom handle (its last row) up to its tag row: tag-only pane
-press left 20 17
-drag left 20 3
-release left 20 3
+# drag the lower pane's grip up under pane 0's tag row: tag-only pane
+press left 1 18
+drag left 1 3
+release left 1 3
motion 40 25
stable 500 8000
snap shrunk
-# the shrunk pane's single row is now the pair's resize handle, but the gutter
-# box must still win: grab it, preview a move into the right column, abort by
-# releasing over the pane itself
+# the shrunk pane's gutter box grabs a move: preview one into the right
+# column, abort by releasing over the pane itself
press left 1 3
drag left 70 9
stable 400 5000
@@ -33,17 +34,17 @@ snap move-preview
drag left 20 3
release left 20 3
stable 400 5000
-# re-enlarge: the tag row doubles as the drag handle, pull it back down
-press left 20 3
-drag left 20 17
-release left 20 17
+# re-enlarge: the lower pane's grip, now under pane 0's tag, pulled back down
+press left 1 4
+drag left 1 18
+release left 1 18
motion 40 25
stable 500 8000
snap restored
-# the bottom pane can shrink to ITS tag too: drag past the bottom, clamp holds
-press left 20 17
-drag left 20 31
-release left 20 31
+# the bottom pane can shrink to ITS tag too: its grip dragged past the bottom
+press left 1 18
+drag left 1 31
+release left 1 31
motion 40 25
stable 500 8000
snap bottom-shrunk
diff --git a/test/snapshots/splitparent.snap b/test/snapshots/splitparent.snap
index 3ec42b14..b9038af2 100644
--- a/test/snapshots/splitparent.snap
+++ b/test/snapshots/splitparent.snap
@@ -5,10 +5,11 @@
config Placement pardes
start 31 100 -n 3
stable 700 20000
-# shrink pane 0 (top-left) to just its tagline
-press left 20 17
-drag left 20 3
-release left 20 3
+# shrink pane 0 (top-left) to just its tagline: the pane below's grip dragged
+# up under it (a terminal has no rule between panes; the grip is the handle)
+press left 1 18
+drag left 1 3
+release left 1 3
motion 40 25
stable 500 8000
snap shrunk
diff --git a/test/snapshots/tagbottom.golden b/test/snapshots/tagbottom.golden
index a86bb8fb..d5f1f720 100644
--- a/test/snapshots/tagbottom.golden
+++ b/test/snapshots/tagbottom.golden
@@ -131,8 +131,8 @@
|27:
|30: /tmp/pardes-snap/tagbottom/cwd/bottom.txt Save Tty Collapse Del
== snap body-cursor grid=100x31 cursor=9,6
-== snap seam-noop grid=100x31 cursor=9,6
-== snap seam-dragged grid=100x31 cursor=9,6
+== snap seam-noop grid=100x31 cursor=12,16
+== snap seam-dragged grid=100x31 cursor=12,12
|11: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty Collapse Del bottom.txt
|12: 1 ZZONE
|13: 2 ZZTWO
diff --git a/test/snapshots/tagbottom.snap b/test/snapshots/tagbottom.snap
index a70ace1f..68b79fc7 100644
--- a/test/snapshots/tagbottom.snap
+++ b/test/snapshots/tagbottom.snap
@@ -67,19 +67,21 @@ press left 10 7
release left 10 7
stable 400 8000
snap body-cursor
-# The h-resize seam. With top taglines it is the upper pane's LAST row; here
-# that row is the upper pane's TAG, so the handle is the lower pane's FIRST row
-# (grid 16, click row 17). A no-drag click on it must leave both sizes alone.
+# No row of text is a resize handle: a click on the lower pane's FIRST row
+# (grid 16, click row 17), where the seam used to be, is a click in its text,
+# and both sizes stay.
press left 40 17
release left 40 17
motion 40 25
stable 500 8000
snap seam-noop
-# ...and the real drag, four rows up: the upper pane keeps 10 rows, the lower
-# grows to 19. Both taglines follow their own pane's bottom.
-press left 40 17
-drag left 40 13
-release left 40 13
+# A terminal has no rule between panes, so the grip resizes them, as acme's
+# button moves a window: the lower pane's, on its tag at the bottom, dragged up
+# to row 13. The upper pane keeps 10 rows, the lower grows to 19. Both
+# taglines follow their own pane's bottom.
+press left 1 31
+drag left 1 13
+release left 1 13
motion 40 25
stable 500 8000
snap seam-dragged
diff --git a/test/snapshots/windowops.golden b/test/snapshots/windowops.golden
index 965486d3..38450ac2 100644
--- a/test/snapshots/windowops.golden
+++ b/test/snapshots/windowops.golden
@@ -112,7 +112,7 @@
|9:
|10:
|11:
-|12: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+|12:
|13: /tmp/pardes-snap/windowops/cwd Tty+ba
|14: sh Save Mode Filter Collapse Del
|15: ls
@@ -132,7 +132,6 @@
|29:
|30:
== snap move-preview grid=100x31 cursor=4,17
-|12:
== snap moved grid=100x31 cursor=4,17
== snap altn grid=100x31 cursor=4,22
|18: /tmp/pardes-snap/windowops/cwd Tty+ba
diff --git a/test/snapshots/windowops.snap b/test/snapshots/windowops.snap
index 32d8c83b..8166f663 100644
--- a/test/snapshots/windowops.snap
+++ b/test/snapshots/windowops.snap
@@ -1,4 +1,4 @@
-# hover resize hints, border drags, move drag, Alt-n, Ctrl-w focus (routed through the Right builtin), Debug box
+# hover resize hints, border drags, grip resize, move drag, Alt-n, Ctrl-w focus (routed through the Right builtin), Debug box
file w.txt x
start 31 100 -n 3
wait 8000 w.txt
@@ -7,7 +7,7 @@ stable 700 20000
motion 50 10
stable 400 5000
snap hover-v
-# hover over the top-left pane's last row: horizontal dash hint
+# hover over the top-left pane's last row: no hint, a row of text is no handle
motion 20 16
stable 400 5000
snap hover-h
@@ -19,10 +19,11 @@ snap border-drag
release left 40 11
stable 500 8000
snap border-done
-# drag the horizontal border up 4 rows (pane 0's new last row)
-press left 20 17
-drag left 20 13
-release left 20 13
+# resize the left pair by the lower pane's grip, 4 rows up (a terminal has no
+# rule between panes; pane 0's last row is now 13)
+press left 1 18
+drag left 1 14
+release left 1 14
stable 500 8000
snap hborder-done
# move pane 1 (its gutter box) into the right column