╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │387 // the commit whose diff the pane currently shows (index into data.commits).│ │388 diffed_index: ?usize, │ │389 │ │390 + // the sub-header leads the box where there is one; local mode has none │ │391 const header_index: usize = 0; │ │391 - const content_index: usize = 1; │ │392 // indices within the content box (the horizontal split). │ │393 const list_index: usize = 0; │ │394 const diff_index: usize = 1; │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │399 var outer = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .vert }); │ │400 errdefer outer.deinit(allocator); │ │401 │ │402 - // the search box and the clone url at the top. │ │403 - { │ │402 + // the search box and the clone url at the top. local mode has neither. │ │403 + if (session.data.host_kind == .server) { │ │404 var header_view = try ui.widget.SearchHeader.init(allocator, session, data.location, " search ", "search", data.search, data.search_available); │ │405 errdefer header_view.deinit(allocator); │ │406 try outer.children.put(allocator, header_view.getFocus().id, .{ .widget = .{ .search_header = header_view }, .rect = null, .min_size = .{ .width = null, .height = 3 } });│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │456 │ │457 // focus lives in the split, except that search results start in the │ │458 // search box so the query can be refined right away. │ │459 - outer.getFocus().child_id = outer.children.keys()[if (data.search != null) header_index else content_index]; │ │459 + outer.getFocus().child_id = outer.children.keys()[if (data.search != null) header_index else outer.children.count() - 1];│ │460 │ │461 return .{ │ │462 .box = outer, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │515 │ │516 pub fn deinit(self: *View, allocator: std.mem.Allocator) void {│ │517 self.box.deinit(allocator); │ │518 + } │ │519 + │ │520 + // the split is last, after the sub-header where there is one │ │521 + fn contentIndex(self: *View) usize { │ │522 + return self.box.children.count() - 1; │ │523 } │ │524 │ │525 fn contentBox(self: *View) *wgt.Box(ui.Widget) { │ ╰────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │521 - return &self.box.children.values()[content_index].widget.box; │ │526 + return &self.box.children.values()[self.contentIndex()].widget.box; │ │527 } │ │528 │ │524 - fn header(self: *View) *ui.widget.SearchHeader { │ │525 - return &self.box.children.values()[header_index].widget.search_header;│ │529 + fn header(self: *View) ?*ui.widget.SearchHeader { │ │530 + switch (self.box.children.values()[header_index].widget) { │ │531 + .search_header => |*header_view| return header_view, │ │532 + else => return null, │ │533 + } │ │534 } │ │535 │ │536 fn headerActive(self: *View) bool { │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │529 - return self.box.getFocus().child_id == self.header().getFocus().id;│ │537 + const header_view = self.header() orelse return false; │ │538 + return self.box.getFocus().child_id == header_view.getFocus().id; │ │539 } │ │540 │ │541 fn listScroll(self: *View) *wgt.Scroll(ui.Widget) { │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │704 // scrolling crosses the sub header boundary the same way arrows do│ │705 const direction = inp.vertDirection(key); │ │706 if (self.headerActive()) { │ │707 + // active means there is one │ │708 + const header_view = self.header() orelse unreachable; │ │709 if (direction == .down) { │ │710 root_focus.setFocus(self.contentBox().getFocus().id); │ │711 return; │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │712 } │ │702 - if (key == .enter) if (try self.header().submittedText(allocator)) |text| {│ │713 + if (key == .enter) if (try header_view.submittedText(allocator)) |text| { │ │714 defer allocator.free(text); │ │715 return self.submit(text); │ │716 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │706 - return self.header().input(allocator, key, root_focus); │ │717 + return header_view.input(allocator, key, root_focus); │ │718 } │ │708 - if (direction == .up and self.contentAtTop() and self.header().focusHeader(root_focus)) return;│ │719 + if (direction == .up and self.contentAtTop() and self.focusHeader(root_focus)) return; │ │720 if (self.diffActive()) { │ │721 if (key == .arrow_left and self.diffScroll().x == 0) { │ │722 self.focusList(root_focus); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │795 │ │796 // only the header's own row sits directly below the repository header. │ │797 pub fn atTop(self: *View) bool { │ │787 - return self.headerActive() or (!self.header().hasFocusable() and self.contentAtTop()); │ │798 + const focusable = if (self.header()) |header_view| header_view.hasFocusable() else false;│ │799 + return self.headerActive() or (!focusable and self.contentAtTop()); │ │800 } │ │801 │ │802 pub fn focusHeader(self: *View, root_focus: *Focus) bool { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯