╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │41 // pane shows a placeholder rather than its bytes. │ │42 is_binary: bool = false, │ │43 // the line index this window starts at (0 = the first window). non-zero only│ │44 - // for the route's selected file, paginated by the url's `after`. │ │44 + // for the route's selected file, paginated by the url's `start`. │ │45 window_start: usize = 0, │ │46 // whether more lines exist after this window. │ │47 has_more: bool = false, │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────╮ │80 requested_ref_or_oid: ?ui.RoutablePage.RefOrOid,│ │81 requested_value: []const u8, │ │82 path: []const u8, │ │83 - after: usize, │ │83 + start: usize, │ │84 ) !Self { │ │85 const aa = arena.allocator(); │ │86 │ ╰────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │150 // only the route's selected file paginates; the rest show │ │151 // their first window (for the in-page detail when selected). │ │152 const is_selected = if (selected_file) |sf| std.mem.eql(u8, sf, name) else false; │ │153 - const window_start = if (is_selected) after else 0; │ │153 + const window_start = if (is_selected) start else 0; │ │154 const content = readFileContent(repo_kind, repo_opts, state, io, gpa, aa, file_path, tree_entry, window_start) catch│ │155 FileContent{ .lines = &.{} }; │ │156 entry.lines = content.lines; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │453 if (self.box.getFocus().children.contains(g)) { │ │454 var buf: [ui.RoutablePage.repo_route_max_len]u8 = undefined;│ │455 var sel_path = self.data.dir; │ │456 - var sel_after: usize = 0; │ │456 + var sel_start: usize = 0; │ │457 if (self.selectedEntry()) |entry| { │ │458 if (!entry.is_dir) { │ │459 sel_path = if (self.data.dir.len == 0) │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │460 entry.name │ │461 else │ │462 std.fmt.bufPrint(&buf, "{s}/{s}", .{ self.data.dir, entry.name }) catch self.data.dir; │ │463 - sel_after = entry.window_start; │ │463 + sel_start = entry.window_start; │ │464 } │ │465 } │ │466 - if (ui.RoutablePage.repoFilesRoute(self.data.identity, self.data.ref_or_oid, self.data.ref_or_oid_value, sel_path, sel_after)) |route|│ │466 + if (ui.RoutablePage.repoFilesRoute(self.data.identity, self.data.ref_or_oid, self.data.ref_or_oid_value, sel_path, sel_start)) |route|│ │467 self.session.data.current_page = route; │ │468 } │ │469 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │571 } │ │572 │ │573 // a focusable "next" link above the content. it's an `a:` link to the │ │574 - // selected file at `target_after`, so activating it (the host follows the │ │574 + // selected file at `target_start`, so activating it (the host follows the │ │575 // link) reloads the page on the next window. │ │576 - fn addNavLink(self: *View, allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, entry: Entry, target_after: usize) !void { │ │576 + fn addNavLink(self: *View, allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, entry: Entry, target_start: usize) !void { │ │577 const page_arena = self.session.page_arena; │ │578 const path = try childDir(page_arena.allocator(), self.data.dir, entry.name); │ │579 - const route = ui.RoutablePage.repoFilesRoute(self.data.identity, self.data.ref_or_oid, self.data.ref_or_oid_value, path, target_after) orelse return error.RouteTooLong;│ │579 + const route = ui.RoutablePage.repoFilesRoute(self.data.identity, self.data.ref_or_oid, self.data.ref_or_oid_value, path, target_start) orelse return error.RouteTooLong;│ │580 const link = try std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{try route.urlAlloc(page_arena)}); │ │581 var tb = try wgt.TextBox(ui.Widget).init(allocator, label, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .none }); │ │582 errdefer tb.deinit(allocator); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │116 const files_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try files_route.urlAlloc(session.page_arena)}); │ │117 const commits_route = ui.RoutablePage.repoCommitsRoute(identity, data.ref_or_oid, data.ref_or_oid_value, 0) orelse return error.RouteTooLong;│ │118 const commits_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try commits_route.urlAlloc(session.page_arena)}); │ │119 - const refs_route = ui.RoutablePage.repoRefsRoute(identity, .branch, 0) orelse return error.RouteTooLong; │ │119 + const refs_route = ui.RoutablePage.repoRefsRoute(identity, .branch, "") orelse return error.RouteTooLong; │ │120 const refs_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try refs_route.urlAlloc(session.page_arena)}); │ │121 const issues_route = ui.RoutablePage.repoIssuesRoute(identity, .open, data.issues_tag, "") orelse return error.RouteTooLong; │ │122 const issues_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try issues_route.urlAlloc(session.page_arena)}); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │252 // seek once to the window start: the root key, or the set's first entry. │ │253 var prev_id: ?[]const u8 = null; │ │254 var iter = if (root_key) |key| blk: { │ │255 - // the previous window starts page_size ranks back. │ │255 + // the previous window starts page_size ranks back ("" = the first │ │256 + // window, linked as the bare list route). │ │257 const rank = try set.rank(key); │ │257 - if (rank > 0) { │ │258 - const prev_rank = rank -| page_size; │ │259 - const kv = try set.getIndexKeyValuePair(@intCast(prev_rank)) orelse return error.NotFound; │ │258 + if (rank > 0 and rank <= page_size) { │ │259 + prev_id = ""; │ │260 + } else if (rank > page_size) { │ │261 + const kv = try set.getIndexKeyValuePair(@intCast(rank - page_size)) orelse return error.NotFound;│ │262 var prev_key: [@sizeOf(u64) + evt.event_id_size]u8 = undefined; │ │263 _ = try kv.key_cursor.readBytes(&prev_key); │ │264 const prev_hex = std.fmt.bytesToHex(prev_key[@sizeOf(u64)..].*, .lower); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │371 defer items.deinit(allocator); │ │372 // when filtered, the first item clears the filter │ │373 if (data.tag.len != 0) │ │372 - try items.append(allocator, .{ .text = "╳", .link = try issuesLink(session.page_arena, data.identity, "", "") }); │ │374 + try items.append(allocator, .{ .text = "╳", .link = try issuesLink(session.page_arena, data.identity, .open, "", "") });│ │375 for (data.tags) |tag| │ │376 try items.append(allocator, .{ .text = tag, .link = try tagLink(session.page_arena, data.identity, .open, tag) }); │ │377 try tf.setItems(allocator, items.items); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │407 var list_box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .vert }); │ │408 errdefer list_box.deinit(allocator); │ │409 if (win.prev_id) |prev| │ │408 - try addRow(allocator, &list_box, "← previous", try issuesLink(session.page_arena, data.identity, data.tag, prev)); │ │410 + try addRow(allocator, &list_box, "← previous", try issuesLink(session.page_arena, data.identity, status, data.tag, prev));│ │411 for (win.issues) |entry| │ │412 try addRow(allocator, &list_box, entry.issue.title, try issueRowLink(session.page_arena, data.identity, entry.id)); │ │413 if (win.next_id) |next| │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯