╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │575 │ │576 fn populateDiff(self: *View, allocator: std.mem.Allocator, sel: usize) !void {│ │577 const commit = self.data.commits[sel]; │ │578 + // the path filter only applies to the top commit (the walk root). │ │579 + const path = if (sel == 0) self.data.path else ""; │ │580 const inner = self.diffInner(); │ │581 │ │582 for (inner.children.values()) |*child| child.widget.deinit(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │583 inner.children.clearAndFree(allocator); │ │584 inner.getFocus().child_id = null; │ │585 │ │571 - // the first row always links to viewing the repo's files at this commit. │ │572 - try self.addViewFilesLink(allocator, inner, commit.oid); │ │586 + if (path.len != 0) { │ │587 + // the file's path, then a row returning to this commit's unfiltered diff. │ │588 + var label = try wgt.TextBox(ui.Widget).init(allocator, path, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .none });│ │589 + errdefer label.deinit(allocator); │ │590 + label.getFocus().focusable = true; │ │591 + try inner.children.put(allocator, label.getFocus().id, .{ .widget = .{ .text_box = label }, .rect = null, .min_size = null }); │ │592 + try self.addNavLink(allocator, inner, "← all files", commit.oid, 0, ""); │ │593 + } else { │ │594 + // the first row always links to viewing the repo's files at this commit. │ │595 + try self.addViewFilesLink(allocator, inner, commit.oid); │ │596 + } │ │597 │ │598 // a "previous" row and a "next" row at the bottom reload the page on the │ │599 // adjacent diff window. │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │576 - if (commit.has_prev) try self.addNavLink(allocator, inner, "← previous", commit.oid, commit.window_start -| diff_page); │ │600 + if (commit.has_prev) try self.addNavLink(allocator, inner, "← previous", commit.oid, commit.window_start -| diff_page, path);│ │601 for (commit.hunks) |hunk| { │ │578 - if (hunk.path) |path| try self.addPathBox(allocator, inner, path); │ │602 + if (path.len == 0) if (hunk.path) |hunk_path| try self.addPathBox(allocator, inner, hunk_path, commit.oid); │ │603 try self.addHunkBox(allocator, inner, hunk.lines); │ │604 } │ │581 - if (commit.has_more) try self.addNavLink(allocator, inner, "next →", commit.oid, commit.window_start + diff_page); │ │605 + if (commit.has_more) try self.addNavLink(allocator, inner, "next →", commit.oid, commit.window_start + diff_page, path); │ │606 │ │607 // point the pane at its first row so focus recovery can land here. │ │608 if (inner.children.count() > 0) inner.getFocus().child_id = inner.children.keys()[0]; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │637 .enter => if (self.selectedCommitIndex() != null) │ │638 try self.focusDiff(root_focus) │ │639 else if (self.data.next_start) |next| { │ │616 - if (ui.RoutablePage.repoCommitsRoute(self.data.identity, .object, next, 0)) |route| │ │640 + if (ui.RoutablePage.repoCommitsRoute(self.data.identity, .object, next, 0, "")) |route|│ │641 try self.session.navigate(route); │ │642 }, │ │643 .arrow_right => try self.focusDiff(root_focus), │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │814 }; │ │815 │ │816 // the "a:" navigation link for the commits page walking from commit `oid` within │ │793 -// `identity`, showing the selected commit's first `start` hunks (0 = default). │ │794 -fn commitsLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, oid: []const u8, start: usize) ![]const u8 { │ │795 - const route = ui.RoutablePage.repoCommitsRoute(identity, .object, oid, start) orelse return error.RouteTooLong; │ │817 +// `identity`, windowing the selected commit's diff from hunk `start`, filtered │ │818 +// to `path` ("" = every file). │ │819 +fn commitsLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, oid: []const u8, start: usize, path: []const u8) ![]const u8 {│ │820 + const route = ui.RoutablePage.repoCommitsRoute(identity, .object, oid, start, path) orelse return error.RouteTooLong; │ │821 const url = try route.toUrl(page_arena); │ │822 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{url}); │ │823 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │833 // the in-page "ai:" anchor for selecting `oid` in `identity`'s commit list. it │ │834 // points at the same route as commitsLink but the "ai:" prefix keeps wasm clicks │ │835 // in-page (crossPageLink ignores it); the href is only followed with js off. │ │811 -fn commitRowLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, oid: []const u8) ![]const u8 { │ │812 - const route = ui.RoutablePage.repoCommitsRoute(identity, .object, oid, 0) orelse return error.RouteTooLong; │ │836 +fn commitRowLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, oid: []const u8, path: []const u8) ![]const u8 {│ │837 + const route = ui.RoutablePage.repoCommitsRoute(identity, .object, oid, 0, path) orelse return error.RouteTooLong; │ │838 const url = try route.toUrl(page_arena); │ │839 return std.fmt.allocPrint(page_arena.allocator(), "ai:{s}", .{url}); │ │840 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │114 // keeps the same ref (the files tab opens at its root directory). │ │115 const files_route = ui.RoutablePage.repoFilesRoute(identity, data.ref_or_oid, data.ref_or_oid_value, "", 0) orelse return error.RouteTooLong; │ │116 const files_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try files_route.toUrl(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; │ │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.toUrl(session.page_arena)}); │ │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.toUrl(session.page_arena)}); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯