From 251ec0c9f32b4926331ce2ad13a5934e923fb13f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 5 Jul 2024 18:25:34 -0700 Subject: [PATCH] terminal: on print, adjust page size if we need to grow for hyperlinks --- src/terminal/Screen.zig | 29 +++++++++++++++++++++++++++++ src/terminal/Terminal.zig | 39 +++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 593fcc86e..37bff05a4 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -1524,6 +1524,35 @@ pub fn endHyperlink(self: *Screen) void { self.cursor.hyperlink = null; } +/// Set the current hyperlink state on the current cell. +pub fn cursorSetHyperlink(self: *Screen) !void { + assert(self.cursor.hyperlink_id != 0); + + var page = &self.cursor.page_pin.page.data; + if (page.setHyperlink( + self.cursor.page_row, + self.cursor.page_cell, + self.cursor.hyperlink_id, + )) { + // Success! + return; + } else |err| switch (err) { + // hyperlink_map is out of space, realloc the page to be larger + error.OutOfMemory => { + _ = try self.pages.adjustCapacity( + self.cursor.page_pin.page, + .{ .hyperlink_bytes = page.capacity.hyperlink_bytes * 2 }, + ); + + // Reload cursor since our cursor page has changed. + self.cursorReload(); + + // Retry + return try self.cursorSetHyperlink(); + }, + } +} + /// Set the selection to the given selection. If this is a tracked selection /// then the screen will take overnship of the selection. If this is untracked /// then the screen will convert it to tracked internally. This will automatically diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index cc4ec9d22..af903a71d 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -601,27 +601,6 @@ fn printCell( ); } - // We check for an active hyperlink first because setHyperlink - // handles clearing the old hyperlink and an optimization if we're - // overwriting the same hyperlink. - if (self.screen.cursor.hyperlink_id > 0) { - // If we have a hyperlink configured, apply it to this cell - var page = &self.screen.cursor.page_pin.page.data; - page.setHyperlink( - self.screen.cursor.page_row, - cell, - self.screen.cursor.hyperlink_id, - ) catch |err| { - // TODO: an error can only happen if our page is out of space - // so realloc the page here. - log.err("failed to set hyperlink, ignoring err={}", .{err}); - }; - } else if (cell.hyperlink) { - // If the previous cell had a hyperlink then we need to clear it. - var page = &self.screen.cursor.page_pin.page.data; - page.clearHyperlink(self.screen.cursor.page_row, cell); - } - // We don't need to update the style refs unless the // cell's new style will be different after writing. const style_changed = cell.style_id != self.screen.cursor.style_id; @@ -635,6 +614,9 @@ fn printCell( } } + // Keep track if we had a hyperlink so we can unset it. + const had_hyperlink = cell.hyperlink; + // Write cell.* = .{ .content_tag = .codepoint, @@ -642,7 +624,6 @@ fn printCell( .style_id = self.screen.cursor.style_id, .wide = wide, .protected = self.screen.cursor.protected, - .hyperlink = self.screen.cursor.hyperlink_id > 0, }; if (style_changed) { @@ -654,6 +635,20 @@ fn printCell( self.screen.cursor.page_row.styled = true; } } + + // We check for an active hyperlink first because setHyperlink + // handles clearing the old hyperlink and an optimization if we're + // overwriting the same hyperlink. + if (self.screen.cursor.hyperlink_id > 0) { + self.screen.cursorSetHyperlink() catch |err| { + log.warn("error reallocating for more hyperlink space, ignoring hyperlink err={}", .{err}); + assert(!cell.hyperlink); + }; + } else if (had_hyperlink) { + // If the previous cell had a hyperlink then we need to clear it. + var page = &self.screen.cursor.page_pin.page.data; + page.clearHyperlink(self.screen.cursor.page_row, cell); + } } fn printWrap(self: *Terminal) !void {