terminal: clamp mirrored selection corners

Rectangle orientation swaps endpoint columns when a selection is mirrored.
During incomplete reflow, copying a column from a wider page onto the
narrower corner page created an invalid pin that panicked when resolved.

Clamp every swapped column to the page that owns the oriented corner.
Top-left and bottom-right calculations now always return valid pins.
This commit is contained in:
Mitchell Hashimoto
2026-07-09 21:05:51 -07:00
parent 6071606577
commit b6f34be44f

View File

@@ -155,12 +155,12 @@ pub fn topLeft(self: Selection, s: *const Screen) Pin {
.reverse => self.end(),
.mirrored_forward => pin: {
var p = self.start();
p.x = self.end().x;
p.x = @min(self.end().x, p.node.cols() - 1);
break :pin p;
},
.mirrored_reverse => pin: {
var p = self.end();
p.x = self.start().x;
p.x = @min(self.start().x, p.node.cols() - 1);
break :pin p;
},
};
@@ -173,12 +173,12 @@ pub fn bottomRight(self: Selection, s: *const Screen) Pin {
.reverse => self.start(),
.mirrored_forward => pin: {
var p = self.end();
p.x = self.start().x;
p.x = @min(self.start().x, p.node.cols() - 1);
break :pin p;
},
.mirrored_reverse => pin: {
var p = self.start();
p.x = self.end().x;
p.x = @min(self.end().x, p.node.cols() - 1);
break :pin p;
},
};
@@ -1055,6 +1055,32 @@ test "Selection: order, standard" {
}
}
test "Selection: rectangle corners clamp across mixed-width pages" {
const testing = std.testing;
var s = try Screen.init(testing.allocator, .{
.cols = 4,
.rows = 2,
.max_scrollback = 0,
});
defer s.deinit();
const first = s.pages.pages.first.?;
try s.pages.split(.{ .node = first, .y = 1 });
const second = first.next.?;
second.page().size.cols = 2;
const sel = Selection.init(
.{ .node = first, .x = 3 },
.{ .node = second, .x = 1 },
true,
);
try testing.expectEqual(.mirrored_forward, sel.order(&s));
const bottom_right = sel.bottomRight(&s);
_ = bottom_right.rowAndCell();
try testing.expect((Pin{ .node = second, .x = 1 }).eql(bottom_right));
}
test "Selection: order, rectangle" {
const testing = std.testing;
const alloc = testing.allocator;