diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-16 23:28:05 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-16 23:29:28 +0300 |
| commit | 4a3302d19a2baa3a33e910e0088c24e780905b90 (patch) | |
| tree | dcaf76fae1c82102d933c9225b17ca7ac5d3a847 /vendor/libghostty-vt/src/terminal/Selection.zig | |
| parent | 550e9f8cc085f428429f5cf2da0bb2dba897e8b8 (diff) | |
chore: update vendored libghostty-vt
refs #276
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/Selection.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/terminal/Selection.zig | 92 |
1 files changed, 81 insertions, 11 deletions
diff --git a/vendor/libghostty-vt/src/terminal/Selection.zig b/vendor/libghostty-vt/src/terminal/Selection.zig index 5258210c..be6854e5 100644 --- a/vendor/libghostty-vt/src/terminal/Selection.zig +++ b/vendor/libghostty-vt/src/terminal/Selection.zig @@ -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; }, }; @@ -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, @@ -432,7 +433,7 @@ pub fn adjust( var current = end_pin.*; while (current.down(1)) |next| : (current = next) { const rac = next.rowAndCell(); - const cells = next.node.data.getCells(rac.row); + const cells = next.node.page().getCells(rac.row); if (page.Cell.hasTextAny(cells)) { end_pin.* = next; break; @@ -494,7 +495,7 @@ pub fn adjust( ); while (it.next()) |next| { const rac = next.rowAndCell(); - const cells = next.node.data.getCells(rac.row); + const cells = next.node.page().getCells(rac.row); if (page.Cell.hasTextAny(cells)) { end_pin.* = next; end_pin.x = @intCast(cells.len - 1); @@ -505,7 +506,7 @@ pub fn adjust( .beginning_of_line => end_pin.x = 0, - .end_of_line => end_pin.x = end_pin.node.data.size.cols - 1, + .end_of_line => end_pin.x = end_pin.node.cols() - 1, } } @@ -1054,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; @@ -1602,3 +1629,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())); +} |
