╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1132 try arena.allocator().print("/{s}/forks/" ++ start_seg ++ "{d}", .{ u.name.slice(), u.start }), │ │1133 .user_repo_new => |name| try arena.allocator().print("/{s}/repo/new", .{name.slice()}), │ │1134 .user_user_new => |name| try arena.allocator().print("/{s}/user/new", .{name.slice()}), │ │1104 - .user_user => |name| try arena.allocator().print("/{s}/user", .{name.slice()}), │ │1135 + .user_user => |u| try userTabUrl(arena, try arena.allocator().print("/{s}", .{u.name.slice()}), u.tab), │ │1136 .repo_files => |f| blk: { │ │1137 const prefix = try repoUrlPrefix(arena, f.name.slice()); │ │1138 if (f.ref_kind == null and f.patchrev_id.len == 0 and f.find.len == 0 and f.line == 0) break :blk if (prefix.len == 0) "/" else prefix;│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1310 if (r.start != 0) try out.writer.print("/" ++ start_seg ++ "{d}", .{r.start}); │ │1311 break :blk out.written(); │ │1312 }, │ │1282 - .repo_user => |name| try arena.allocator().print("{s}/user", .{try repoUrlPrefix(arena, name.slice())}),│ │1313 + .repo_user => |u| try userTabUrl(arena, try repoUrlPrefix(arena, u.name.slice()), u.tab), │ │1314 .fork_patch => |f| try arena.allocator().print("/{s}+{s}", .{ f.name.slice(), f.id.slice() }), │ │1315 .fork_diff => |d| blk: { │ │1316 var out: std.Io.Writer.Allocating = .init(arena.allocator()); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1338 }, │ │1339 .fork_repo_new => |f| try arena.allocator().print("/{s}+{s}/repo/new", .{ f.name.slice(), f.id.slice() }), │ │1340 .fork_user_new => |f| try arena.allocator().print("/{s}+{s}/user/new", .{ f.name.slice(), f.id.slice() }), │ │1310 - .fork_user => |f| try arena.allocator().print("/{s}+{s}/user", .{ f.name.slice(), f.id.slice() }), │ │1341 + .fork_user => |u| try userTabUrl(arena, try arena.allocator().print("/{s}+{s}", .{ u.fork.name.slice(), u.fork.id.slice() }), u.tab),│ │1342 + }; │ │1343 + } │ │1344 + │ │1345 + // a user tab's url under its page's `prefix` │ │1346 + fn userTabUrl(arena: *std.heap.ArenaAllocator, prefix: []const u8, tab: UserTab) ![]const u8 { │ │1347 + return switch (tab.view) { │ │1348 + .settings => try arena.allocator().print("{s}/user/settings", .{prefix}), │ │1349 + .notifications => if (tab.start == 0) │ │1350 + try arena.allocator().print("{s}/user/notifications", .{prefix}) │ │1351 + else │ │1352 + try arena.allocator().print("{s}/user/notifications/" ++ start_seg ++ "{d}", .{ prefix, tab.start }), │ │1353 }; │ │1354 } │ │1355 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1397 return if (segments.rest().len == 0) forkCommitsRoute(identity, id, oid) else null; │ │1398 } │ │1399 if (std.mem.eql(u8, tab, "repo")) return if (isNewTail(&segments)) forkRepoNewRoute(identity, id) else null; │ │1358 - if (std.mem.eql(u8, tab, "user")) return if (segments.peek() == null) forkUserRoute(identity, id) else if (isNewTail(&segments)) forkUserNewRoute(identity, id) else null;│ │1400 + if (std.mem.eql(u8, tab, "user")) return switch (userTail(&segments) orelse return null) { │ │1401 + .new => forkUserNewRoute(identity, id), │ │1402 + .tab => |user_tab| (forkUserRoute(identity, id) orelse return null).withUserTab(user_tab), │ │1403 + }; │ │1404 return null; │ │1405 } │ │1406 // "<username>:<reponame>[/<tab tail>]"; the bare pair is the files root │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │1411 } │ │1412 return repoFilesRoute(first, null, "", "", 0); │ │1413 } │ │1369 - // "home[/users[/search:<s>][/start:<n>]|/repo/new|/user[/new]|/not-found]" │ │1414 + // "home[/users[/search:<s>][/start:<n>]|/repo/new|/user/<tail>|/not-found]"│ │1415 if (std.mem.eql(u8, first, home_segment)) { │ │1416 const sub = segments.next() orelse return default; │ │1417 if (std.mem.eql(u8, sub, "users")) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1419 return withEncodedSearch(.{ .home_users = .{ .start = params.start() orelse return null } }, params.values.get(.search) orelse ""); │ │1420 } │ │1421 if (std.mem.eql(u8, sub, "repo")) return if (isNewTail(&segments)) .home_repo_new else null; │ │1377 - if (std.mem.eql(u8, sub, "user")) return if (segments.peek() == null) .home_user else if (isNewTail(&segments)) .home_user_new else null;│ │1422 + if (std.mem.eql(u8, sub, "user")) return switch (userTail(&segments) orelse return null) { │ │1423 + .new => .home_user_new, │ │1424 + .tab => |user_tab| .{ .home_user = user_tab }, │ │1425 + }; │ │1426 if (std.mem.eql(u8, sub, "not-found")) return if (segments.peek() == null) .not_found else null; │ │1427 return null; │ │1428 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │1381 - // "<username>[/repos[/search:<s>][/start:<n>]|/forks|/repo/new|/user[/new]]" │ │1429 + // "<username>[/repos[/search:<s>][/start:<n>]|/forks|/repo/new|/user/<tail>]" │ │1430 evt.User.validateName(first) catch return null; │ │1431 const parsed = Array(evt.User.name_max_len).from(first) orelse return null; │ │1432 const sub = segments.next() orelse return .{ .user_repos = .{ .name = parsed } };│ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1436 } │ │1437 if (std.mem.eql(u8, sub, "forks")) return .{ .user_forks = .{ .name = parsed, .start = listStart(&segments) orelse return null } }; │ │1438 if (std.mem.eql(u8, sub, "repo")) return if (isNewTail(&segments)) .{ .user_repo_new = parsed } else null; │ │1391 - if (std.mem.eql(u8, sub, "user")) return if (segments.peek() == null) .{ .user_user = parsed } else if (isNewTail(&segments)) .{ .user_user_new = parsed } else null;│ │1439 + if (std.mem.eql(u8, sub, "user")) return switch (userTail(&segments) orelse return null) { │ │1440 + .new => .{ .user_user_new = parsed }, │ │1441 + .tab => |user_tab| .{ .user_user = .{ .name = parsed, .tab = user_tab } }, │ │1442 + }; │ │1443 return null; // unknown sub-path │ │1444 } │ │1445 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1482 .repo_events => |*e| e.name.slice(), │ │1483 .repo_undo => |*u| u.name.slice(), │ │1484 .repo_roles => |*r| r.name.slice(), │ │1434 - .repo_settings, .repo_repo_new, .repo_user_new, .repo_user => |*name| name.slice(),│ │1485 + .repo_user => |*u| u.name.slice(), │ │1486 + .repo_settings, .repo_repo_new, .repo_user_new => |*name| name.slice(), │ │1487 else => null, │ │1488 }; │ │1489 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────╮ │1496 .fork_commits => |*f| &f.fork,│ │1497 .fork_repo_new => |*f| f, │ │1498 .fork_user_new => |*f| f, │ │1447 - .fork_user => |*f| f, │ │1499 + .fork_user => |*u| &u.fork, │ │1500 else => null, │ │1501 }; │ │1502 } │ ╰────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯