╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────╮ │src/ui/Repo/Refs.zig│ ╰────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │425 }; │ │426 │ │427 // the "a:" link to `kind`'s column windowed from ref `name` (raw; "" = the │ │428 -// first window) within `identity` ("owner/name"). the other column resets to │ │428 +// first window) within `identity` ("owner:name"). the other column resets to │ │429 // its first window. │ │430 fn windowLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, kind: ui.RoutablePage.RefKind, name: []const u8, search: []const u8) ![]const u8 {│ │431 const encoded = try ui.urlEncodeRef(page_arena.allocator(), name); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │436 } │ │437 │ │438 // the "a:" link to the files tab at ref `name` (a branch or tag) within │ │439 -// `identity` ("owner/name"), at its root directory. the name is percent-encoded │ │439 +// `identity` ("owner:name"), at its root directory. the name is percent-encoded │ │440 // since it can contain a '/'. │ │441 fn refLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, kind: ui.RoutablePage.RefKind, name: []const u8) ![]const u8 {│ │442 const aa = page_arena.allocator(); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/ui/Repo/Settings.zig│ ╰────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │202 const owner_id = actor.repo_user_id orelse return error.NotFound; │ │203 try evt.updateRepo(io, allocator, users_dir, &owner_id, actor.author, parsed.name, name, description, access); │ │204 var buf: [ui.RoutablePage.repo_route_max_len]u8 = undefined; │ │205 - const new_identity = std.fmt.bufPrint(&buf, "{s}/{s}", .{ parsed.owner, name }) catch return error.RouteTooLong;│ │205 + const new_identity = std.fmt.bufPrint(&buf, "{s}:{s}", .{ parsed.owner, name }) catch return error.RouteTooLong;│ │206 return ui.RoutablePage.repoRepoRoute(new_identity) orelse error.RouteTooLong; │ │207 } │ │208 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │212 const aa = item_arena.allocator(); │ │213 var items: std.ArrayList(ui.widget.FlowBox.Item) = .empty; │ │214 if (data.forks_start > 0) │ │215 - try items.append(aa, .{ .text = "← previous", .link = try std.fmt.allocPrint(aa, "a:/user/{s}/forks/start:{d}", .{ data.user.name, data.forks_start -| page_size }) });│ │215 + try items.append(aa, .{ .text = "← previous", .link = try std.fmt.allocPrint(aa, "a:/{s}/forks/start:{d}", .{ data.user.name, data.forks_start -| page_size }) }); │ │216 for (data.forks) |fork_item| { │ │217 // the fork route names the forker │ │218 - const identity = try std.fmt.allocPrint(aa, "{s}/{s}", .{ data.user.name, fork_item.target.name }); │ │218 + const identity = try std.fmt.allocPrint(aa, "{s}:{s}", .{ data.user.name, fork_item.target.name }); │ │219 const route = ui.RoutablePage.forkPatchRoute(identity, fork_item.id) orelse return error.RouteTooLong; │ │220 try items.append(aa, .{ │ │221 .text = try std.fmt.allocPrint(aa, "{s} - {s}", .{ fork_item.target.name, fork_item.title }), │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │224 }); │ │225 } │ │226 if (data.forks_next_start) |next_start| │ │227 - try items.append(aa, .{ .text = "next →", .link = try std.fmt.allocPrint(aa, "a:/user/{s}/forks/start:{d}", .{ data.user.name, next_start }) });│ │227 + try items.append(aa, .{ .text = "next →", .link = try std.fmt.allocPrint(aa, "a:/{s}/forks/start:{d}", .{ data.user.name, next_start }) }); │ │228 try list.setItems(allocator, items.items); │ │229 try stack.children.put(allocator, list.getFocus().id, .{ .flow_box_scroll = list }); │ │230 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │401 } │ │402 for (data.repos) |repo| │ │403 // clicking a repo opens its page; the "a:" prefix makes the web │ │404 - // renderer emit an <a href="/repo/alice/foo"> anchor. │ │404 + // renderer emit an <a href="/alice:foo"> anchor. │ │405 try items.append(aa, .{ │ │406 .text = if (repo.event.description.len == 0) repo.event.name else try std.fmt.allocPrint(aa, "{s} - {s}", .{ repo.event.name, repo.event.description }),│ │407 - .link = try std.fmt.allocPrint(aa, "a:/repo/{s}/{s}", .{ data.user.name, repo.event.name }), │ │407 + .link = try std.fmt.allocPrint(aa, "a:/{s}:{s}", .{ data.user.name, repo.event.name }), │ │408 .bottom_label = if (repo.event.read_access == .private) "(private)" else "", │ │409 }); │ │410 if (data.repos_next_start) |next_start| { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/User/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const ui = @import("../../ui.zig"); │ │3 +const evt = @import("../../event.zig");│ │4 const inp = @import("../input.zig"); │ │5 const xit = @import("xit"); │ │6 const xitui = xit.xitui; │ ╰──────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 97 // tabs (the page already holds every tab's content), while the href is │ │ 98 // still followed with js off. allocated in the page arena so the focus │ │ 99 // kinds that borrow them live as long as this page's widget tree. │ │ 99 - const aa = session.page_arena.allocator(); │ │100 const current_page = session.data.current_page; │ │101 const current_tag = std.meta.activeTag(current_page); │ │102 - const current_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try current_page.toUrl(session.page_arena)}); │ │103 - const repos_link = if (current_tag == .user_repos) current_link else try std.fmt.allocPrint(aa, "ai:/user/{s}", .{data.name}); │ │104 - const forks_link = if (current_tag == .user_forks) current_link else try std.fmt.allocPrint(aa, "ai:/user/{s}/forks", .{data.name}); │ │105 - const new_repo_link = if (current_tag == .user_repo_new) current_link else try std.fmt.allocPrint(aa, "ai:/user/{s}/repo/new", .{data.name});│ │106 - const new_user_link = if (current_tag == .user_user_new) current_link else try std.fmt.allocPrint(aa, "ai:/user/{s}/user/new", .{data.name});│ │107 - const user_link = if (current_tag == .user_user) current_link else try std.fmt.allocPrint(aa, "ai:/user/{s}/user", .{data.name}); │ │102 + const name = ui.RoutablePage.Array(evt.User.name_max_len).from(data.name) orelse return error.RouteTooLong; │ │103 + const repos_link = try ui.inPageTabLink(session, .{ .user_repos = .{ .name = name } }, current_tag == .user_repos); │ │104 + const forks_link = try ui.inPageTabLink(session, .{ .user_forks = .{ .name = name } }, current_tag == .user_forks); │ │105 + const new_repo_link = try ui.inPageTabLink(session, .{ .user_repo_new = name }, current_tag == .user_repo_new); │ │106 + const new_user_link = try ui.inPageTabLink(session, .{ .user_user_new = name }, current_tag == .user_user_new); │ │107 + const user_link = try ui.inPageTabLink(session, .{ .user_user = name }, current_tag == .user_user); │ │108 │ │109 // the tab matching the current page is focused initially; matching by │ │110 // link (rather than position) keeps this robust to tab changes. │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/ui/widget.zig│ ╰─────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │256 .fork => unreachable, │ │257 }; │ │258 const aa = session.page_arena.allocator(); │ │259 - const url = try std.fmt.allocPrint(aa, "ssh://localhost:{d}/repo/{s}", .{ port, identity });│ │259 + const url = try std.fmt.allocPrint(aa, "ssh://localhost:{d}/{s}", .{ port, identity }); │ │260 break :blk try CopyableText.init(allocator, session, &.{.{ │ │261 .text = url, │ │262 .copyable_text = try std.fmt.allocPrint(aa, "git remote add origin {s}", .{url}), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1927 switch (handle.location) { │ │1928 .repo => |identity| { │ │1929 if (session.data.git_http_port) |port| { │ │1930 - const url = try std.fmt.allocPrint(aa, "http://localhost:{d}/repo/{s}", .{ port, identity });│ │1930 + const url = try std.fmt.allocPrint(aa, "http://localhost:{d}/{s}", .{ port, identity }); │ │1931 choices[count] = .{ │ │1932 .selector = "http", │ │1933 .text = url, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯