mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-12-19 08:35:46 +01:00
terminal: RenderState linkCells needs to use Page y not Viewport y
Fixes #9957 Our `Page.getRowAndCell` uses a _page-relative_ x/y coordinate system and we were passing in viewport x/y. This has the possibility to leading to all sorts of bugs, including the crash found in #9957 but also simply reading the wrong cell even in single-page scenarios.
This commit is contained in:
@@ -817,11 +817,12 @@ pub const RenderState = struct {
|
||||
const row_cells = row_slice.items(.cells);
|
||||
|
||||
// Grab our link ID
|
||||
const link_page: *page.Page = &row_pins[viewport_point.y].node.data;
|
||||
const link_pin: PageList.Pin = row_pins[viewport_point.y];
|
||||
const link_page: *page.Page = &link_pin.node.data;
|
||||
const link = link: {
|
||||
const rac = link_page.getRowAndCell(
|
||||
viewport_point.x,
|
||||
viewport_point.y,
|
||||
link_pin.y,
|
||||
);
|
||||
|
||||
// The likely scenario is that our mouse isn't even over a link.
|
||||
@@ -848,7 +849,7 @@ pub const RenderState = struct {
|
||||
|
||||
const other_page: *page.Page = &pin.node.data;
|
||||
const other = link: {
|
||||
const rac = other_page.getRowAndCell(x, y);
|
||||
const rac = other_page.getRowAndCell(x, pin.y);
|
||||
const link_id = other_page.lookupHyperlink(rac.cell) orelse continue;
|
||||
break :link other_page.hyperlink_set.get(
|
||||
other_page.memory,
|
||||
@@ -1317,6 +1318,48 @@ test "string" {
|
||||
try testing.expectEqualStrings(expected, result);
|
||||
}
|
||||
|
||||
test "linkCells with scrollback spanning pages" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
const viewport_rows: size.CellCountInt = 10;
|
||||
const tail_rows: size.CellCountInt = 5;
|
||||
|
||||
var t = try Terminal.init(alloc, .{
|
||||
.cols = page.std_capacity.cols,
|
||||
.rows = viewport_rows,
|
||||
.max_scrollback = 10_000,
|
||||
});
|
||||
defer t.deinit(alloc);
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
|
||||
const pages = &t.screens.active.pages;
|
||||
const first_page_cap = pages.pages.first.?.data.capacity.rows;
|
||||
|
||||
// Fill first page
|
||||
for (0..first_page_cap - 1) |_| try s.nextSlice("\r\n");
|
||||
|
||||
// Create second page with hyperlink
|
||||
try s.nextSlice("\r\n");
|
||||
try s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\");
|
||||
for (0..(tail_rows - 1)) |_| try s.nextSlice("\r\n");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
try state.update(alloc, &t);
|
||||
|
||||
const expected_viewport_y: usize = viewport_rows - tail_rows;
|
||||
// BUG: This crashes without the fix
|
||||
var cells = try state.linkCells(alloc, .{
|
||||
.x = 0,
|
||||
.y = expected_viewport_y,
|
||||
});
|
||||
defer cells.deinit(alloc);
|
||||
try testing.expectEqual(@as(usize, 4), cells.count());
|
||||
}
|
||||
|
||||
test "dirty row resets highlights" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
Reference in New Issue
Block a user