╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │323 const value = if (k2) |i| after_kind[0..i] else after_kind; │ │324 if (value.len == 0) return null; │ │325 const dir = if (k2) |i| after_kind[i + 1 ..] else ""; │ │321 - return repoFilesRoute(pair, kind, value, dir); │ │326 + return repoFilesRoute(pair, kind, value, dir, after); │ │327 } │ │328 if (std.mem.eql(u8, sub, commits_seg)) return repoCommitsRoute(pair, null, "", after); // trailing /commits == default branch│ │329 if (std.mem.startsWith(u8, sub, commits_seg ++ "/")) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────╮ │337 } │ │338 return null; // unknown sub-path │ │339 } │ │335 - return repoFilesRoute(pair, null, "", ""); │ │340 + return repoFilesRoute(pair, null, "", "", after);│ │341 } │ │342 return null; │ │343 } │ ╰──────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │374 .user => |a_u| std.mem.eql(u8, a_u.name.slice(), b.user.name.slice()) and a_u.after == b.user.after, │ │375 .user_settings => |a_name| std.mem.eql(u8, a_name.slice(), b.user_settings.slice()), │ │376 .user_auth => |a_name| std.mem.eql(u8, a_name.slice(), b.user_auth.slice()), │ │372 - .repo => |a_name| std.mem.eql(u8, a_name.slice(), b.repo.slice()), │ │377 + .repo_files => |a_f| std.mem.eql(u8, a_f.name.slice(), b.repo_files.name.slice()) and a_f.after == b.repo_files.after, │ │378 .repo_commits => |a_c| std.mem.eql(u8, a_c.name.slice(), b.repo_commits.name.slice()) and a_c.after == b.repo_commits.after, │ │379 .repo_refs => |a_r| std.mem.eql(u8, a_r.name.slice(), b.repo_refs.name.slice()) and a_r.kind == b.repo_refs.kind and a_r.after == b.repo_refs.after,│ │380 .repo_settings => |a_name| std.mem.eql(u8, a_name.slice(), b.repo_settings.slice()), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────╮ │442 try jw.objectField("name"); │ │443 try jw.write(name.slice()); │ │444 }, │ │440 - .repo, .repo_settings, .repo_auth => |name| {│ │445 + .repo_settings, .repo_auth => |name| { │ │446 try jw.objectField("name"); │ │447 try jw.write(name.slice()); │ │448 + }, │ │449 + .repo_files => |f| { │ │450 + try jw.objectField("name"); │ │451 + try jw.write(f.name.slice()); │ │452 + try jw.objectField("after"); │ │453 + try jw.write(f.after); │ │454 }, │ │455 .repo_commits => |c| { │ │456 try jw.objectField("name"); │ ╰──────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │495 .user => .{ .user = .{ .name = try parseName(evt.User.name_max_len, helper.name), .after = helper.after } }, │ │496 .user_settings => .{ .user_settings = try parseName(evt.User.name_max_len, helper.name) }, │ │497 .user_auth => .{ .user_auth = try parseName(evt.User.name_max_len, helper.name) }, │ │487 - .repo => .{ .repo = try parseName(repo_route_max_len, helper.name) }, │ │498 + .repo_files => .{ .repo_files = .{ .name = try parseName(repo_route_max_len, helper.name), .after = helper.after } }, │ │499 .repo_commits => .{ .repo_commits = .{ .name = try parseName(repo_route_max_len, helper.name), .after = helper.after } },│ │500 .repo_refs => .{ .repo_refs = .{ │ │501 .name = try parseName(repo_route_max_len, helper.name), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │31 // the full files route this page renders ("owner/name" or "owner/name/files/<dir>"),│ │32 // mirrored into current_page when the files tab is selected. │ │33 route_name: Array, │ │34 +// the content window (?after=N) of that files route; mirrored alongside the name │ │35 +// so the url keeps the query param even when focus isn't in the files view. │ │36 +files_after: usize, │ │37 // the commits route this page renders ("owner/name/commits[/<oid>]"), mirrored │ │38 // when the commits tab is selected. │ │39 commits_route_name: Array, │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │57 // every repo route's stored string starts with "owner/name"; the files and│ │58 // commits routes additionally encode a ref/oid (files also a directory). │ │59 const name_str: []const u8 = switch (route) { │ │57 - .repo, .repo_settings, .repo_auth => |n| n.slice(), │ │60 + .repo_files => |f| f.name.slice(), │ │61 + .repo_settings, .repo_auth => |n| n.slice(), │ │62 .repo_commits => |c| c.name.slice(), │ │63 .repo_refs => |r| r.name.slice(), │ │64 else => return error.UnexpectedRoute, │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │74 // window only apply to their own tab. │ │75 const commits_ref = if (tag == .repo_commits) ui.RoutablePage.repoCommitsRef(name_str) else ui.RoutablePage.CommitsRef{ .ref_or_oid = null, .value = "" };│ │76 const requested_ref_or_oid: ?ui.RoutablePage.RefOrOid = switch (tag) { │ │73 - .repo => rf.ref_kind, │ │77 + .repo_files => rf.ref_kind, │ │78 .repo_commits => commits_ref.ref_or_oid, │ │79 else => null, │ │80 }; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────╮ │81 const requested_ref_value: []const u8 = switch (tag) {│ │78 - .repo => rf.ref_value, │ │82 + .repo_files => rf.ref_value, │ │83 .repo_commits => commits_ref.value, │ │84 else => "", │ │85 }; │ ╰──────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │82 - const files_dir = if (tag == .repo) rf.dir else ""; │ │86 + const files_dir = if (tag == .repo_files) rf.dir else ""; │ │87 + // the line offset the files view's selected file content window starts at. │ │88 + const files_after: usize = switch (route) { │ │89 + .repo_files => |f| f.after, │ │90 + else => 0, │ │91 + }; │ │92 // how many diff hunks the commits view's selected commit shows ("load more").│ │93 const commits_after: usize = switch (route) { │ │94 .repo_commits => |c| c.after, │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯