╭ changed ───────────╮ │src/ui/Repo/Refs.zig│ ╰────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │33 const Self = @This(); │ │34 │ │35 const Window = struct { names: []const []const u8, next_after: ?usize }; │ │36 + │ │37 +// empty columns, for the wasm / no-repo paths. │ │38 +pub fn emptyResult(arena: *std.heap.ArenaAllocator, identity: []const u8, kind: ui.RoutablePage.RefKind, after: usize) !Self {│ │39 + return .{ │ │40 + .identity = try arena.allocator().dupe(u8, identity), │ │41 + .kind = kind, │ │42 + .after = after, │ │43 + .branches = &.{}, │ │44 + .tags = &.{}, │ │45 + .branches_next_after = null, │ │46 + .tags_next_after = null, │ │47 + .branches_label = try ui.SubTitle.init(arena, "branches"), │ │48 + .tags_label = try ui.SubTitle.init(arena, "tags"), │ │49 + }; │ │50 +} │ │51 │ │52 +// read one window of each column from an opened repo. the ref names are duped │ │53 +// into the page arena so they outlive the repo handle. │ │54 pub fn init( │ │55 + comptime repo_kind: rp.RepoKind, │ │56 + comptime repo_opts: rp.RepoOpts(repo_kind), │ │57 arena: *std.heap.ArenaAllocator, │ │39 - session: *ui.Session, │ │40 - source_maybe: ?ui.RepoSource, │ │58 + repo: *rp.Repo(repo_kind, repo_opts), │ │59 + io: std.Io, │ │60 + gpa: std.mem.Allocator, │ │61 identity: []const u8, │ │62 kind: ui.RoutablePage.RefKind, │ │63 after: usize, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 66 // the offset only applies to its own column; the other stays at 0. │ │ 67 const branches_after: usize = if (kind == .branch) after else 0; │ │ 68 const tags_after: usize = if (kind == .tag) after else 0; │ │ 49 - const branches_label = try ui.SubTitle.init(arena, "branches"); │ │ 50 - const tags_label = try ui.SubTitle.init(arena, "tags"); │ │ 51 - const empty: Self = .{ │ │ 52 - .identity = try aa.dupe(u8, identity), │ │ 53 - .kind = kind, │ │ 54 - .after = after, │ │ 55 - .branches = &.{}, │ │ 56 - .tags = &.{}, │ │ 57 - .branches_next_after = null, │ │ 58 - .tags_next_after = null, │ │ 59 - .branches_label = branches_label, │ │ 60 - .tags_label = tags_label, │ │ 61 - }; │ │ 62 - │ │ 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 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; │ │ 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); │ │ 69 + var result = try emptyResult(arena, identity, kind, after); │ │ 70 │ │ 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; │ │ 71 + // xit seeks each iterator straight to its window; the git backend can't │ │ 72 + // seek, so it starts at the beginning and collectWindow discards the │ │ 73 + // entries before the window. │ │ 74 + const can_seek = repo_kind == .xit; │ │ 75 │ │ 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); │ │ 76 + var branch_iter = repo.listBranches(io, gpa, if (can_seek) .{ .index = branches_after } else .beginning) catch return result; │ │ 77 + defer branch_iter.deinit(io); │ │ 78 + const branches = try collectWindow(io, aa, &branch_iter, branches_after, if (can_seek) 0 else branches_after); │ │ 79 │ │ 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 - }; │ │ 80 + var tag_iter = repo.listTags(io, gpa, if (can_seek) .{ .index = tags_after } else .beginning) catch return result; │ │ 81 + defer tag_iter.deinit(io); │ │ 82 + const tags = try collectWindow(io, aa, &tag_iter, tags_after, if (can_seek) 0 else tags_after); │ │ 83 │ │ 96 - return .{ │ │ 97 - .identity = empty.identity, │ │ 98 - .kind = kind, │ │ 99 - .after = after, │ │100 - .branches = branches.names, │ │101 - .tags = tags.names, │ │102 - .branches_next_after = branches.next_after, │ │103 - .tags_next_after = tags.next_after, │ │104 - .branches_label = branches_label, │ │105 - .tags_label = tags_label, │ │106 - }; │ │ 84 + result.branches = branches.names; │ │ 85 + result.tags = tags.names; │ │ 86 + result.branches_next_after = branches.next_after; │ │ 87 + result.tags_next_after = tags.next_after; │ │ 88 + return result; │ │ 89 } │ │ 90 │ │ 91 // window a ref iterator without materializing the whole list. `skip` entries │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯