╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────────╮ │src/test/undo.zig│ ╰─────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │120 session.io = io; │ │121 session.users_dir = users_dir; │ │122 - try Undo.perform(allocator, &session, ui.RoutablePage.repoUndoRoute("alice/demo", 2).?.repo_undo);│ │122 + try Undo.perform(allocator, &session, ui.RoutablePage.repoUndoRoute("alice:demo", 2).?.repo_undo);│ │123 try std.testing.expectEqual(null, session.next_page.?.repo_undo.index); │ │124 { │ │125 var repo = try xit.repo.Repo(.xit, .{}).open(io, allocator, .{ .path = path }); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │126 defer repo.deinit(io, allocator); │ │127 try expectConfig(&repo, "first"); │ │128 - const data = try Undo.init(.{}, &arena, &repo, null, "alice/demo", null, .{ .location = .{ .repo = "" } });│ │128 + const data = try Undo.init(.{}, &arena, &repo, null, "alice:demo", null, .{ .location = .{ .repo = "" } });│ │129 try std.testing.expectEqualStrings("undo", data.items[0].action); │ │130 } │ │131 // keep the old session/page moment, but transfer ownership to the writer. │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │132 repo_event.user_id = &writer; │ │133 try evt.consume(.{ .server = .{ .users_dir = users_dir } }, .user, .xit, evt.user_repo_opts, io, allocator, &user_repo, evt.events_ref, &.{.{ .id = std.fmt.bytesToHex(repo_id, .lower), .author = author, .event = .{ .repo = repo_event } }});│ │134 session.next_page = null; │ │135 - Undo.handleRequest(allocator, &session, ui.RoutablePage.repoUndoRoute("alice/demo", 1).?.repo_undo); │ │135 + Undo.handleRequest(allocator, &session, ui.RoutablePage.repoUndoRoute("alice:demo", 1).?.repo_undo); │ │136 try std.testing.expectEqualStrings("Forbidden", session.data.undo_failure.?); │ │137 try std.testing.expectEqual(null, session.next_page); │ │138 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │143 var anonymous = try ui.Session.init(&arena, &admin, .{}); │ │144 anonymous.io = io; │ │145 anonymous.users_dir = users_dir; │ │146 - try std.testing.expectError(error.NotFound, ui.Repo.init(&arena, &anonymous, ui.RoutablePage.repoUndoRoute("alice/demo", null).?));│ │146 + try std.testing.expectError(error.NotFound, ui.Repo.init(&arena, &anonymous, ui.RoutablePage.repoUndoRoute("alice:demo", null).?));│ │147 } │ │148 │ │149 test "local git has no undo and local xit can undo and refresh" { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │942 \\ echo "hello" > hello.txt │ │943 \\ git add hello.txt │ │944 \\ git commit -m "let there be light" │ │945 - \\ GIT_SSH_COMMAND='ssh -p {d} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -i {s}' git push localhost:admin/test HEAD:master│ │945 + \\ GIT_SSH_COMMAND='ssh -p {d} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -i {s}' git push localhost:admin:test HEAD:master│ │946 \\ │ │947 \\to quit, press enter. │ │948 \\ │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────╮ │300 search: Array(search_route_max_len) = .{}, │ │301 }; │ │302 │ │303 - const user_segment = "/user/"; │ │304 - const repo_segment = "/repo/"; │ │305 - const fork_segment = "/fork/"; │ │303 + const home_segment = "home"; │ │304 const files_seg = "files"; │ │305 const commits_seg = "commits"; │ │306 // ends a commits route naming its commit's full message│ ╰─────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │323 // remainder of the url, so it must come last │ │324 const path_seg = "path:"; │ │325 │ │328 - // a repo route is "username/reponame", optionally followed by the files │ │326 + // a repo route is "username:reponame", optionally followed by the files │ │327 // tab's "/files/<refkind>:<refvalue>[/line:<n>][/path:<dir>]"; the bare │ │328 // pair means the default branch's files root. a local session's routes │ │329 // elide the identity: "" at the bare root, else starting at the tail's "/".│ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │355 │ │356 // the identity stored by every repo route. Local routes elide it.│ │357 pub const RepoIdentity = struct { │ │360 - identity: []const u8, // "owner/name" │ │358 + identity: []const u8, // "owner:name" │ │359 owner: []const u8, │ │360 name: []const u8, │ │361 │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │365 .owner = "", │ │366 .name = "", │ │367 }; │ │370 - if (identityElided(s)) { │ │371 - return result; │ │372 - } else { │ │373 - var id_segments = std.mem.splitScalar(u8, s, '/'); │ │374 - const owner = id_segments.next() orelse return null; │ │375 - const name = id_segments.next() orelse return null; │ │376 - if (owner.len == 0 or name.len == 0) return null; │ │377 - result.identity = s[0 .. owner.len + 1 + name.len]; │ │378 - result.owner = owner; │ │379 - result.name = name; │ │380 - } │ │368 + if (identityElided(s)) return result; │ │369 + const parsed = evt.parseOwnerRepoPath(s) orelse return null;│ │370 + result.identity = s; │ │371 + result.owner = parsed.owner; │ │372 + result.name = parsed.name; │ │373 return result; │ │374 } │ │375 }; │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │771 } }; │ │772 } │ │773 │ │782 - // build a `.repo_issues` route for "owner/name" (identity) showing │ │774 + // build a `.repo_issues` route for "owner:name" (identity) showing │ │775 // `status`'s list, filtered to the url-encoded `label` ("" = unfiltered) and │ │776 // rooted at the issue with hex event id `selected` ("" = the first window). │ │777 pub fn repoIssuesRoute(identity: []const u8, status: evt.Issue.Status, label: []const u8, selected: []const u8) ?RoutablePage {│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯