╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │335 // the list row whose contents the detail pane currently shows. │ │336 shown_index: ?usize, │ │337 │ │338 + // the sub-header leads the box where there is one; local mode has none│ │339 const header_index: usize = 0; │ │339 - const content_index: usize = 1; │ │340 // indices within the content box (the horizontal split). │ │341 const list_index: usize = 0; │ │342 const detail_index: usize = 1; │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │352 var outer = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .vert }); │ │353 errdefer outer.deinit(allocator); │ │354 │ │355 - // the search box and the clone url at the top. │ │356 - { │ │355 + // the search box and the clone url at the top. local mode has neither. │ │356 + if (session.data.host_kind == .server) { │ │357 var header_view = try ui.widget.SearchHeader.init(allocator, session, data.location, " find file ", "find", data.find, data.find_available); │ │358 errdefer header_view.deinit(allocator); │ │359 try outer.children.put(allocator, header_view.getFocus().id, .{ .widget = .{ .search_header = header_view }, .rect = null, .min_size = .{ .width = null, .height = 3 } });│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │471 │ │472 // focus lives in the split, except that search results start in the │ │473 // search box so the term can be refined right away. │ │474 - outer.getFocus().child_id = outer.children.keys()[if (data.find != null) header_index else content_index]; │ │474 + outer.getFocus().child_id = outer.children.keys()[if (data.find != null) header_index else outer.children.count() - 1];│ │475 return .{ .box = outer, .data = data, .session = session, .shown_index = null }; │ │476 } │ │477 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │498 │ │499 pub fn deinit(self: *View, allocator: std.mem.Allocator) void {│ │500 self.box.deinit(allocator); │ │501 + } │ │502 + │ │503 + // the split is last, after the sub-header where there is one │ │504 + fn contentIndex(self: *View) usize { │ │505 + return self.box.children.count() - 1; │ │506 } │ │507 │ │508 fn contentBox(self: *View) *wgt.Box(ui.Widget) { │ ╰────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │504 - return &self.box.children.values()[content_index].widget.box; │ │509 + return &self.box.children.values()[self.contentIndex()].widget.box; │ │510 } │ │511 │ │507 - fn header(self: *View) *ui.widget.SearchHeader { │ │508 - return &self.box.children.values()[header_index].widget.search_header;│ │512 + fn header(self: *View) ?*ui.widget.SearchHeader { │ │513 + switch (self.box.children.values()[header_index].widget) { │ │514 + .search_header => |*header_view| return header_view, │ │515 + else => return null, │ │516 + } │ │517 } │ │518 │ │519 fn headerActive(self: *View) bool { │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │512 - return self.box.getFocus().child_id == self.header().getFocus().id;│ │520 + const header_view = self.header() orelse return false; │ │521 + return self.box.getFocus().child_id == header_view.getFocus().id; │ │522 } │ │523 │ │524 fn listScroll(self: *View) *wgt.Scroll(ui.Widget) { │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │710 // scrolling crosses the sub header boundary the same way arrows do│ │711 const direction = inp.vertDirection(key); │ │712 if (self.headerActive()) { │ │713 + // active means there is one │ │714 + const header_view = self.header() orelse unreachable; │ │715 if (direction == .down) { │ │716 root_focus.setFocus(self.contentBox().getFocus().id); │ │717 return; │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │718 } │ │708 - if (key == .enter) if (try self.header().submittedText(allocator)) |term| {│ │719 + if (key == .enter) if (try header_view.submittedText(allocator)) |term| { │ │720 defer allocator.free(term); │ │721 return self.submit(term); │ │722 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │712 - return self.header().input(allocator, key, root_focus); │ │723 + return header_view.input(allocator, key, root_focus); │ │724 } │ │714 - if (direction == .up and self.contentAtTop() and self.header().focusHeader(root_focus)) return;│ │725 + if (direction == .up and self.contentAtTop() and self.focusHeader(root_focus)) return; │ │726 if (self.detailActive()) { │ │727 try self.detailInput(key, root_focus); │ │728 } else { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │899 │ │900 // only the header's own row sits directly below the repository header. │ │901 pub fn atTop(self: *View) bool { │ │891 - return self.headerActive() or (!self.header().hasFocusable() and self.contentAtTop()); │ │902 + const focusable = if (self.header()) |header_view| header_view.hasFocusable() else false;│ │903 + return self.headerActive() or (!focusable and self.contentAtTop()); │ │904 } │ │905 │ │906 pub fn focusHeader(self: *View, root_focus: *Focus) bool { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯