╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │91 else => return error.UnexpectedRoute, │ │92 }, │ │93 .fork => switch (route) { │ │94 - .fork_patch, .fork_files, .fork_commits, .fork_settings, .fork_auth => .{ .fork = try Fork.init(arena, session, route) }, │ │94 + .fork_patch, .fork_diff, .fork_files, .fork_commits, .fork_settings, .fork_auth => .{ .fork = try Fork.init(arena, session, route) },│ │95 else => return error.UnexpectedRoute, │ │96 }, │ │97 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │166 repo_settings: Array(repo_route_max_len), │ │167 repo_auth: Array(repo_route_max_len), │ │168 fork_patch: ForkRoute, │ │169 + fork_diff: struct { fork: ForkRoute, start: usize = 0, path: Array(repo_route_max_len) = .{} },│ │170 fork_files: ForkFilesRoute, │ │171 fork_commits: ForkCommitsRoute, │ │172 fork_settings: ForkRoute, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │447 return .{ .fork_patch = initForkRoute(identity, id) orelse return null }; │ │448 } │ │449 │ │450 + pub fn forkDiffRoute(identity: []const u8, id: []const u8, start: usize, path: []const u8) ?RoutablePage { │ │451 + return .{ .fork_diff = .{ │ │452 + .fork = initForkRoute(identity, id) orelse return null, │ │453 + .start = start, │ │454 + .path = Array(repo_route_max_len).from(path) orelse return null, │ │455 + } }; │ │456 + } │ │457 + │ │458 pub fn forkFilesRoute(identity: []const u8, id: []const u8, oid: []const u8, path: []const u8, line: usize) ?RoutablePage {│ │459 return .{ .fork_files = .{ │ │460 .fork = initForkRoute(identity, id) orelse return null, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │981 .repo_settings => |name| try std.fmt.allocPrint(arena.allocator(), "{s}/settings", .{try repoUrlPrefix(arena, name.slice())}), │ │982 .repo_auth => |name| try std.fmt.allocPrint(arena.allocator(), "{s}/auth", .{try repoUrlPrefix(arena, name.slice())}), │ │983 .fork_patch => |f| try std.fmt.allocPrint(arena.allocator(), fork_segment ++ "{s}/" ++ patch_seg ++ "{s}", .{ f.name.slice(), f.id.slice() }),│ │984 + .fork_diff => |d| blk: { │ │985 + var out: std.Io.Writer.Allocating = .init(arena.allocator()); │ │986 + try out.writer.print(fork_segment ++ "{s}/" ++ patch_seg ++ "{s}/diff", .{ d.fork.name.slice(), d.fork.id.slice() }); │ │987 + if (d.start != 0) try out.writer.print("/" ++ start_seg ++ "{d}", .{d.start}); │ │988 + if (d.path.len != 0) try out.writer.print("/" ++ path_seg ++ "{s}", .{d.path.slice()}); │ │989 + break :blk out.written(); │ │990 + }, │ │991 .fork_files => |f| blk: { │ │992 var out: std.Io.Writer.Allocating = .init(arena.allocator()); │ │993 try out.writer.print(fork_segment ++ "{s}/" ++ patch_seg ++ "{s}/" ++ files_seg, .{ f.fork.name.slice(), f.fork.id.slice() }); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1050 if (id.len != evt.event_id_size * 2) return null; │ │1051 const tab = segments.next() orelse return forkPatchRoute(identity, id); │ │1052 var params = Params{}; │ │1053 + if (std.mem.eql(u8, tab, "diff")) { │ │1054 + params.scanPairs(&segments) catch return null; │ │1055 + if (!params.only(&.{.start})) return null; │ │1056 + return forkDiffRoute(identity, id, params.start() orelse return null, pathValue(segments.rest()) orelse return null);│ │1057 + } │ │1058 if (std.mem.eql(u8, tab, files_seg)) { │ │1059 params.scanPairs(&segments) catch return null; │ │1060 if (!params.only(&.{ .line, .object })) return null; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────╮ │1140 pub fn forkRoute(self: *const RoutablePage) ?*const ForkRoute {│ │1141 return switch (self.*) { │ │1142 .fork_patch => |*f| f, │ │1143 + .fork_diff => |*d| &d.fork, │ │1144 .fork_files => |*f| &f.fork, │ │1145 .fork_commits => |*f| &f.fork, │ │1146 .fork_settings => |*f| f, │ ╰─────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1174 .home_users, .home_repos, .home_settings, .home_auth => .home, │ │1175 .user_repos, .user_forks, .user_settings, .user_auth => .user, │ │1176 .repo_files, .repo_commits, .repo_refs, .repo_issues, .repo_patches, .repo_discussions, .repo_events, .repo_settings, .repo_auth => .repo,│ │1155 - .fork_patch, .fork_files, .fork_commits, .fork_settings, .fork_auth => .fork, │ │1177 + .fork_patch, .fork_diff, .fork_files, .fork_commits, .fork_settings, .fork_auth => .fork, │ │1178 }; │ │1179 } │ │1180 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1449 .repo_settings => |a_name| std.mem.eql(u8, a_name.slice(), b.repo_settings.slice()), │ │1450 .repo_auth => |a_name| std.mem.eql(u8, a_name.slice(), b.repo_auth.slice()), │ │1451 .fork_patch => |a_f| std.mem.eql(u8, a_f.name.slice(), b.fork_patch.name.slice()) and std.mem.eql(u8, a_f.id.slice(), b.fork_patch.id.slice()),│ │1452 + .fork_diff => |a_d| std.mem.eql(u8, a_d.fork.name.slice(), b.fork_diff.fork.name.slice()) and │ │1453 + std.mem.eql(u8, a_d.fork.id.slice(), b.fork_diff.fork.id.slice()) and │ │1454 + a_d.start == b.fork_diff.start and std.mem.eql(u8, a_d.path.slice(), b.fork_diff.path.slice()), │ │1455 .fork_files => |a_f| std.mem.eql(u8, a_f.fork.name.slice(), b.fork_files.fork.name.slice()) and │ │1456 std.mem.eql(u8, a_f.fork.id.slice(), b.fork_files.fork.id.slice()) and │ │1457 std.mem.eql(u8, a_f.oid.slice(), b.fork_files.oid.slice()) and │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯