From 5329d05005f02c742264955b6c8ee2925292f4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Wed, 11 Mar 2026 15:27:12 +0900 Subject: [PATCH] interactive: optimize getTextContent single-chunk path Avoids an unnecessary double allocation and maintains a zero-copy fast path for single-chunk text extraction. --- src/browser/interactive.zig | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/browser/interactive.zig b/src/browser/interactive.zig index ed8af8d0..2d03db51 100644 --- a/src/browser/interactive.zig +++ b/src/browser/interactive.zig @@ -331,7 +331,8 @@ fn getAccessibleName(el: *Element, arena: Allocator) !?[]const u8 { fn getTextContent(node: *Node, arena: Allocator) !?[]const u8 { var tw: TreeWalker.FullExcludeSelf = .init(node, .{}); - var chunks: std.ArrayList([]const u8) = .empty; + var arr: std.ArrayList(u8) = .empty; + var single_chunk: ?[]const u8 = null; while (tw.next()) |child| { // Skip text inside script/style elements. @@ -348,16 +349,27 @@ fn getTextContent(node: *Node, arena: Allocator) !?[]const u8 { if (cdata.is(Node.CData.Text)) |text| { const content = std.mem.trim(u8, text.getWholeText(), &std.ascii.whitespace); if (content.len > 0) { - try chunks.append(arena, content); + if (single_chunk == null and arr.items.len == 0) { + single_chunk = content; + } else { + if (single_chunk) |sc| { + try arr.appendSlice(arena, sc); + try arr.append(arena, ' '); + single_chunk = null; + } + try arr.appendSlice(arena, content); + try arr.append(arena, ' '); + } } } } } - if (chunks.items.len == 0) return null; - if (chunks.items.len == 1) return chunks.items[0]; + if (single_chunk) |sc| return sc; + if (arr.items.len == 0) return null; - return try std.mem.join(arena, " ", chunks.items); + // strip out trailing space + return arr.items[0 .. arr.items.len - 1]; } fn isDisabled(el: *Element) bool { if (el.getAttributeSafe(comptime .wrap("disabled")) != null) return true;