╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │13 const Focus = xitui.focus.Focus; │ │14 │ │15 const SubHeader = @import("SubHeader.zig"); │ │16 - │ │17 -const RefOrOid = ui.RoutablePage.RefOrOid; │ │16 │ │17 // how many lines of a file's content one window shows before a "next" link.│ │18 const file_page = 2000; │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │52 identity: []const u8, │ │53 // the resolved ref this listing is read at (the default branch when the route│ │54 // didn't name one), so the view's directory links stay pinned to it. │ │57 -ref_or_oid: RefOrOid, │ │55 +ref_or_oid: ui.RoutablePage.RefOrOid, │ │56 ref_or_oid_value: []const u8, │ │57 // the directory being viewed, relative to the repo root ("" at the root). │ │58 dir: []const u8, │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │71 session: *ui.Session, │ │72 event_id: *const [evt.event_id_size]u8, │ │73 identity: []const u8, │ │76 - requested_ref_or_oid: ?RefOrOid, │ │74 + requested_ref_or_oid: ?ui.RoutablePage.RefOrOid, │ │75 requested_value: []const u8, │ │76 path: []const u8, │ │77 // the line offset the selected file's content window starts at (0 = first).│ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 91 │ │ 92 // open + read the committed file list with the arena's backing allocator │ │ 93 // (transient; freed before init returns); the listing is built into the │ │ 96 - // page arena so it outlives them. │ │ 94 + // page arena so it outlives them. AnyRepo opens both sha1 and sha256 repos. │ │ 95 const gpa = arena.child_allocator; │ │ 98 - var repo = rp.Repo(.xit, .{}).open(io, gpa, .{ .path = repo_path }) catch return emptyResult(aa, identity, requested_ref_or_oid orelse .branch, requested_value, path); │ │ 99 - defer repo.deinit(io, gpa); │ │ 96 + 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);│ │ 97 + defer any_repo.deinit(io, gpa); │ │ 98 + │ │ 99 + return switch (any_repo) { │ │100 + inline else => |*repo| listing(repo.self_repo_opts, arena, repo, io, gpa, identity, requested_ref_or_oid, requested_value, path, after), │ │101 + }; │ │102 +} │ │103 + │ │104 +// build the listing for an opened repo. generic over the repo's hash kind so │ │105 +// the tree/diff types it threads through match the repo's opts. │ │106 +fn listing( │ │107 + comptime repo_opts: rp.RepoOpts(.xit), │ │108 + arena: *std.heap.ArenaAllocator, │ │109 + repo: *rp.Repo(.xit, repo_opts), │ │110 + io: std.Io, │ │111 + gpa: std.mem.Allocator, │ │112 + identity: []const u8, │ │113 + requested_ref_or_oid: ?ui.RoutablePage.RefOrOid, │ │114 + requested_value: []const u8, │ │115 + path: []const u8, │ │116 + after: usize, │ │117 +) !Self { │ │118 + const aa = arena.allocator(); │ │119 │ │120 // resolve the requested ref (or the default branch) to the commit oid whose │ │121 // tree we list. a ref the route named explicitly that doesn't resolve is a │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │122 // bad url (NotFound -> 404); the default-branch path falls through to empty. │ │104 - const resolved = (try ui.ResolvedRefOrOid.init(&repo, io, aa, requested_ref_or_oid, requested_value)) orelse { │ │123 + const resolved = (try ui.ResolvedRefOrOid(repo_opts).init(repo, io, aa, requested_ref_or_oid, requested_value)) orelse {│ │124 if (requested_ref_or_oid != null) return error.NotFound; │ │125 return emptyResult(aa, identity, .branch, requested_value, path); │ │126 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │128 // read the tree at that commit. building the read-only state mirrors what │ │129 // repo.status does internally, but for an arbitrary commit rather than HEAD. │ │130 var moment = repo.core.latestMoment() catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, path); │ │112 - const state = rp.Repo(.xit, .{}).State(.read_only){ .core = &repo.core, .extra = .{ .moment = &moment } }; │ │113 - var tree = tr.Tree(.xit, .{}).init(state, io, gpa, &resolved.oid) catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, path); │ │131 + const state = rp.Repo(.xit, repo_opts).State(.read_only){ .core = &repo.core, .extra = .{ .moment = &moment } }; │ │132 + 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 defer tree.deinit(); │ │134 │ │135 // `path` names a file when it's an exact tree entry: list its parent │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │184 // their first window (for the in-page detail when selected). │ │185 const is_selected = if (selected_file) |sf| std.mem.eql(u8, sf, name) else false; │ │186 const window_start = if (is_selected) after else 0; │ │168 - const content = readFileContent(state, io, gpa, aa, file_path, tree_entry, window_start) catch │ │187 + const content = readFileContent(repo_opts, state, io, gpa, aa, file_path, tree_entry, window_start) catch│ │188 FileContent{ .lines = &.{} }; │ │189 entry.lines = content.lines; │ │190 entry.is_binary = content.is_binary; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │219 // line iterator flags binary files (its source becomes `.binary`), in which case│ │220 // we report no lines and let the view show a placeholder. │ │221 fn readFileContent( │ │203 - state: rp.Repo(.xit, .{}).State(.read_only), │ │222 + comptime repo_opts: rp.RepoOpts(.xit), │ │223 + state: rp.Repo(.xit, repo_opts).State(.read_only), │ │224 io: std.Io, │ │225 gpa: std.mem.Allocator, │ │226 arena: std.mem.Allocator, │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │227 path: []const u8, │ │208 - tree_entry: tr.TreeEntry((rp.RepoOpts(.xit){}).hash), │ │228 + tree_entry: tr.TreeEntry(repo_opts.hash), │ │229 start: usize, │ │230 ) !FileContent { │ │211 - var line_iter = try df.LineIterator(.xit, .{}).initFromTree(state, io, gpa, path, tree_entry); │ │231 + var line_iter = try df.LineIterator(.xit, repo_opts).initFromTree(state, io, gpa, path, tree_entry);│ │232 defer line_iter.deinit(); │ │233 if (line_iter.source == .binary) return .{ .lines = &.{}, .is_binary = true }; │ │234 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │251 } │ │252 │ │253 // an empty listing pinned to a ref, for the wasm / no-repo / unresolved paths. │ │234 -fn emptyResult(aa: std.mem.Allocator, identity: []const u8, ref_or_oid: RefOrOid, ref_or_oid_value: []const u8, dir: []const u8) !Self { │ │254 +fn emptyResult(aa: std.mem.Allocator, identity: []const u8, ref_or_oid: ui.RoutablePage.RefOrOid, ref_or_oid_value: []const u8, dir: []const u8) !Self {│ │255 return .{ │ │256 .identity = try aa.dupe(u8, identity), │ │257 .ref_or_oid = ref_or_oid, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯