╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────────────╮ │src/ui/Home/Users.zig│ ╰─────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │88 // a trailing "next" row when more remain. each window row navigates to the │ │89 // adjacent window (full reload on web, Nav rebuild on the TUI). │ │90 var items: std.ArrayList(ui.FlowBox.Item) = .empty; │ │91 - if (data.after > 0) │ │92 - try items.append(aa, .{ .text = "← previous", .link = try std.fmt.allocPrint(aa, "a:/users?after={d}", .{data.after -| page_size}) });│ │91 + if (data.start > 0) │ │92 + try items.append(aa, .{ .text = "← previous", .link = try std.fmt.allocPrint(aa, "a:/users/start:{d}", .{data.start -| page_size}) });│ │93 for (data.users) |user| │ │94 // clicking a user opens their page; the "a:" prefix makes the web │ │95 // renderer emit an <a href="/user/foo"> anchor. │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 97 .text = try std.fmt.allocPrint(aa, "{s} ({s})", .{ user.name, user.display_name }), │ │ 98 .link = try std.fmt.allocPrint(aa, "a:/user/{s}", .{user.name}), │ │ 99 }); │ │100 - if (data.next_after) |next_after| │ │101 - try items.append(aa, .{ .text = "next →", .link = try std.fmt.allocPrint(aa, "a:/users?after={d}", .{next_after}) });│ │100 + if (data.next_start) |next_start| │ │101 + try items.append(aa, .{ .text = "next →", .link = try std.fmt.allocPrint(aa, "a:/users/start:{d}", .{next_start}) });│ │102 try self.list.setItems(allocator, items.items); │ │103 │ │104 return self; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │31 settings: Settings, │ │32 auth: Auth, │ │33 quit: Quit, │ │34 -// the full files route this page renders ("owner/name" or "owner/name/files/<dir>"),│ │35 -// mirrored into current_page when the files tab is selected. │ │34 +// the full files route this page renders, mirrored into current_page when │ │35 +// the files tab is selected. │ │36 route_name: Array, │ │37 -// the content window (?after=N) of that files route; mirrored alongside the name │ │38 -// so the url keeps the query param even when focus isn't in the files view. │ │39 -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, │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │43 -// the diff window (?after=N) of that commits route; mirrored alongside the name│ │44 -// so the url keeps the query param even when focus isn't in the commits view. │ │45 -commits_after: usize, │ │40 // "owner/name" alone, mirrored when the settings/auth tab is selected. │ │41 identity: Array, │ │42 │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │53 // every repo route's stored string starts with "owner/name"; the files and│ │54 // commits routes additionally encode a ref/oid (files also a directory). │ │55 const name_str: []const u8 = switch (route) { │ │62 - .repo_files => |f| f.name.slice(), │ │63 - .repo_settings, .repo_auth => |n| n.slice(), │ │64 - .repo_commits => |c| c.name.slice(), │ │56 + .repo_files, .repo_settings, .repo_auth => |n| n.slice(), │ │57 + .repo_commits => |c| c.slice(), │ │58 .repo_refs => |r| r.name.slice(), │ │59 .repo_issues => |i| i.name.slice(), │ │60 else => return error.UnexpectedRoute, │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │68 // (even by key, without a reload) on the same ref. a null ref means the │ │69 // default branch (Files/Commits.init resolve it). the directory and the diff │ │70 // window only apply to their own tab. │ │78 - const commits_ref = if (tag == .repo_commits) ui.RoutablePage.repoCommitsRef(name_str) else ui.RoutablePage.CommitsRef{ .ref_or_oid = null, .value = "" }; │ │71 + const commits_ref = if (tag == .repo_commits) ui.RoutablePage.repoCommitsRef(name_str) else ui.RoutablePage.CommitsRef{ .ref_or_oid = null, .value = "", .start = 0 };│ │72 const requested_ref_or_oid: ?ui.RoutablePage.RefOrOid = switch (tag) { │ │73 .repo_files => rf.ref_kind, │ │74 .repo_commits => commits_ref.ref_or_oid, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │ 80 else => "", │ │ 81 }; │ │ 82 const files_dir = if (tag == .repo_files) rf.dir else ""; │ │ 90 - // the line offset the files view's selected file content window starts at. │ │ 91 - const files_after: usize = switch (route) { │ │ 92 - .repo_files => |f| f.after, │ │ 93 - else => 0, │ │ 94 - }; │ │ 95 - // how many diff hunks the commits view's selected commit shows ("load more").│ │ 96 - const commits_after: usize = switch (route) { │ │ 97 - .repo_commits => |c| c.after, │ │ 98 - else => 0, │ │ 99 - }; │ │100 - // the refs tab paginates one column at a time: this offset applies to │ │101 - // `refs_kind`'s column, the other stays at its first window. │ │ 83 + // 0 for non-files routes, whose tails parse as the bare root │ │ 84 + const files_start = rf.start; │ │ 85 + // the hunk the commits view's selected commit's diff window starts at. │ │ 86 + const commits_start = commits_ref.start; │ │ 87 + // the refs tab windows one column at a time: `refs_from` (a url-encoded │ │ 88 + // ref name) roots `refs_kind`'s column, the other stays at its first window. │ │ 89 const refs_kind: ui.RoutablePage.RefKind = switch (route) { │ │ 90 .repo_refs => |r| r.kind, │ │ 91 else => .branch, │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │ 92 }; │ │106 - const refs_after: usize = switch (route) { │ │107 - .repo_refs => |r| r.after, │ │108 - else => 0, │ │ 93 + const refs_from: []const u8 = switch (route) { │ │ 94 + .repo_refs => |r| r.from.slice(), │ │ 95 + else => "", │ │ 96 }; │ │ 97 // the issues tab's tag filter, the issue its window is rooted at, and the│ │ 98 // view it shows. │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │166 const is_local = session.local != null; │ │167 if (is_local) try evt.syncLocalEvents(repo_kind, opened.self_repo_opts, io, gpa, opened); │ │168 break :blk .{ │ │182 - try Files.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, rf.identity, requested_ref_or_oid, requested_ref_value, files_dir, files_after),│ │183 - try Commits.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, rf.identity, requested_ref_or_oid, requested_ref_value, commits_after), │ │184 - try Refs.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, rf.identity, refs_kind, refs_after), │ │169 + try Files.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, rf.identity, requested_ref_or_oid, requested_ref_value, files_dir, files_start),│ │170 + try Commits.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, rf.identity, requested_ref_or_oid, requested_ref_value, commits_start), │ │171 + try Refs.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, rf.identity, refs_kind, refs_from), │ │172 try Issues.init(repo_kind, opened.self_repo_opts, arena, opened, io, is_local, rf.identity, issues_tag, issues_selected, issues_view), │ │173 }; │ │174 }, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │180 break :blk .{ │ │181 try Files.emptyResult(aa, rf.identity, requested_ref_or_oid orelse .branch, requested_ref_value, files_dir),│ │182 try Commits.emptyResult(aa, rf.identity, requested_ref_or_oid orelse .branch, requested_ref_value), │ │196 - try Refs.emptyResult(arena, rf.identity, refs_kind, refs_after), │ │183 + try Refs.emptyResult(arena, rf.identity, refs_kind, refs_from), │ │184 try Issues.emptyResult(aa, rf.identity, issues_tag, issues_selected, issues_view), │ │185 }; │ │186 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯