From 9085cb5bfdd0b78ff3a62c0c71fc231dd7b5052a Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sun, 9 Aug 2026 10:41:33 -0300 Subject: replace ArrayLists with bounded storage --- src/term_pane.zig | 55 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'src/term_pane.zig') diff --git a/src/term_pane.zig b/src/term_pane.zig index 47123ceb..5e50e15d 100644 --- a/src/term_pane.zig +++ b/src/term_pane.zig @@ -35,14 +35,18 @@ pub fn shellRows(p: *Pardes, pane: *Pane) ![]const []const u8 { const arena = p.scratch.allocator(); const full = try pane.vt.screens.active.dumpStringAlloc(arena, .{ .screen = .{} }); var pit = pane.vt.screens.active.pages.rowIterator(.right_down, .{ .screen = .{} }, null); - var ls: std.ArrayList([]const u8) = .empty; - var it = std.mem.splitAny(u8, full, "\n"); + // split yields one more item than delimiters; the extra final slot is the + // cursor row retained below. + const rows = try arena.alloc([]const u8, std.mem.count(u8, full, "\n") + 2); + var n: usize = 0; + var it = std.mem.splitScalar(u8, full, '\n'); while (it.next()) |raw| { const is_prompt = if (pit.next()) |pin| pin.rowAndCell().row.semantic_prompt != .none else false; - try ls.append(arena, if (is_prompt) "" else raw); + rows[n] = if (is_prompt) "" else raw; + n += 1; } - try ls.append(arena, ""); - return ls.items; + rows[n] = ""; + return rows; } /// The body a terminal renders: the viewport's shell rows (prompt rows blanked @@ -51,21 +55,35 @@ pub fn shellRows(p: *Pardes, pane: *Pane) ![]const []const u8 { pub fn bodyText(arena: std.mem.Allocator, pane: *Pane) ![]const u8 { const raw = try pane.vt.plainString(arena); var prompts = pane.vt.screens.active.pages.rowIterator(.right_down, .{ .viewport = .{} }, null); - var vp: std.ArrayList([]const u8) = .empty; + const vp = try arena.alloc([]const u8, std.mem.count(u8, raw, "\n") + 1); var lines = std.mem.splitScalar(u8, raw, '\n'); + var n: usize = 0; while (lines.next()) |ln| { const is_prompt = if (pane.mode != .tty) if (prompts.next()) |pin| pin.rowAndCell().row.semantic_prompt != .none else false else false; - try vp.append(arena, if (is_prompt) "" else ln); + vp[n] = if (is_prompt) "" else ln; + n += 1; } + std.debug.assert(n == vp.len); + + const len = fillBody(null, pane, vp); + const out = try arena.alloc(u8, len); + const filled = fillBody(out, pane, vp); + std.debug.assert(filled == out.len); + return out; +} + +/// Run the terminal body row walk. A null destination counts bytes; a slice +/// fills the exact allocation made from that count. +fn fillBody(dst: ?[]u8, pane: *Pane, viewport: []const []const u8) usize { const goff: i32 = @intCast(pane.vt.screens.active.pages.scrollbar().offset); const off = pane.scroll(); var g: i32 = pane.gridRow(off); // the buffer can start above the viewport: drop the lines scrolled past var skip: usize = if (pane.ovl) |o| @intCast(@max(0, off - pane.surfRow(o.row))) else 0; - var out: std.ArrayList(u8) = .empty; + var written: usize = 0; var n: usize = 0; while (n < pane.rows) { if (pane.mode != .tty) if (pane.ovl) |o| if (g == o.row) { @@ -74,21 +92,32 @@ pub fn bodyText(arena: std.mem.Allocator, pane: *Pane) ![]const u8 { while (bit.next()) |ln| : (k += 1) { if (k < skip) continue; if (n >= pane.rows) break; - if (n > 0) try out.append(arena, '\n'); - try out.appendSlice(arena, ln); + if (n > 0) { + if (dst) |out| out[written] = '\n'; + written += 1; + } + if (dst) |out| @memcpy(out[written..][0..ln.len], ln); + written += ln.len; n += 1; } skip = 0; g += o.rows; continue; }; - if (n > 0) try out.append(arena, '\n'); + if (n > 0) { + if (dst) |out| out[written] = '\n'; + written += 1; + } const vi = g - goff; - if (vi >= 0 and @as(usize, @intCast(vi)) < vp.items.len) try out.appendSlice(arena, vp.items[@intCast(vi)]); + if (vi >= 0 and @as(usize, @intCast(vi)) < viewport.len) { + const line = viewport[@intCast(vi)]; + if (dst) |out| @memcpy(out[written..][0..line.len], line); + written += line.len; + } n += 1; g += 1; } - return out.items; + return written; } /// tty colors: recolor each body cell from the emulator's own style so shell -- cgit v1.3