╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │291 .commits = &.{}, │ │292 .next_start = null, │ │293 }; │ │294 +} │ │295 + │ │296 +// a log without commits, which shows the empty message │ │297 +fn isEmpty(self: *const Self) bool { │ │298 + return self.commits.len == 0; │ │299 } │ │300 │ │301 // the commit message, trimmed and read into `aa`, plus whether its preview was│ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │399 errdefer header_view.deinit(allocator); │ │400 // a row taller than the header, leaving a blank line beneath it │ │401 try outer.children.put(allocator, header_view.getFocus().id, .{ .widget = .{ .search_header = header_view }, .rect = null, .min_size = .{ .width = null, .height = 4 } });│ │402 + } │ │403 + │ │404 + // an empty list shows the empty message in place of the split │ │405 + if (data.isEmpty()) { │ │406 + var center = try ui.widget.initEmpty(allocator); │ │407 + errdefer center.deinit(allocator); │ │408 + try outer.children.put(allocator, center.getFocus().id, .{ .widget = .{ .center = center }, .rect = null, .min_size = null }); │ │409 + // with nothing below to focus, focus rests on the sub-header │ │410 + outer.getFocus().child_id = outer.children.keys()[header_index]; │ │411 + return .{ .box = outer, .data = data, .session = session }; │ │412 } │ │413 │ │414 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .horiz }); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │566 │ │567 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void {│ │568 self.clearGrid(); │ │554 - if (self.data.no_commits) return self.box.build(allocator, constraint, root_focus); │ │569 + if (self.data.no_commits or self.data.isEmpty()) return self.box.build(allocator, constraint, root_focus); │ │570 │ │571 // whether the detail pane fits beside the list, which decides the list │ │572 // cap below and whether the detail carries a way back to the list │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────╮ │715 // active means there is one │ │716 const header_view = self.header() orelse unreachable; │ │717 if (direction == .down) { │ │703 - root_focus.setFocus(self.contentBox().getFocus().id); │ │718 + // the empty message has nothing to focus │ │719 + if (!self.data.isEmpty()) root_focus.setFocus(self.contentBox().getFocus().id);│ │720 return; │ │721 } │ │722 if (key == .enter) if (try header_view.submittedText(allocator)) |text| { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │822 │ │823 // only the header's own row sits directly below the repository header. │ │824 pub fn atTop(self: *View) bool { │ │809 - if (self.data.no_commits) return true; │ │825 + if (self.data.no_commits or self.data.isEmpty()) return true; │ │826 const focusable = if (self.header()) |header_view| header_view.hasFocusable() else false;│ │827 return self.headerActive() or (!focusable and self.contentAtTop()); │ │828 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯