╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │634 // jump a fixed amount. right/Enter cross into the diff pane. Enter/clicks │ │635 // on the "next" row become navigation in the host before reaching here. │ │636 if (inp.rowDelta(key, @intCast(self.listBox().children.count()))) |delta| {│ │637 - return self.moveSelection(root_focus, delta); │ │637 + ui.moveRowFocus(self.listBox(), self.listScroll(), root_focus, delta); │ │638 + return; │ │639 } │ │640 switch (key) { │ │641 .enter => if (self.selectedCommitIndex() != null) │ ╰────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────╮ │656 .arrow_left => { │ │657 if (sc.x > 0) { │ │658 sc.x -= 1; │ │658 - self.clampDiffScroll(); │ │659 + ui.clampScroll(self.diffScroll());│ │660 } else try self.focusList(root_focus);│ │661 }, │ │662 .arrow_right => { │ ╰───────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────╮ │663 sc.x += 1; │ │663 - self.clampDiffScroll(); │ │664 + ui.clampScroll(self.diffScroll()); │ │665 }, │ │666 .arrow_up => try self.moveDiff(root_focus, -1), │ │667 .arrow_down => try self.moveDiff(root_focus, 1),│ ╰─────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │698 │ │699 const sc = self.diffScroll(); │ │700 sc.y += delta * 5; // magnify because it's a line count│ │700 - self.clampDiffScroll(); │ │701 + ui.clampScroll(self.diffScroll()); │ │702 if (in_range and self.hunkVisible(@intCast(target))) { │ │703 root_focus.setFocus(keys[@intCast(target)]); │ │704 } │ ╰────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │716 if (self.session.is_terminal) { │ │717 const sc = self.diffScroll(); │ │718 sc.y += delta * 5; // magnify because it's a line count│ │718 - self.clampDiffScroll(); │ │719 + ui.clampScroll(self.diffScroll()); │ │720 try self.focusVisible(root_focus, delta > 0); │ │721 } else { │ │722 const inner = self.diffInner(); │ ╰────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │737 if (self.session.is_terminal) { │ │738 const sc = self.diffScroll(); │ │739 sc.y = if (to_end) std.math.maxInt(isize) else 0; │ │739 - self.clampDiffScroll(); │ │740 + ui.clampScroll(self.diffScroll()); │ │741 } │ │742 root_focus.setFocus(if (to_end) keys[keys.len - 1] else keys[0]);│ │743 } │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │774 if (chosen) |id| root_focus.setFocus(id); │ │775 } │ │776 │ │776 - // keep the diff scroll within its content, using the last build's grids. the │ │777 - // scroll bar's reserved column/row isn't part of the content viewport, so │ │778 - // exclude it (as scrollToRect does) or the last column/row stays unreachable. │ │779 - fn clampDiffScroll(self: *View) void { │ │780 - const sc = self.diffScroll(); │ │781 - const vp = sc.grid orelse return; │ │782 - const content = sc.child.box.grid orelse return; │ │783 - const view_w = vp.size.width - sc.bar_w; │ │784 - const view_h = vp.size.height - sc.bar_h; │ │785 - const max_y: isize = if (content.size.height > view_h) @intCast(content.size.height - view_h) else 0;│ │786 - const max_x: isize = if (content.size.width > view_w) @intCast(content.size.width - view_w) else 0; │ │787 - sc.y = std.math.clamp(sc.y, 0, max_y); │ │788 - sc.x = std.math.clamp(sc.x, 0, max_x); │ │789 - } │ │790 - │ │777 // enter the diff pane. the host arrives here on right-arrow or Enter from the │ │778 // list. a diff with no rows can't be entered. setFocus handles the too-narrow │ │779 // case where the pane isn't laid out yet (it gets selected, then focused after │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │786 // return to the list. │ │787 fn focusList(self: *View, root_focus: *Focus) !void { │ │788 root_focus.setFocus(self.listScroll().getFocus().id); │ │803 - } │ │804 - │ │805 - fn moveSelection(self: *View, root_focus: *Focus, delta: isize) !void { │ │806 - const lb = self.listBox(); │ │807 - const keys = lb.children.keys(); │ │808 - if (keys.len == 0) return; │ │809 - const cur_id = lb.getFocus().child_id orelse return; │ │810 - const cur: isize = @intCast(lb.children.getIndex(cur_id) orelse return); │ │811 - const last: isize = @intCast(keys.len - 1); │ │812 - const next: usize = @intCast(std.math.clamp(cur + delta, 0, last)); │ │813 - if (next == @as(usize, @intCast(cur))) return; │ │814 - root_focus.setFocus(keys[next]); │ │815 - if (lb.children.values()[next].rect) |rect| self.listScroll().scrollToRect(rect);│ │789 } │ │790 │ │791 pub fn clearGrid(self: *View) void { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │633 // directory (or "..") row are turned into navigation by the host │ │634 // (crossPageLink) before reaching here. │ │635 if (inp.rowDelta(key, @intCast(self.listBox().children.count()))) |delta| {│ │636 - return self.moveSelection(root_focus, delta); │ │636 + ui.moveRowFocus(self.listBox(), self.listScroll(), root_focus, delta); │ │637 + return; │ │638 } │ │639 switch (key) { │ │640 .enter, .arrow_right => try self.focusDetail(root_focus), │ ╰────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────╮ │661 if (on_content) { │ │662 if (sc.x > 0) { │ │663 sc.x -= 1; │ │663 - self.clampDetailScroll(); │ │664 + ui.clampScroll(self.detailScroll());│ │665 } else try self.focusList(root_focus); │ │666 } else if (!self.moveNav(root_focus, -1)) { │ │667 try self.focusList(root_focus); │ ╰─────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯