╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │600 - fn descriptionInput(self: *View, key: Key, root_focus: *Focus) !void { │ │601 - const sc = self.detailScroll(); │ │742 + fn descriptionInput(self: *View, index: usize, key: Key, root_focus: *Focus) !void {│ │743 + const sc = self.detailScroll(index); │ │744 switch (key) { │ │603 - .arrow_left => return self.focusList(root_focus), │ │745 + .arrow_left => return self.focusList(index, root_focus), │ │746 // once the scroll can't move further, cross into the tags (or the │ │747 // header tabs when the issue has none). │ │748 .arrow_up => { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │750 sc.y -= 1; │ │751 sc.clampToContent(); │ │752 if (sc.y == before) { │ │611 - if (self.tagFlow() != null) try self.focusTags(root_focus) else self.focusHeader(root_focus); │ │753 + if (self.tagFlow(index) != null) try self.focusTags(index, root_focus) else self.focusHeader(root_focus);│ │754 } │ │755 return; │ │756 }, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │770 │ │771 // arrow keys move the tag selection; at the flow's edges focus crosses to │ │772 // the neighboring widgets. │ │631 - fn tagsInput(self: *View, key: Key, root_focus: *Focus) !void { │ │632 - const tf = self.tagFlow() orelse return; │ │773 + fn tagsInput(self: *View, index: usize, key: Key, root_focus: *Focus) !void {│ │774 + const tf = self.tagFlow(index) orelse return; │ │775 const cid = tf.focus.child_id orelse return; │ │776 const cur = tf.indexOfFocusId(cid) orelse return; │ │777 const count = tf.text_boxes.items.len; │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │636 - const sc = self.detailScroll(); │ │778 + const sc = self.detailScroll(index); │ │779 switch (key) { │ │638 - .arrow_left => if (cur > 0) self.focusTag(tf, root_focus, cur - 1) else try self.focusList(root_focus), │ │639 - .arrow_right => if (cur + 1 < count) self.focusTag(tf, root_focus, cur + 1), │ │640 - .arrow_up => if (tf.rowStep(cur, false)) |i| self.focusTag(tf, root_focus, i) else self.focusHeader(root_focus), │ │641 - .arrow_down => if (tf.rowStep(cur, true)) |i| self.focusTag(tf, root_focus, i) else try self.focusDescription(root_focus), │ │642 - .home => self.focusTag(tf, root_focus, 0), │ │643 - .end => self.focusTag(tf, root_focus, count - 1), │ │780 + .arrow_left => if (cur > 0) self.focusTag(index, tf, root_focus, cur - 1) else try self.focusList(index, root_focus), │ │781 + .arrow_right => if (cur + 1 < count) self.focusTag(index, tf, root_focus, cur + 1), │ │782 + .arrow_up => if (tf.rowStep(cur, false)) |i| self.focusTag(index, tf, root_focus, i) else self.focusHeader(root_focus), │ │783 + .arrow_down => if (tf.rowStep(cur, true)) |i| self.focusTag(index, tf, root_focus, i) else try self.focusDescription(index, root_focus),│ │784 + .home => self.focusTag(index, tf, root_focus, 0), │ │785 + .end => self.focusTag(index, tf, root_focus, count - 1), │ │786 .mouse => |mouse| switch (mouse.action) { │ │787 .scroll => |dir| { │ │788 sc.y += if (dir == .up) @as(isize, -1) else 1; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │796 │ │797 const tags_child_index: usize = 0; │ │798 │ │657 - fn tagFlow(self: *View) ?*ui.TagFlow { │ │658 - const inner = self.detailInner(); │ │799 + fn tagFlow(self: *View, index: usize) ?*ui.TagFlow { │ │800 + const inner = self.detailInner(index); │ │801 if (inner.children.count() == 0) return null; │ │802 return switch (inner.children.values()[tags_child_index].widget) {│ │803 .tag_flow => |*tf| tf, │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │805 }; │ │806 } │ │807 │ │666 - fn tagsFocused(self: *View) bool { │ │667 - const inner = self.detailInner(); │ │808 + fn tagsFocused(self: *View, index: usize) bool { │ │809 + const inner = self.detailInner(index); │ │810 const cid = inner.getFocus().child_id orelse return false; │ │669 - return inner.children.getIndex(cid) == tags_child_index and self.tagFlow() != null; │ │811 + return inner.children.getIndex(cid) == tags_child_index and self.tagFlow(index) != null; │ │812 } │ │813 │ │672 - fn focusTag(self: *View, tf: *ui.TagFlow, root_focus: *Focus, index: usize) void { │ │673 - root_focus.setFocus(tf.text_boxes.items[index].getFocus().id); │ │814 + fn focusTag(self: *View, index: usize, tf: *ui.TagFlow, root_focus: *Focus, item: usize) void {│ │815 + root_focus.setFocus(tf.text_boxes.items[item].getFocus().id); │ │816 // keep the tag visible on the terminal: its rect offset by the flow's │ │817 // position in the pane. │ │676 - if (self.session.is_terminal and index < tf.rects.items.len) { │ │677 - if (self.detailInner().children.values()[tags_child_index].rect) |flow_rect| { │ │678 - var rect = tf.rects.items[index]; │ │818 + if (self.session.is_terminal and item < tf.rects.items.len) { │ │819 + if (self.detailInner(index).children.values()[tags_child_index].rect) |flow_rect| { │ │820 + var rect = tf.rects.items[item]; │ │821 rect.x += flow_rect.x; │ │822 rect.y += flow_rect.y; │ │681 - self.detailScroll().scrollToRect(rect); │ │823 + self.detailScroll(index).scrollToRect(rect); │ │824 } │ │825 } │ │826 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │827 │ │686 - fn focusTags(self: *View, root_focus: *Focus) !void { │ │687 - const tf = self.tagFlow() orelse return; │ │828 + fn focusTags(self: *View, index: usize, root_focus: *Focus) !void { │ │829 + const tf = self.tagFlow(index) orelse return; │ │830 if (tf.text_boxes.items.len == 0) return; │ │831 const cid = tf.focus.child_id orelse tf.text_boxes.items[0].getFocus().id;│ │690 - const index = tf.indexOfFocusId(cid) orelse 0; │ │691 - self.focusTag(tf, root_focus, index); │ │832 + const item = tf.indexOfFocusId(cid) orelse 0; │ │833 + self.focusTag(index, tf, root_focus, item); │ │834 } │ │835 │ │694 - fn focusDescription(self: *View, root_focus: *Focus) !void { │ │695 - if (self.description_id) |id| root_focus.setFocus(id); │ │836 + fn focusDescription(self: *View, index: usize, root_focus: *Focus) !void { │ │837 + if (self.description_id[index]) |id| root_focus.setFocus(id); │ │838 } │ │839 │ │840 // enter the detail pane. an empty pane (no issues) can't be entered. │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │699 - fn focusDetail(self: *View, root_focus: *Focus) !void { │ │700 - if (self.detailInner().children.count() == 0) return; │ │701 - root_focus.setFocus(self.detailOuter().getFocus().id); │ │841 + fn focusDetail(self: *View, index: usize, root_focus: *Focus) !void {│ │842 + if (self.detailInner(index).children.count() == 0) return; │ │843 + root_focus.setFocus(self.detailOuter(index).getFocus().id); │ │844 } │ │845 │ │846 // return to the list. │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │705 - fn focusList(self: *View, root_focus: *Focus) !void { │ │706 - root_focus.setFocus(self.listScroll().getFocus().id); │ │847 + fn focusList(self: *View, index: usize, root_focus: *Focus) !void {│ │848 + root_focus.setFocus(self.listScroll(index).getFocus().id); │ │849 } │ │850 │ │709 - // cross to the header tabs above the split. │ │851 + // cross to the header tabs above the stack. │ │852 fn focusHeader(self: *View, root_focus: *Focus) void { │ │853 root_focus.setFocus(self.box.children.keys()[header_index]); │ │854 } │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │874 }; │ │875 │ │876 // the "a:" navigation link for the issues page filtered to the url-encoded │ │735 -// `tag` and rooted at issue `id` within `identity` ("owner/name"). │ │877 +// `tag` and rooted at issue `id` within `identity` ("owner/name"). a rooted │ │878 +// url derives its view from the issue's status; the bare list is the open view. │ │879 fn issuesLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, tag: []const u8, id: []const u8) ![]const u8 {│ │737 - const route = ui.RoutablePage.repoIssuesRoute(identity, tag, id) orelse return error.RouteTooLong; │ │880 + const route = ui.RoutablePage.repoIssuesRoute(identity, .open, tag, id) orelse return error.RouteTooLong; │ │881 const url = try route.urlAlloc(page_arena); │ │882 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{url}); │ │883 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯