╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │56 - // the files and commits tabs share one ref/oid: whichever the incoming route│ │57 - // names (it rides on the route's target tab), or the default branch when │ │58 - // neither tab is targeted. building both views at it keeps switching tabs │ │59 - // (even by key, without a reload) on the same ref. a null ref means the │ │60 - // default branch (Files/Commits.init resolve it). the directory and the diff│ │61 - // window only apply to their own tab. │ │61 + // files, commits and diff share the requested ref, or the default branch. │ │62 + // directories and hunk windows only apply to their own tab. │ │63 const requested_ref_or_oid: ?ui.RoutablePage.RefOrOid = switch (route) { │ │64 .repo_files => |f| f.ref_kind, │ │65 .repo_commits => |c| c.ref_or_oid, │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │66 + .repo_diff => |d| d.ref_or_oid, │ │67 else => null, │ │68 }; │ │69 const requested_ref_value: []const u8 = switch (route) {│ ╰────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────╮ │70 .repo_files => |*f| f.ref_value.slice(), │ │71 .repo_commits => |*c| c.value.slice(), │ │72 + .repo_diff => |*d| d.value.slice(), │ │73 else => "", │ │74 }; │ │75 + const patchrev_id: []const u8 = switch (route) {│ │76 + .repo_files => |*f| f.patchrev_id.slice(), │ │77 + .repo_diff => |*d| d.patchrev_id.slice(), │ │78 + else => "", │ │79 + }; │ │80 const files_dir = switch (route) { │ │81 .repo_files => |*f| f.path.slice(), │ │82 else => "", │ ╰────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │226 } │ │227 } │ │228 │ │221 - // open the on-disk repo once and read every tab's data from it. files and │ │222 - // commits resolve the same requested ref (the default branch when the │ │223 - // route named none), so they end up viewing the same one. no filesystem │ │224 - // (wasm), nowhere to look, or a failed open: empty tabs. │ │225 - const files, const commits, const refs, var issues, var patches, var discussions, const events = blk: {│ │229 + // open the repo once for every tab. files and changes share a ref or revision. │ │230 + // no filesystem (wasm), nowhere to look, or a failed open: empty tabs. │ │231 + const files, const changes, const refs, var issues, var patches, var discussions, const events = blk: {│ │232 read: { │ │233 const io = session.io orelse break :read; │ │234 const src = source orelse break :read; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │244 try evt.consume(.local, .repo, repo_kind, opened.self_repo_opts, io, gpa, opened, evt.events_ref, &.{}); │ │245 try pch.refreshBranches(.local, repo_kind, opened.self_repo_opts, io, gpa, opened, null, null); │ │246 } │ │241 - const files_data = try Files.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, location, requested_ref_or_oid, requested_ref_value, files_dir, files_line); │ │247 + const files_data = if (patchrev_id.len != 0) │ │248 + try Files.initPatchRev(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, location, patchrev_id, files_dir, files_line) │ │249 + else │ │250 + try Files.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, location, requested_ref_or_oid, requested_ref_value, files_dir, files_line); │ │251 + const changes_data: Changes = if (route == .repo_diff) │ │252 + .{ .diff = try Diff.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, route.repo_diff) } │ │253 + else if (patchrev_id.len != 0) diff: { │ │254 + const diff_route = ui.RoutablePage.repoPatchRevDiffRoute(repo_identity.identity, patchrev_id, 0, "") orelse return error.RouteTooLong; │ │255 + break :diff .{ .diff = try Diff.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, diff_route.repo_diff) }; │ │256 + } else .{ .commits = try Commits.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, session.haxy_moment, location, requested_ref_or_oid, requested_ref_value, commits_content, commits_base_oid) };│ │257 const target_branch = if (files_data.ref_or_oid == .branch) files_data.ref_or_oid_value else ""; │ │258 break :blk .{ │ │259 files_data, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │245 - try Commits.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, session.haxy_moment, location, requested_ref_or_oid, requested_ref_value, commits_content, commits_base_oid), │ │260 + changes_data, │ │261 try Refs.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, repo_identity.identity, refs_kind, refs_from), │ │262 try Issues.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, issues_tag, issues_selected, issues_comment, issues_comments_start, issues_theirs, issues_view), │ │263 try Patches.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, session, repo_id_maybe, repo_identity.identity, target_branch, patches_tag, patches_selected, patches_comment, patches_comments_start, patches_theirs, patches_view),│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │272 const aa = arena.allocator(); │ │273 break :blk .{ │ │274 try Files.emptyResult(aa, location, requested_ref_or_oid orelse .branch, requested_ref_value, files_dir), │ │260 - try Commits.emptyResult(aa, location, requested_ref_or_oid orelse .branch, requested_ref_value, commits_content, commits_base_oid), │ │275 + Changes{ .commits = try Commits.emptyResult(aa, location, requested_ref_or_oid orelse .branch, requested_ref_value, commits_content, commits_base_oid) }, │ │276 try Refs.emptyResult(arena, repo_identity.identity, refs_kind, refs_from), │ │277 try Issues.emptyResult(aa, repo_identity.identity, issues_tag, issues_selected, issues_comment, issues_comments_start, issues_theirs, issues_view), │ │278 try Patches.emptyResult(aa, repo_identity.identity, patches_tag, patches_selected, patches_comment, patches_comments_start, patches_theirs, patches_view),│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │286 discussions.repo_source = source; │ │287 │ │288 return .{ │ │274 - // files and commits resolve the same ref, so either's serves the header, │ │275 - // which points both tabs at it. │ │289 + // use the files tab's resolved ref for the header │ │290 .header = try Header.init(arena, repo.event.name, owner_name, files.ref_or_oid, files.ref_or_oid_value, issues.tag, patches.tag, discussions.tag),│ │291 .repo = repo, │ │292 .files = files, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────╮ │279 - .commits = commits,│ │293 + .changes = changes,│ │294 .refs = refs, │ │295 .issues = issues, │ │296 .patches = patches,│ ╰────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │315 // build the header first so we can grab the files-tab id for the auth │ │316 // view (it focuses there after login). │ │317 { │ │304 - var header_view = try Header.View.init(allocator, &data.header, data.commits.commit_count, data.commits.base_oid, session); │ │318 + var header_view = try Header.View.init(allocator, data, session); │ │319 errdefer header_view.deinit(allocator); │ │320 try box.children.put(allocator, header_view.getFocus().id, .{ .widget = .{ .repo_header = header_view }, .rect = null, .min_size = null });│ │321 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯