╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────╮ │70 pub fn init( │ │71 arena: *std.heap.ArenaAllocator, │ │72 session: *ui.Session, │ │73 - event_id: *const [evt.event_id_size]u8, │ │73 + source_maybe: ?ui.RepoSource, │ │74 identity: []const u8, │ │75 requested_ref_or_oid: ?ui.RoutablePage.RefOrOid,│ │76 requested_value: []const u8, │ ╰────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │84 // ref the route asked for. the wasm path never calls init anyway — it │ │85 // rebuilds from the serialized snapshot. │ │86 const io = session.io orelse return emptyResult(aa, identity, requested_ref_or_oid orelse .branch, requested_value, path); │ │87 - const repos_dir = session.repos_dir orelse return emptyResult(aa, identity, requested_ref_or_oid orelse .branch, requested_value, path);│ │88 - │ │89 - // the repo's working copy lives at <repos_dir>/<hex event id>. │ │90 - const hex = std.fmt.bytesToHex(event_id.*, .lower); │ │91 - const repo_path = try std.fs.path.join(aa, &.{ repos_dir, &hex }); │ │87 + const source = source_maybe orelse return emptyResult(aa, identity, requested_ref_or_oid orelse .branch, requested_value, path); │ │88 │ │89 // open + read the committed file list with the arena's backing allocator │ │90 // (transient; freed before init returns); the listing is built into the │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 91 // page arena so it outlives them. AnyRepo opens both sha1 and sha256 repos. │ │ 92 const gpa = arena.child_allocator; │ │ 97 - var any_repo = rp.AnyRepo(.xit, .{}).open(io, gpa, .{ .path = repo_path }) catch return emptyResult(aa, identity, requested_ref_or_oid orelse .branch, requested_value, path); │ │ 98 - defer any_repo.deinit(io, gpa); │ │ 93 + switch (source.repo_kind) { │ │ 94 + inline else => |repo_kind| { │ │ 95 + var any_repo = rp.AnyRepo(repo_kind, .{}).open(io, gpa, .{ .path = source.path }) catch return emptyResult(aa, identity, requested_ref_or_oid orelse .branch, requested_value, path);│ │ 96 + defer any_repo.deinit(io, gpa); │ │ 97 │ │100 - return switch (any_repo) { │ │101 - inline else => |*repo| listing(repo.self_repo_opts, arena, repo, io, gpa, identity, requested_ref_or_oid, requested_value, path, after), │ │102 - }; │ │ 98 + return switch (any_repo) { │ │ 99 + inline else => |*repo| listing(repo_kind, repo.self_repo_opts, arena, repo, io, gpa, identity, requested_ref_or_oid, requested_value, path, after), │ │100 + }; │ │101 + }, │ │102 + } │ │103 } │ │104 │ │105 -// build the listing for an opened repo. generic over the repo's hash kind so │ │106 -// the tree/diff types it threads through match the repo's opts. │ │105 +// build the listing for an opened repo. generic over the repo's backend and │ │106 +// hash kind so the tree/diff types it threads through match the repo's opts. │ │107 fn listing( │ │108 - comptime repo_opts: rp.RepoOpts(.xit), │ │108 + comptime repo_kind: rp.RepoKind, │ │109 + comptime repo_opts: rp.RepoOpts(repo_kind), │ │110 arena: *std.heap.ArenaAllocator, │ │110 - repo: *rp.Repo(.xit, repo_opts), │ │111 + repo: *rp.Repo(repo_kind, repo_opts), │ │112 io: std.Io, │ │113 gpa: std.mem.Allocator, │ │114 identity: []const u8, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │122 // resolve the requested ref (or the default branch) to the commit oid whose │ │123 // tree we list. a ref the route named explicitly that doesn't resolve is a │ │124 // bad url (NotFound -> 404); the default-branch path falls through to empty. │ │124 - const resolved = (try ui.ResolvedRefOrOid(repo_opts).init(repo, io, aa, requested_ref_or_oid, requested_value)) orelse { │ │125 + const resolved = (try ui.ResolvedRefOrOid(repo_kind, repo_opts).init(repo, io, aa, requested_ref_or_oid, requested_value)) orelse {│ │126 if (requested_ref_or_oid != null) return error.NotFound; │ │127 return emptyResult(aa, identity, .branch, requested_value, path); │ │128 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │130 // read the tree at that commit. building the read-only state mirrors what │ │131 // repo.status does internally, but for an arbitrary commit rather than HEAD. │ │132 var moment = repo.core.latestMoment() catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, path); │ │132 - const state = rp.Repo(.xit, repo_opts).State(.read_only){ .core = &repo.core, .extra = .{ .moment = &moment } }; │ │133 - var tree = tr.Tree(.xit, repo_opts).init(state, io, gpa, &resolved.oid) catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, path); │ │133 + const state = rp.Repo(repo_kind, repo_opts).State(.read_only){ .core = &repo.core, .extra = .{ .moment = &moment } }; │ │134 + var tree = tr.Tree(repo_kind, repo_opts).init(state, io, gpa, &resolved.oid) catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, path);│ │135 defer tree.deinit(); │ │136 │ │137 // `path` names a file when it's an exact tree entry: list its parent │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │186 // their first window (for the in-page detail when selected). │ │187 const is_selected = if (selected_file) |sf| std.mem.eql(u8, sf, name) else false; │ │188 const window_start = if (is_selected) after else 0; │ │188 - const content = readFileContent(repo_opts, state, io, gpa, aa, file_path, tree_entry, window_start) catch │ │189 + const content = readFileContent(repo_kind, repo_opts, state, io, gpa, aa, file_path, tree_entry, window_start) catch│ │190 FileContent{ .lines = &.{} }; │ │191 entry.lines = content.lines; │ │192 entry.is_binary = content.is_binary; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │221 // line iterator flags binary files (its source becomes `.binary`), in which case│ │222 // we report no lines and let the view show a placeholder. │ │223 fn readFileContent( │ │223 - comptime repo_opts: rp.RepoOpts(.xit), │ │224 - state: rp.Repo(.xit, repo_opts).State(.read_only), │ │224 + comptime repo_kind: rp.RepoKind, │ │225 + comptime repo_opts: rp.RepoOpts(repo_kind), │ │226 + state: rp.Repo(repo_kind, repo_opts).State(.read_only), │ │227 io: std.Io, │ │228 gpa: std.mem.Allocator, │ │229 arena: std.mem.Allocator, │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │231 tree_entry: tr.TreeEntry(repo_opts.hash), │ │232 start: usize, │ │233 ) !FileContent { │ │232 - var line_iter = try df.LineIterator(.xit, repo_opts).initFromTree(state, io, gpa, path, tree_entry); │ │234 + var line_iter = try df.LineIterator(repo_kind, repo_opts).initFromTree(state, io, gpa, path, tree_entry);│ │235 defer line_iter.deinit(); │ │236 if (line_iter.source == .binary) return .{ .lines = &.{}, .is_binary = true }; │ │237 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯