╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────╮ │src/ui/Repo/Refs.zig│ ╰────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │70 const gpa = arena.child_allocator; │ │75 - var any_repo = rp.AnyRepo(.xit, .{}).open(io, gpa, .{ .path = repo_path }) catch return empty; │ │76 - defer any_repo.deinit(io, gpa); │ │71 + const branches, const tags = switch (source.repo_kind) { │ │72 + inline else => |repo_kind| blk: { │ │73 + var any_repo = rp.AnyRepo(repo_kind, .{}).open(io, gpa, .{ .path = source.path }) catch return empty; │ │74 + defer any_repo.deinit(io, gpa); │ │75 + │ │76 + switch (any_repo) { │ │77 + inline else => |*repo| { │ │78 + // xit seeks each iterator straight to its window; the git │ │79 + // backend can't seek, so it starts at the beginning and │ │80 + // collectWindow discards the entries before the window. │ │81 + const can_seek = repo_kind == .xit; │ │82 │ │78 - const branches, const tags = switch (any_repo) { │ │79 - inline else => |*repo| blk: { │ │80 - var branch_iter = repo.listBranches(io, gpa, .{ .index = branches_after }) catch return empty; │ │81 - defer branch_iter.deinit(io); │ │82 - const b = try collectWindow(io, aa, &branch_iter, branches_after); │ │83 + var branch_iter = repo.listBranches(io, gpa, if (can_seek) .{ .index = branches_after } else .beginning) catch return empty;│ │84 + defer branch_iter.deinit(io); │ │85 + const b = try collectWindow(io, aa, &branch_iter, branches_after, if (can_seek) 0 else branches_after); │ │86 │ │84 - var tag_iter = repo.listTags(io, gpa, .{ .index = tags_after }) catch return empty; │ │85 - defer tag_iter.deinit(io); │ │86 - const t = try collectWindow(io, aa, &tag_iter, tags_after); │ │87 - break :blk .{ b, t }; │ │87 + var tag_iter = repo.listTags(io, gpa, if (can_seek) .{ .index = tags_after } else .beginning) catch return empty; │ │88 + defer tag_iter.deinit(io); │ │89 + const t = try collectWindow(io, aa, &tag_iter, tags_after, if (can_seek) 0 else tags_after); │ │90 + break :blk .{ b, t }; │ │91 + }, │ │92 + } │ │93 }, │ │94 }; │ │95 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │106 }; │ │107 } │ │108 │ │104 -// window a ref iterator without materializing the whole list │ │105 -fn collectWindow(io: std.Io, aa: std.mem.Allocator, iter: anytype, after: usize) !Window { │ │109 +// window a ref iterator without materializing the whole list. `skip` entries │ │110 +// are discarded first, for backends whose iterators can't seek. │ │111 +fn collectWindow(io: std.Io, aa: std.mem.Allocator, iter: anytype, after: usize, skip: usize) !Window {│ │112 + for (0..skip) |_| { │ │113 + if (try iter.next(io) == null) break; │ │114 + } │ │115 var names = try std.ArrayListUnmanaged([]const u8).initCapacity(aa, page_size); │ │116 while (names.items.len < page_size) { │ │117 const ref = try iter.next(io) orelse break; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯