╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │343 io: ?std.Io = null, │ │344 repos_dir: ?[]const u8 = null, │ │345 pending: std.ArrayList(Action) = .empty, // actions queued by widgets this frame │ │346 + // focus id -> the live TextInput, refreshed each frame by the views that own │ │347 + // inputs. web/wasm form handling looks widgets up here by focus id. │ │348 + text_inputs: std.AutoHashMapUnmanaged(usize, *wgt.TextInput(Widget)) = .empty, │ │349 nav_back: bool = false, // set by input (escape) to request the native TUI pop a page; see Nav│ │350 is_terminal: bool = false, // true on remote SSH and local TUI │ │351 quit_requested: bool = false, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │450 │ │451 var terminal = try term.Terminal.init(io, allocator); │ │452 defer terminal.deinit(io); │ │453 + │ │454 + // set term as active so it will be properly cooked │ │455 + // when a panic/segfault happens │ │456 + term.setActive(&terminal); │ │457 + defer term.setActive(null); │ │458 │ │459 var last_size = layout.Size{ .width = 0, .height = 0 };│ │460 var last_grid = try Grid.init(allocator, last_size); │ ╰────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │705 var root = Widget{ .background = try AnsiBackground.init(allocator, page_widget, demon_art, session) };│ │706 errdefer root.deinit(allocator); │ │707 │ │708 + // input-owning views build their TextInputs in init — so reset the │ │709 + // focus-id -> *TextInput map here │ │710 + session.text_inputs.clearRetainingCapacity(); │ │711 + │ │712 try root.build(allocator, .{ │ │713 .min_size = .{ .width = null, .height = 40 }, │ │714 .max_size = .{ .width = 80, .height = null }, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │787 }; │ │788 │ │789 pub const FlowBox = struct { │ │778 - focus: Focus, │ │790 + focus: *Focus, │ │791 grid: ?Grid, │ │792 text_boxes: std.ArrayList(wgt.TextBox(Widget)), │ │793 // backs the per-item strings the text boxes borrow: each box's `content`│ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │806 cell_height: usize = 3, │ │807 }; │ │808 │ │797 - pub fn init(allocator: std.mem.Allocator, options: Options) FlowBox { │ │809 + pub fn init(allocator: std.mem.Allocator, options: Options) !FlowBox {│ │810 return .{ │ │799 - .focus = Focus.init(.container), │ │811 + .focus = try Focus.create(allocator, .container), │ │812 .grid = null, │ │813 .text_boxes = .empty, │ │814 .arena = std.heap.ArenaAllocator.init(allocator), │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │818 } │ │819 │ │820 pub fn deinit(self: *FlowBox, allocator: std.mem.Allocator) void {│ │809 - self.focus.deinit(allocator); │ │821 + self.focus.destroy(allocator); │ │822 if (self.grid) |*grid| { │ │823 grid.deinit(); │ │824 self.grid = null; │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────╮ │930 } │ │931 │ │932 pub fn getFocus(self: *FlowBox) *Focus { │ │921 - return &self.focus; │ │933 + return self.focus; │ │934 } │ │935 │ │936 pub fn cellRect(self: FlowBox, index: usize) ?layout.IRect {│ ╰─────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │956 scroll: wgt.Scroll(Widget), │ │957 │ │958 pub fn init(allocator: std.mem.Allocator, options: FlowBox.Options) !Scroll { │ │947 - var layout_inner = FlowBox.init(allocator, options); │ │959 + var layout_inner = try FlowBox.init(allocator, options); │ │960 errdefer layout_inner.deinit(allocator); │ │949 - var scroll = try wgt.Scroll(Widget).init(allocator, .{ .flow_box = layout_inner }, .vert); │ │961 + var scroll = try wgt.Scroll(Widget).init(allocator, .{ .flow_box = layout_inner }, .{ .direction = .vert });│ │962 errdefer scroll.deinit(allocator); │ │963 return .{ .scroll = scroll }; │ │964 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │1062 // used inside Box(horiz) with a min_size so the box reserves space for the│ │1063 // children that follow, pushing them to the right. │ │1064 pub const Spacer = struct { │ │1053 - focus: Focus, │ │1065 + focus: *Focus, │ │1066 grid: ?Grid, │ │1067 │ │1056 - pub fn init() Spacer { │ │1068 + pub fn init(allocator: std.mem.Allocator) !Spacer { │ │1069 return .{ │ │1058 - .focus = Focus.init(.container), │ │1070 + .focus = try Focus.create(allocator, .container), │ │1071 .grid = null, │ │1072 }; │ │1073 } │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │1074 │ │1075 pub fn deinit(self: *Spacer, allocator: std.mem.Allocator) void {│ │1064 - self.focus.deinit(allocator); │ │1076 + self.focus.destroy(allocator); │ │1077 if (self.grid) |*grid| { │ │1078 grid.deinit(); │ │1079 self.grid = null; │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯