From a1b682d0da53fbdc1d9e40b758ab61f744b3897d Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Mon, 10 Feb 2025 15:45:53 -0500 Subject: [PATCH] fix(terminal): properly lookup hyperlinks when cloning rows across pages Before this we were doing bad things with the memory, looking at `PageEntry`s for links not actually in the page we were reading the strings from. --- src/terminal/hyperlink.zig | 14 ++++++++++++-- src/terminal/page.zig | 6 +----- src/terminal/ref_counted_set.zig | 6 ++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/terminal/hyperlink.zig b/src/terminal/hyperlink.zig index 1ab3c5ea7..bb9e78ca6 100644 --- a/src/terminal/hyperlink.zig +++ b/src/terminal/hyperlink.zig @@ -194,14 +194,24 @@ pub const Set = RefCountedSet( Id, size.CellCountInt, struct { + /// The page which holds the strings for items in this set. page: ?*Page = null, + /// The page which holds the strings for items + /// looked up with, e.g., `add` or `lookup`, + /// if different from the destination page. + src_page: ?*const Page = null, + pub fn hash(self: *const @This(), link: PageEntry) u64 { - return link.hash(self.page.?.memory); + return link.hash((self.src_page orelse self.page.?).memory); } pub fn eql(self: *const @This(), a: PageEntry, b: PageEntry) bool { - return a.eql(self.page.?.memory, &b, self.page.?.memory); + return a.eql( + (self.src_page orelse self.page.?).memory, + &b, + self.page.?.memory, + ); } pub fn deleted(self: *const @This(), link: PageEntry) void { diff --git a/src/terminal/page.zig b/src/terminal/page.zig index ae14b8c01..30f6658aa 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -821,11 +821,7 @@ pub const Page = struct { if (self.hyperlink_set.lookupContext( self.memory, other_link.*, - - // `lookupContext` uses the context for hashing, and - // that doesn't write to the page, so this constCast - // is completely safe. - .{ .page = @constCast(other) }, + .{ .page = self, .src_page = @constCast(other) }, )) |i| { self.hyperlink_set.use(self.memory, i); break :dst_id i; diff --git a/src/terminal/ref_counted_set.zig b/src/terminal/ref_counted_set.zig index 1a58a4e5b..b674295dc 100644 --- a/src/terminal/ref_counted_set.zig +++ b/src/terminal/ref_counted_set.zig @@ -38,8 +38,14 @@ const fastmem = @import("../fastmem.zig"); /// /// `Context` /// A type containing methods to define behaviors. +/// /// - `fn hash(*Context, T) u64` - Return a hash for an item. +/// /// - `fn eql(*Context, T, T) bool` - Check two items for equality. +/// The first of the two items passed in is guaranteed to be from +/// a value passed in to an `add` or `lookup` function, the second +/// is guaranteed to be a value already resident in the set. +/// /// - `fn deleted(*Context, T) void` - [OPTIONAL] Deletion callback. /// If present, called whenever an item is finally deleted. /// Useful if the item has memory that needs to be freed.