terminal: renderstate stores pins

pull/9662/head
Mitchell Hashimoto 2025-11-19 14:39:41 -10:00
parent b8363a8417
commit 81142265aa
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
2 changed files with 18 additions and 7 deletions

View File

@ -1061,9 +1061,13 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
state: *renderer.State, state: *renderer.State,
cursor_blink_visible: bool, cursor_blink_visible: bool,
) !void { ) !void {
// Create an arena for all our temporary allocations while rebuilding
var arena = ArenaAllocator.init(self.alloc);
defer arena.deinit();
const arena_alloc = arena.allocator();
// Data we extract out of the critical area. // Data we extract out of the critical area.
const Critical = struct { const Critical = struct {
mouse: renderer.State.Mouse,
preedit: ?renderer.State.Preedit, preedit: ?renderer.State.Preedit,
cursor_style: ?renderer.CursorStyle, cursor_style: ?renderer.CursorStyle,
scrollbar: terminal.Scrollbar, scrollbar: terminal.Scrollbar,
@ -1111,9 +1115,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
const preedit: ?renderer.State.Preedit = preedit: { const preedit: ?renderer.State.Preedit = preedit: {
if (cursor_style == null) break :preedit null; if (cursor_style == null) break :preedit null;
const p = state.preedit orelse break :preedit null; const p = state.preedit orelse break :preedit null;
break :preedit try p.clone(self.alloc); break :preedit try p.clone(arena_alloc);
}; };
errdefer if (preedit) |p| p.deinit(self.alloc);
// If we have Kitty graphics data, we enter a SLOW SLOW SLOW path. // If we have Kitty graphics data, we enter a SLOW SLOW SLOW path.
// We only do this if the Kitty image state is dirty meaning only if // We only do this if the Kitty image state is dirty meaning only if
@ -1129,15 +1132,11 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
} }
break :critical .{ break :critical .{
.mouse = state.mouse,
.preedit = preedit, .preedit = preedit,
.cursor_style = cursor_style, .cursor_style = cursor_style,
.scrollbar = scrollbar, .scrollbar = scrollbar,
}; };
}; };
defer {
if (critical.preedit) |p| p.deinit(self.alloc);
}
// Build our GPU cells // Build our GPU cells
try self.rebuildCells( try self.rebuildCells(

View File

@ -149,6 +149,10 @@ pub const RenderState = struct {
/// change often. /// change often.
arena: ArenaAllocator.State, arena: ArenaAllocator.State,
/// The page pin. This is not safe to read unless you can guarantee
/// the terminal state hasn't changed since the last `update` call.
pin: Pin,
/// Raw row data. /// Raw row data.
raw: page.Row, raw: page.Row,
@ -299,6 +303,7 @@ pub const RenderState = struct {
for (old_len..self.rows) |y| { for (old_len..self.rows) |y| {
row_data.set(y, .{ row_data.set(y, .{
.arena = .{}, .arena = .{},
.pin = undefined,
.raw = undefined, .raw = undefined,
.cells = .empty, .cells = .empty,
.dirty = true, .dirty = true,
@ -322,6 +327,7 @@ pub const RenderState = struct {
// Break down our row data // Break down our row data
const row_data = self.row_data.slice(); const row_data = self.row_data.slice();
const row_arenas = row_data.items(.arena); const row_arenas = row_data.items(.arena);
const row_pins = row_data.items(.pin);
const row_raws = row_data.items(.raw); const row_raws = row_data.items(.raw);
const row_cells = row_data.items(.cells); const row_cells = row_data.items(.cells);
const row_dirties = row_data.items(.dirty); const row_dirties = row_data.items(.dirty);
@ -357,6 +363,12 @@ pub const RenderState = struct {
}; };
} }
// Store our pin. We have to store these even if we're not dirty
// because dirty is only a renderer optimization. It doesn't
// apply to memory movement. This will let us remap any cell
// pins back to an exact entry in our RenderState.
row_pins[y] = row_pin;
// Get all our cells in the page. // Get all our cells in the page.
const p: *page.Page = &row_pin.node.data; const p: *page.Page = &row_pin.node.data;
const page_rac = row_pin.rowAndCell(); const page_rac = row_pin.rowAndCell();