╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │1946 focus: *Focus, │ │1947 grid: ?Grid, │ │1948 text_boxes: std.ArrayList(wgt.TextBox(Widget)), │ │1949 - // backs the per-item strings the text boxes borrow: each box's `content` │ │1950 - // and, for link items, its `.custom` focus kind (e.g. "a:/user/foo"). reset│ │1949 + // backs each link item's `.custom` focus kind (e.g. "a:/user/foo"). reset │ │1950 // wholesale on each setItems so there's no per-string ownership to track. │ │1951 arena: std.heap.ArenaAllocator, │ │1952 // column count from the last build — FlowBox.Scroll.input uses it so arrow │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1988 // the web renderer turns into an anchor. │ │1989 pub const Item = struct { text: []const u8, link: []const u8 = "" }; │ │1990 │ │1992 - // both the item text and the link are copied into the arena, so the caller's │ │1993 - // slices needn't outlive this call. │ │1991 + // the text box copies the item text; links are copied into the arena, so the │ │1992 + // caller's slices needn't outlive this call. │ │1993 pub fn setItems(self: *FlowBox, allocator: std.mem.Allocator, items: []const Item) !void {│ │1994 for (self.text_boxes.items) |*tb| tb.deinit(allocator); │ │1995 self.text_boxes.clearAndFree(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │1996 │ │1998 - // the old text boxes (and their borrowed content/links) are gone now, so│ │1999 - // the arena that backed those strings can be reclaimed. │ │1997 + // the old text boxes and their borrowed links are gone now, so the link │ │1998 + // arena can be reclaimed. │ │1999 _ = self.arena.reset(.retain_capacity); │ │2000 const aa = self.arena.allocator(); │ │2001 │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2003 self.focus.child_id = null; │ │2004 │ │2005 for (items) |item| { │ │2007 - const line = try aa.dupe(u8, item.text); │ │2008 - │ │2009 - var text_box = try wgt.TextBox(Widget).init(allocator, line, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word }); │ │2006 + var text_box = try wgt.TextBox(Widget).init(allocator, item.text, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word });│ │2007 errdefer text_box.deinit(allocator); │ │2008 text_box.getFocus().focusable = true; │ │2009 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │2222 // last build's item rects (content space), for vertical navigation and│ │2223 // scroll-into-view. │ │2224 rects: std.ArrayList(layout.IRect), │ │2228 - // backs the per-item strings the text boxes borrow. │ │2225 + // backs each link item's `.custom` focus kind. │ │2226 arena: std.heap.ArenaAllocator, │ │2227 │ │2228 pub const Item = struct { text: []const u8, link: []const u8 = "" }; │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2249 self.arena.deinit(); │ │2250 } │ │2251 │ │2255 - // both the item text and the link are copied into the arena, so the caller's │ │2256 - // slices needn't outlive this call. │ │2252 + // the text box copies the item text; links are copied into the arena, so the │ │2253 + // caller's slices needn't outlive this call. │ │2254 pub fn setItems(self: *TagFlow, allocator: std.mem.Allocator, items: []const Item) !void {│ │2255 for (self.text_boxes.items) |*tb| tb.deinit(allocator); │ │2256 self.text_boxes.clearAndFree(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2262 self.focus.child_id = null; │ │2263 │ │2264 for (items) |item| { │ │2268 - const line = try aa.dupe(u8, item.text); │ │2269 - │ │2270 - var text_box = try wgt.TextBox(Widget).init(allocator, line, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); │ │2265 + var text_box = try wgt.TextBox(Widget).init(allocator, item.text, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none });│ │2266 errdefer text_box.deinit(allocator); │ │2267 text_box.getFocus().focusable = true; │ │2268 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Comment.zig│ ╰───────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │288 try box.children.put(allocator, item.getFocus().id, .{ .widget = .{ .repo_comment = item }, .rect = null, .min_size = null }); │ │289 } │ │290 │ │291 -pub fn appendCount(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), count: usize, singular: []const u8, plural: []const u8, arena: std.mem.Allocator) !void {│ │292 - const text = try std.fmt.allocPrint(arena, "{d} {s}", .{ count, if (count == 1) singular else plural }); │ │291 +pub fn appendCount(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), count: usize, singular: []const u8, plural: []const u8) !void { │ │292 + var text_buf: [64]u8 = undefined; │ │293 + const text = try std.fmt.bufPrint(&text_buf, "{d} {s}", .{ count, if (count == 1) singular else plural }); │ │294 var count_box = try wgt.TextBox(ui.Widget).init(allocator, text, .{ .border_style = .hidden, .wrap_kind = .none }); │ │295 errdefer count_box.deinit(allocator); │ │296 try box.children.put(allocator, count_box.getFocus().id, .{ .widget = .{ .text_box = count_box }, .rect = null, .min_size = null }); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────────╮ │src/ui/Repo/Discussions.zig│ ╰───────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │285 { │ │286 const route = ui.RoutablePage.repoDiscussionsRoute(data.identity, data.tag, "") orelse return error.RouteTooLong;│ │287 const link = try std.fmt.allocPrint(aa, "ai:{s}", .{try route.toUrl(session.page_arena)}); │ │288 - const label = try std.fmt.allocPrint(aa, "recent ({d})", .{data.recent.count}); │ │288 + var label_buf: [64]u8 = undefined; │ │289 + const label = try std.fmt.bufPrint(&label_buf, "recent ({d})", .{data.recent.count}); │ │290 try addTab(allocator, &box, &tab_ids, label, link); │ │291 } │ │292 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Events.zig│ ╰──────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │578 inline for ([_]ui.RoutablePage.EventsView{ .active, .removed }, 0..) |view, i| { │ │579 const route = ui.RoutablePage.repoEventsRoute(data.identity, view, null, "") orelse return error.RouteTooLong; │ │580 const count = data.window(view).count; │ │581 - const label = try std.fmt.allocPrint(session.page_arena.allocator(), "{s} ({d})", .{ @tagName(view), count }); │ │581 + var label_buf: [64]u8 = undefined; │ │582 + const label = try std.fmt.bufPrint(&label_buf, "{s} ({d})", .{ @tagName(view), count }); │ │583 var tab = try wgt.TextBox(ui.Widget).init(allocator, label, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .none });│ │584 errdefer tab.deinit(allocator); │ │585 tab.getFocus().focusable = true; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯