╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────╮ │3 const ui = @import("../../ui.zig");│ │4 const xit = @import("xit"); │ │5 const rp = xit.repo; │ │6 -const Diff = @import("Diff.zig"); │ │6 const Undo = @import("Undo.zig"); │ │7 const obj = xit.object; │ │8 const mrg = xit.merge; │ ╰──────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │433 // the detail pane: a frame around a scroll of its rows │ │434 { │ │435 var detail_outer = blk: { │ │437 - var detail_scroll = try Diff.View.initEmpty(allocator, session); │ │436 + var detail_scroll = blk2: { │ │437 + var rows = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .vert }); │ │438 + errdefer rows.deinit(allocator); │ │439 + break :blk2 try wgt.Scroll(ui.Widget).init(allocator, .{ .box = rows }, .{ .direction = .vert, .web_native = !session.is_terminal, .fill = true });│ │440 + }; │ │441 errdefer detail_scroll.deinit(allocator); │ │442 var frame = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = .hidden, .direction = .vert }); │ │443 errdefer frame.deinit(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │446 // one), letting focus recovery descend into the pane after │ │447 // it's laid out beside a too-narrow list. │ │448 frame.getFocus().child_id = detail_scroll.getFocus().id; │ │446 - try frame.children.put(allocator, detail_scroll.getFocus().id, .{ .widget = .{ .diff_view = detail_scroll }, .rect = null, .min_size = null });│ │449 + try frame.children.put(allocator, detail_scroll.getFocus().id, .{ .widget = .{ .scroll = detail_scroll }, .rect = null, .min_size = null }); │ │450 break :blk frame; │ │451 }; │ │452 errdefer detail_outer.deinit(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │540 } │ │541 │ │542 fn detailScroll(self: *View) *wgt.Scroll(ui.Widget) { │ │540 - return &self.detailOuter().children.values()[0].widget.diff_view.scroll;│ │543 + return &self.detailOuter().children.values()[0].widget.scroll; │ │544 } │ │545 │ │546 fn detailInner(self: *View) *wgt.Box(ui.Widget) { │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │593 else │ │594 detail_min_width; │ │595 self.contentBox().children.values()[detail_index].min_size = .{ .width = detail_width, .height = null };│ │593 - │ │594 - // the message is the pane's only wrapping row, and wrapping needs a │ │595 - // bounded width, which the pane's scroll doesn't grant (it scrolls │ │596 - // horizontally too). cap it to the pane, leaving room for the border │ │597 - // and the scrollbar column. re-capped each build so it tracks resizes. │ │598 - for (self.detailInner().children.values()) |*child| switch (child.widget) { │ │599 - .text_box => |text_box| if (text_box.options.wrap_kind == .word) { │ │600 - child.max_size = .{ .width = detail_width -| 3, .height = null }; │ │601 - }, │ │602 - else => {}, │ │603 - }; │ │596 │ │597 // the web bounds the layout to the browser viewport like the terminal; │ │598 // each Scroll's web-native mode hands its full content to a real │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │711 } │ │712 if (direction == .up and self.contentAtTop() and self.focusHeader(root_focus)) return; │ │713 if (self.detailActive()) { │ │722 - const detail_view = &self.detailOuter().children.values()[0].widget.diff_view; │ │723 - if (key == .arrow_left and self.detailScroll().x == 0) { │ │724 - if (!detail_view.moveInRow(root_focus, false)) self.focusList(root_focus); │ │725 - } else { │ │726 - try detail_view.input(allocator, key, root_focus); │ │714 + const inner = self.detailInner(); │ │715 + if (inp.rowDelta(key, @intCast(inner.children.count()))) |delta| { │ │716 + ui.widget.moveRowFocus(inner, self.detailScroll(), root_focus, delta); │ │717 + } else if (key == .arrow_left) { │ │718 + if (!ui.widget.moveInSelectedRow(inner, root_focus, false)) self.focusList(root_focus);│ │719 + } else if (key == .arrow_right) { │ │720 + _ = ui.widget.moveInSelectedRow(inner, root_focus, true); │ │721 } │ │722 } else { │ │723 try self.listInput(key, root_focus); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯