╭ changed ───────────╮ │src/ui/Repo/Refs.zig│ ╰────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────╮ │37 pub fn init( │ │38 arena: *std.heap.ArenaAllocator, │ │39 session: *ui.Session, │ │40 - event_id: *const [evt.event_id_size]u8,│ │40 + source_maybe: ?ui.RepoSource, │ │41 identity: []const u8, │ │42 kind: ui.RoutablePage.RefKind, │ │43 after: usize, │ ╰───────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │63 // no filesystem (wasm) or nowhere to look: empty lists. the wasm path never│ │64 // calls init anyway — it rebuilds from the serialized snapshot. │ │65 const io = session.io orelse return empty; │ │66 - const repos_dir = session.repos_dir orelse return empty; │ │67 - │ │68 - // the repo's working copy lives at <repos_dir>/<hex event id>. │ │69 - const hex = std.fmt.bytesToHex(event_id.*, .lower); │ │70 - const repo_path = try std.fs.path.join(aa, &.{ repos_dir, &hex }); │ │66 + const source = source_maybe orelse return empty; │ │67 │ │68 // open with the arena's backing allocator (transient; the ref names are │ │69 // duped into the page arena so they outlive the repo handle). │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │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; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯