diff --git a/src/terminal/Selection.zig b/src/terminal/Selection.zig index 8aacc9ba9..17f6e462f 100644 --- a/src/terminal/Selection.zig +++ b/src/terminal/Selection.zig @@ -326,6 +326,7 @@ pub fn containedRowCached( br: point.Coordinate, p: point.Coordinate, ) ?Selection { + _ = s; if (p.y < tl.y or p.y > br.y) return null; // Rectangle case: we can return early as the x range will always be the @@ -333,12 +334,12 @@ pub fn containedRowCached( if (self.rectangle) return init( start: { var copy: Pin = pin; - copy.x = tl.x; + copy.x = @min(tl.x, copy.node.cols() - 1); break :start copy; }, end: { var copy: Pin = pin; - copy.x = br.x; + copy.x = @min(br.x, copy.node.cols() - 1); break :end copy; }, true, @@ -355,7 +356,7 @@ pub fn containedRowCached( tl_pin, end: { var copy: Pin = pin; - copy.x = s.pages.cols - 1; + copy.x = copy.node.cols() - 1; break :end copy; }, false, @@ -387,7 +388,7 @@ pub fn containedRowCached( }, end: { var copy: Pin = pin; - copy.x = s.pages.cols - 1; + copy.x = copy.node.cols() - 1; break :end copy; }, false, @@ -1602,3 +1603,46 @@ test "Selection: containedRow" { ).?); } } + +test "Selection: containedRow clamps mixed-width pages" { + const testing = std.testing; + var s = try Screen.init(testing.allocator, .{ + .cols = 4, + .rows = 3, + .max_scrollback = 0, + }); + defer s.deinit(); + + const first = s.pages.pages.first.?; + try s.pages.split(.{ .node = first, .y = 2 }); + try s.pages.split(.{ .node = first, .y = 1 }); + const middle = first.next.?; + const last = middle.next.?; + middle.page().size.cols = 2; + + const linear = Selection.init( + .{ .node = first, .x = 1 }, + .{ .node = last, .x = 1 }, + false, + ); + const linear_row = linear.containedRow( + &s, + .{ .node = middle }, + ).?; + _ = linear_row.end().rowAndCell(); + try testing.expect((Pin{ .node = middle }).eql(linear_row.start())); + try testing.expect((Pin{ .node = middle, .x = 1 }).eql(linear_row.end())); + + const rectangle = Selection.init( + .{ .node = first, .x = 1 }, + .{ .node = last, .x = 3 }, + true, + ); + const rectangle_row = rectangle.containedRow( + &s, + .{ .node = middle }, + ).?; + _ = rectangle_row.end().rowAndCell(); + try testing.expect((Pin{ .node = middle, .x = 1 }).eql(rectangle_row.start())); + try testing.expect((Pin{ .node = middle, .x = 1 }).eql(rectangle_row.end())); +}