╭ changed ──────╮ │src/ui/Fork.zig│ ╰───────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 59 const target_identity = try std.fmt.allocPrint(aa, "{s}/{s}", .{ owner.event.name, target_record.event.name }); │ │ 60 const id_hex = std.fmt.bytesToHex(id, .lower); │ │ 61 const fork_path = try fork.forkPath(aa, users_dir, &forker_id, &id); │ │ 62 - var fork_repo = try rp.Repo(.xit, .{}).open(io, arena.child_allocator, .{ .path = fork_path, .require_repo_root = true }); │ │ 63 - defer fork_repo.deinit(io, arena.child_allocator); │ │ 64 - const fork_moment = try evt.currentMoment(.{}, &fork_repo); │ │ 65 - const retained_patch = (try evt.Patch.readById(evt.EventDB(.sha1), .sha1, fork_moment, arena, &id)) orelse return error.NotFound; │ │ 66 - const fork_oid = (try fork_repo.readRef(io, fork.ref)) orelse return error.NotFound; │ │ 67 - const newest_revision = try evt.PatchRev.readNewest(evt.EventDB(.sha1), .sha1, fork_moment, arena); │ │ 68 - var commits_base_oid = fork_oid; │ │ 69 - if (newest_revision) |revision| { │ │ 70 - if (revision.record.event.base_oid.len != commits_base_oid.len) return error.NotFound; │ │ 71 - @memcpy(&commits_base_oid, revision.record.event.base_oid); │ │ 72 - } │ │ 62 + // a fork shares its target's hash kind │ │ 63 + var any_fork = try rp.AnyRepo(.xit, .{}).open(io, arena.child_allocator, .{ .path = fork_path, .require_repo_root = true }); │ │ 64 + defer any_fork.deinit(io, arena.child_allocator); │ │ 65 + switch (any_fork) { │ │ 66 + inline else => |*fork_repo| { │ │ 67 + const repo_opts = fork_repo.self_repo_opts; │ │ 68 + const fork_moment = try evt.currentMoment(repo_opts, fork_repo); │ │ 69 + const retained_patch = (try evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, arena, &id)) orelse return error.NotFound; │ │ 70 + const fork_oid = (try fork_repo.readRef(io, fork.ref)) orelse return error.NotFound; │ │ 71 + const newest_revision = try evt.PatchRev.readNewest(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, arena); │ │ 72 + var commits_base_oid = fork_oid; │ │ 73 + if (newest_revision) |revision| { │ │ 74 + if (revision.record.event.base_oid.len != commits_base_oid.len) return error.NotFound; │ │ 75 + @memcpy(&commits_base_oid, revision.record.event.base_oid); │ │ 76 + } │ │ 77 │ │ 74 - const target_path = try evt.repoPath(aa, users_dir, owner_id, &target_id); │ │ 75 - const target_source = ui.RepoSource{ .path = target_path, .repo_kind = .xit }; │ │ 76 - var target_repo_maybe: ?rp.Repo(.xit, .{}) = if (!target_record.removed) │ │ 77 - rp.Repo(.xit, .{}).open(io, arena.child_allocator, target_source.localInitOpts()) catch null │ │ 78 - else │ │ 79 - null; │ │ 80 - defer if (target_repo_maybe) |*target_repo| target_repo.deinit(io, arena.child_allocator); │ │ 78 + const target_path = try evt.repoPath(aa, users_dir, owner_id, &target_id); │ │ 79 + const target_source = ui.RepoSource{ .path = target_path, .repo_kind = .xit }; │ │ 80 + var target_repo_maybe: ?rp.Repo(.xit, repo_opts) = if (!target_record.removed) │ │ 81 + rp.Repo(.xit, repo_opts).open(io, arena.child_allocator, target_source.localInitOpts()) catch null │ │ 82 + else │ │ 83 + null; │ │ 84 + defer if (target_repo_maybe) |*target_repo| target_repo.deinit(io, arena.child_allocator); │ │ 85 │ │ 82 - const target_branch = retained_patch.event.target_branch; │ │ 86 + const target_branch = retained_patch.event.target_branch; │ │ 87 │ │ 84 - const retained_entry = Patches.PatchWithId{ │ │ 85 - .id = try aa.dupe(u8, &id_hex), │ │ 86 - .record = retained_patch, │ │ 87 - .author = try ui.Author.initFromEmail(haxy_moment, arena, retained_patch.author_email), │ │ 88 - .draft = fork_record.event.stage == .draft, │ │ 89 - .revision_oid = try aa.dupe(u8, &fork_oid), │ │ 90 - .fork_exists = true, │ │ 91 - .forker = identity.owner, │ │ 92 - }; │ │ 93 - var patch_data = try Patches.detailResult(aa, target_identity, retained_entry); │ │ 88 + const retained_entry = Patches.PatchWithId{ │ │ 89 + .id = try aa.dupe(u8, &id_hex), │ │ 90 + .record = retained_patch, │ │ 91 + .author = try ui.Author.initFromEmail(haxy_moment, arena, retained_patch.author_email), │ │ 92 + .draft = fork_record.event.stage == .draft, │ │ 93 + .revision_oid = try aa.dupe(u8, &fork_oid), │ │ 94 + .fork_exists = true, │ │ 95 + .forker = identity.owner, │ │ 96 + }; │ │ 97 + var patch_data = try Patches.detailResult(aa, target_identity, retained_entry); │ │ 98 │ │ 95 - if (target_repo_maybe) |*target_repo| switch (fork_record.event.stage) { │ │ 96 - .draft => if (try Patches.loadDraftEntry(.xit, .{}, arena, io, haxy_moment, &fork_repo, target_repo, id, identity.owner)) |entry| { │ │ 97 - patch_data = try Patches.detailResult(aa, target_identity, entry); │ │ 98 - patch_data.repo_source = target_source; │ │ 99 - }, │ │100 - .publish => { │ │101 - patch_data = Patches.init(.xit, .{}, arena, target_repo, io, haxy_moment, session, target_id, target_identity, target_branch, "", "", &id_hex, "", 0, "", .open) catch |err| switch (err) { │ │102 - error.NotFound => patch_data, │ │103 - else => |other| return other, │ │ 99 + if (target_repo_maybe) |*target_repo| switch (fork_record.event.stage) { │ │100 + .draft => if (try Patches.loadDraftEntry(.xit, repo_opts, arena, io, haxy_moment, fork_repo, target_repo, id, identity.owner)) |entry| { │ │101 + patch_data = try Patches.detailResult(aa, target_identity, entry); │ │102 + patch_data.repo_source = target_source; │ │103 + }, │ │104 + .publish => { │ │105 + patch_data = Patches.init(.xit, repo_opts, arena, target_repo, io, haxy_moment, session, target_id, target_identity, target_branch, "", "", &id_hex, "", 0, "", .open) catch |err| switch (err) {│ │106 + error.NotFound => patch_data, │ │107 + else => |other| return other, │ │108 + }; │ │109 + if (patch_data.selectedThread() != null) patch_data.repo_source = target_source; │ │110 + }, │ │111 }; │ │105 - if (patch_data.selectedThread() != null) patch_data.repo_source = target_source; │ │106 - }, │ │107 - }; │ │108 - patch_data.repo_id = target_id; │ │112 + patch_data.repo_id = target_id; │ │113 │ │110 - const requested_ref: ?ui.RoutablePage.RefOrOid = switch (route) { │ │111 - .fork_files => |f| if (f.oid.len == 0) null else .object, │ │112 - .fork_commits => |c| if (c.oid.len == 0) null else .object, │ │113 - else => null, │ │114 - }; │ │115 - const requested_value: []const u8 = switch (route) { │ │116 - .fork_files => |*f| f.oid.slice(), │ │117 - .fork_commits => |*c| c.oid.slice(), │ │118 - else => "", │ │119 - }; │ │120 - const files_path: []const u8 = switch (route) { │ │121 - .fork_files => |*f| f.path.slice(), │ │122 - else => "", │ │123 - }; │ │124 - const files_line: usize = switch (route) { │ │125 - .fork_files => |f| f.line, │ │126 - else => 0, │ │127 - }; │ │128 - const files_find: []const u8 = switch (route) { │ │129 - .fork_files => |*f| f.find.slice(), │ │130 - else => "", │ │131 - }; │ │132 - const commits_content: ui.RoutablePage.RepoCommitsRoute.Content = switch (route) { │ │133 - .fork_commits => |c| c.content, │ │134 - else => .{ .diff = .{} }, │ │135 - }; │ │136 - const location = ui.RoutablePage.RepoLocation{ .fork = .{ │ │137 - .identity = identity.identity, │ │138 - .id = &id_hex, │ │139 - } }; │ │140 - const files = try Files.init(.xit, .{}, arena, &fork_repo, io, arena.child_allocator, location, requested_ref, requested_value, files_path, files_line, files_find); │ │141 - var commits = try Commits.init(.xit, .{}, arena, &fork_repo, io, arena.child_allocator, haxy_moment, location, requested_ref, requested_value, commits_content, &commits_base_oid, "", ""); │ │142 - commits.commit_count = if (newest_revision) |revision| revision.record.commit_count else 0; │ │143 - const diff_start: usize = switch (route) { │ │144 - .fork_diff => |d| d.start, │ │145 - else => 0, │ │146 - }; │ │147 - const diff_path = switch (route) { │ │148 - .fork_diff => |*d| try aa.dupe(u8, d.path.slice()), │ │149 - else => "", │ │150 - }; │ │114 + const requested_ref: ?ui.RoutablePage.RefOrOid = switch (route) { │ │115 + .fork_files => |f| if (f.oid.len == 0) null else .object, │ │116 + .fork_commits => |c| if (c.oid.len == 0) null else .object, │ │117 + else => null, │ │118 + }; │ │119 + const requested_value: []const u8 = switch (route) { │ │120 + .fork_files => |*f| f.oid.slice(), │ │121 + .fork_commits => |*c| c.oid.slice(), │ │122 + else => "", │ │123 + }; │ │124 + const files_path: []const u8 = switch (route) { │ │125 + .fork_files => |*f| f.path.slice(), │ │126 + else => "", │ │127 + }; │ │128 + const files_line: usize = switch (route) { │ │129 + .fork_files => |f| f.line, │ │130 + else => 0, │ │131 + }; │ │132 + const files_find: []const u8 = switch (route) { │ │133 + .fork_files => |*f| f.find.slice(), │ │134 + else => "", │ │135 + }; │ │136 + const commits_content: ui.RoutablePage.RepoCommitsRoute.Content = switch (route) { │ │137 + .fork_commits => |c| c.content, │ │138 + else => .{ .diff = .{} }, │ │139 + }; │ │140 + const location = ui.RoutablePage.RepoLocation{ .fork = .{ │ │141 + .identity = identity.identity, │ │142 + .id = &id_hex, │ │143 + } }; │ │144 + const files = try Files.init(.xit, repo_opts, arena, fork_repo, io, arena.child_allocator, location, requested_ref, requested_value, files_path, files_line, files_find); │ │145 + var commits = try Commits.init(.xit, repo_opts, arena, fork_repo, io, arena.child_allocator, haxy_moment, location, requested_ref, requested_value, commits_content, &commits_base_oid, "", ""); │ │146 + commits.commit_count = if (newest_revision) |revision| revision.record.commit_count else 0; │ │147 + const diff_start: usize = switch (route) { │ │148 + .fork_diff => |d| d.start, │ │149 + else => 0, │ │150 + }; │ │151 + const diff_path = switch (route) { │ │152 + .fork_diff => |*d| try aa.dupe(u8, d.path.slice()), │ │153 + else => "", │ │154 + }; │ │155 │ │152 - return .{ │ │153 - .header = try Header.init(arena, target_record.event.name, identity.owner, &id_hex, requested_value), │ │154 - .files = files, │ │155 - .commits = commits, │ │156 - .patch = patch_data, │ │157 - .diff = .{ │ │158 - .route = .{ .fork = .{ .identity = try aa.dupe(u8, identity.identity), .id = try aa.dupe(u8, &id_hex) } }, │ │159 - .path = diff_path, │ │160 - .window = try Diff.render(.xit, .{}, io, arena.child_allocator, aa, &fork_repo, &commits_base_oid, fork_oid, diff_start, diff_path), │ │156 + return .{ │ │157 + .header = try Header.init(arena, target_record.event.name, identity.owner, &id_hex, requested_value), │ │158 + .files = files, │ │159 + .commits = commits, │ │160 + .patch = patch_data, │ │161 + .diff = .{ │ │162 + .route = .{ .fork = .{ .identity = try aa.dupe(u8, identity.identity), .id = try aa.dupe(u8, &id_hex) } }, │ │163 + .path = diff_path, │ │164 + .window = try Diff.render(.xit, repo_opts, io, arena.child_allocator, aa, fork_repo, &commits_base_oid, fork_oid, diff_start, diff_path), │ │165 + }, │ │166 + .settings = Settings.init(), │ │167 + .auth = Auth.init(), │ │168 + .quit = Quit.init(), │ │169 + }; │ │170 }, │ │162 - .settings = Settings.init(), │ │163 - .auth = Auth.init(), │ │164 - .quit = Quit.init(), │ │165 - }; │ │171 + } │ │172 } │ │173 │ │174 pub const View = struct { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │206 var commits = try Commits.View.init(allocator, &data.commits, session); │ │207 errdefer commits.deinit(allocator); │ │208 try stack.children.put(allocator, commits.getFocus().id, .{ .repo_commits = commits }); │ │209 + } │ │210 + if (session.data.user_id != null) { │ │211 + const identity = try std.fmt.allocPrint(session.page_arena.allocator(), "{s}/{s}", .{ data.header.forker_name, data.header.name });│ │212 + const route = ui.RoutablePage.forkNewRepoRoute(identity, data.header.id) orelse return error.RouteTooLong; │ │213 + var new_repo = try ui.NewRepo.View.init(allocator, session, route); │ │214 + errdefer new_repo.deinit(allocator); │ │215 + try stack.children.put(allocator, new_repo.getFocus().id, .{ .new_repo = new_repo }); │ │216 } │ │217 if (session.data.user_id != null) { │ │218 var settings = try Settings.View.init(allocator, session); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯