╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1717 .arrow_left => if (cur > button_in_row_index) root_focus.setFocus(row.children.keys()[cur - 1]) else try self.focusList(index, root_focus),│ │1718 .arrow_right => if (cur + 1 < row.children.count()) root_focus.setFocus(row.children.keys()[cur + 1]), │ │1719 .arrow_up => self.focusHeader(root_focus), │ │1720 - .arrow_down => self.focusTitle(index, root_focus), │ │1720 + .arrow_down => { │ │1721 + self.focusDetailEdge(index, root_focus, false); │ │1722 + self.detailScroll(index).y = 0; │ │1723 + }, │ │1724 .enter => if (on_status) try self.toggleIssueStatus(allocator, index), │ │1725 .mouse => |mouse| if (self.statusButton(index)) |button| { │ │1726 if (inp.leftClickOn(root_focus, button.getFocus().id, mouse)) try self.toggleIssueStatus(allocator, index); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1733 switch (key) { │ │1734 .arrow_left => try self.focusList(index, root_focus), │ │1735 .arrow_up => self.focusToolRow(index, root_focus), │ │1733 - .arrow_down => if (self.authorPresent(index)) self.focusAuthor(index, root_focus) else try self.focusDescription(index, root_focus),│ │1736 + .arrow_down => _ = self.moveDetailVertical(index, root_focus, true), │ │1737 else => {}, │ │1738 } │ │1739 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1743 fn authorInput(self: *View, index: usize, key: Key, root_focus: *Focus) !void { │ │1744 switch (key) { │ │1745 .arrow_left => try self.focusList(index, root_focus), │ │1743 - .arrow_up => self.focusTitle(index, root_focus), │ │1744 - .arrow_down => if (self.tagFlow(index) != null) try self.focusTags(index, root_focus) else try self.focusDescription(index, root_focus),│ │1746 + .arrow_up => _ = self.moveDetailVertical(index, root_focus, false), │ │1747 + .arrow_down => _ = self.moveDetailVertical(index, root_focus, true), │ │1748 else => {}, │ │1749 } │ │1750 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │1753 const sc = self.detailScroll(index); │ │1754 switch (key) { │ │1755 .arrow_left => return self.focusList(index, root_focus), │ │1753 - // once the scroll can't move further, cross into the tags (or the │ │1754 - // open/close button when the issue has none). │ │1756 + // the terminal moves through the description one line at a time; │ │1757 + // the web lets focus changes drive its native scroll. │ │1758 .arrow_up => { │ │1759 + if (!self.session.is_terminal) { │ │1760 + _ = self.moveDetailVertical(index, root_focus, false); │ │1761 + return; │ │1762 + } │ │1763 + if (self.focusAdjacentVisible(index, root_focus, false)) return;│ │1764 const before = sc.y; │ │1765 sc.y -= 1; │ │1766 sc.clampToContent(); │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │1759 - if (sc.y == before) { │ │1760 - if (self.tagFlow(index) != null) │ │1761 - try self.focusTags(index, root_focus) │ │1762 - else if (self.authorPresent(index)) │ │1763 - self.focusAuthor(index, root_focus) │ │1764 - else │ │1765 - self.focusTitle(index, root_focus); │ │1766 - } │ │1767 + if (sc.y == before) _ = self.moveDetailVertical(index, root_focus, false);│ │1768 return; │ │1769 }, │ │1770 .arrow_down => { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │1770 - if (self.moveCommentVertical(index, root_focus, true)) return; │ │1771 + if (!self.session.is_terminal) { │ │1772 + _ = self.moveDetailVertical(index, root_focus, true); │ │1773 + return; │ │1774 + } │ │1775 + if (self.focusAdjacentVisible(index, root_focus, true)) return;│ │1776 const before = sc.y; │ │1777 sc.y += 1; │ │1778 sc.clampToContent(); │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │1774 - if (sc.y == before) _ = self.moveCommentVertical(index, root_focus, true);│ │1779 + if (sc.y == before) _ = self.moveDetailVertical(index, root_focus, true); │ │1780 return; │ │1781 }, │ │1782 else => return, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1788 switch (key) { │ │1789 .arrow_left => if (!self.moveCommentHorizontal(index, root_focus, false)) return self.focusList(index, root_focus),│ │1790 .arrow_right => _ = self.moveCommentHorizontal(index, root_focus, true), │ │1786 - .arrow_up => _ = self.moveCommentVertical(index, root_focus, false), │ │1787 - .arrow_down => _ = self.moveCommentVertical(index, root_focus, true), │ │1791 + .arrow_up => _ = self.moveDetailVertical(index, root_focus, false), │ │1792 + .arrow_down => _ = self.moveDetailVertical(index, root_focus, true), │ │1793 else => return, │ │1794 } │ │1795 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │1796 │ │1797 // page the detail scroll, then focus the first or last visible widget. │ │1798 fn pageDetail(self: *View, index: usize, root_focus: *Focus, delta: isize) void {│ │1799 + if (!self.session.is_terminal) return; │ │1800 const sc = self.detailScroll(index); │ │1801 sc.y += delta; │ │1802 sc.clampToContent(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │1803 self.focusVisible(index, root_focus, delta > 0); │ │1804 } │ │1805 │ │1800 - // jump to the detail's top or bottom and focus that edge's visible widget. │ │1806 + // jump to the detail's first or last focusable widget. the terminal pins │ │1807 + // its synthetic scroll too; the browser scrolls to the new focus itself. │ │1808 fn jumpDetail(self: *View, index: usize, root_focus: *Focus, to_end: bool) void { │ │1802 - const sc = self.detailScroll(index); │ │1803 - sc.y = if (to_end) std.math.maxInt(isize) else 0; │ │1804 - sc.clampToContent(); │ │1805 - self.focusVisible(index, root_focus, to_end); │ │1809 + if (self.session.is_terminal) { │ │1810 + const sc = self.detailScroll(index); │ │1811 + sc.y = if (to_end) std.math.maxInt(isize) else 0; │ │1812 + sc.clampToContent(); │ │1813 + self.focusVisible(index, root_focus, to_end); │ │1814 + } else { │ │1815 + self.focusDetailEdge(index, root_focus, to_end); │ │1816 + } │ │1817 + } │ │1818 + │ │1819 + fn focusDetailEdge(self: *View, index: usize, root_focus: *Focus, last: bool) void {│ │1820 + const focus = self.detailInner(index).getFocus(); │ │1821 + var chosen: ?usize = null; │ │1822 + for (focus.children.keys(), focus.children.values()) |id, child| { │ │1823 + if (!child.focus.focusable) continue; │ │1824 + chosen = id; │ │1825 + if (!last) break; │ │1826 + } │ │1827 + if (chosen) |id| root_focus.setFocus(id); │ │1828 } │ │1829 │ │1830 fn detailRectVisible(self: *View, index: usize, rect: layout.IRect) bool { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯