╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────╮ │16 pub const Commits = @import("./Repo/Commits.zig"); │ │17 pub const Refs = @import("./Repo/Refs.zig"); │ │18 pub const Issues = @import("./Repo/Issues.zig"); │ │19 +pub const Comments = @import("./Repo/Comments.zig");│ │20 pub const Settings = @import("./Settings.zig"); │ │21 pub const Auth = @import("./Auth.zig"); │ │22 pub const Quit = @import("./Quit.zig"); │ ╰────────────────────────────────────────────────────────╯ ╭────────────────────────╮ │29 commits: Commits, │ │30 refs: Refs, │ │31 issues: Issues, │ │32 +comments: ?Comments,│ │33 settings: Settings, │ │34 auth: Auth, │ │35 quit: Quit, │ ╰────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │117 const issues_view: ui.RoutablePage.IssuesView = switch (route) { │ │118 .repo_issues => |i| i.view, │ │119 else => .open, │ │120 + }; │ │121 + const issues_comments_start: usize = switch (route) { │ │122 + .repo_issues => |i| i.comments_start, │ │123 + else => 0, │ │124 }; │ │125 │ │126 // where the on-disk repo lives (null keeps the views' empty fallback), plus│ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │164 // route named none), so they end up viewing the same one and either's │ │165 // resolved ref can canonicalize the tab mirror urls below. no filesystem │ │166 // (wasm), nowhere to look, or a failed open: empty tabs. │ │161 - const files, const commits, const refs, var issues = blk: { │ │167 + const files, const commits, const refs, var issues, const comments = blk: {│ │168 read: { │ │169 const io = session.io orelse break :read; │ │170 const src = source orelse break :read; │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │177 inline else => |*opened| { │ │178 // local mode: bring the event db up to date with the events branch │ │179 if (session.local != null) try evt.consume(repo_kind, opened.self_repo_opts, io, gpa, opened, evt.events_ref, &.{}); │ │180 + const comments = switch (route) { │ │181 + .repo_comments => |*c| try Comments.initFromRepo(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, c.thread.slice(), c.selected.slice(), c.start),│ │182 + else => null, │ │183 + }; │ │184 break :blk .{ │ │185 try Files.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, repo_identity.identity, requested_ref_or_oid, requested_ref_value, files_dir, files_line), │ │186 try Commits.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, session.haxy_moment, repo_identity.identity, requested_ref_or_oid, requested_ref_value, commits_content), │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │187 try Refs.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, repo_identity.identity, refs_kind, refs_from), │ │178 - try Issues.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, issues_tag, issues_selected, issues_theirs, issues_view), │ │188 + if (comments == null) │ │189 + try Issues.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, issues_tag, issues_selected, issues_comments_start, issues_theirs, issues_view)│ │190 + else │ │191 + try Issues.emptyResult(arena.allocator(), repo_identity.identity, "", "", 0, "", .open), │ │192 + comments, │ │193 }; │ │194 }, │ │195 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │201 try Files.emptyResult(aa, repo_identity.identity, requested_ref_or_oid orelse .branch, requested_ref_value, files_dir), │ │202 try Commits.emptyResult(aa, repo_identity.identity, requested_ref_or_oid orelse .branch, requested_ref_value, commits_content), │ │203 try Refs.emptyResult(arena, repo_identity.identity, refs_kind, refs_from), │ │190 - try Issues.emptyResult(aa, repo_identity.identity, issues_tag, issues_selected, issues_theirs, issues_view), │ │204 + try Issues.emptyResult(aa, repo_identity.identity, issues_tag, issues_selected, issues_comments_start, issues_theirs, issues_view),│ │205 + null, │ │206 }; │ │207 }; │ │208 + if (std.meta.activeTag(route) == .repo_comments and comments == null) return error.NotFound; │ │209 issues.repo_source = source; │ │210 │ │211 // each tab mirror carries this page's route for that tab; tabs not targeted │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────╮ │233 .commits = commits, │ │234 .refs = refs, │ │235 .issues = issues, │ │236 + .comments = comments, │ │237 .settings = Settings.init(),│ │238 .auth = Auth.init(), │ │239 .quit = Quit.init(), │ ╰─────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │288 try stack.children.put(allocator, refs_view.getFocus().id, .{ .repo_refs = refs_view }); │ │289 } │ │290 │ │274 - // issues — the repo's issue tracker. │ │291 + // issues — the repo's issue tracker or a comment permalink. │ │292 { │ │276 - var issues_view = try Issues.View.init(allocator, &data.issues, session); │ │277 - errdefer issues_view.deinit(allocator); │ │278 - try stack.children.put(allocator, issues_view.getFocus().id, .{ .repo_issues = issues_view }); │ │293 + if (data.comments) |*comments| { │ │294 + var comments_view = try Comments.View.init(allocator, comments, session); │ │295 + errdefer comments_view.deinit(allocator); │ │296 + try stack.children.put(allocator, comments_view.getFocus().id, .{ .repo_comments = comments_view });│ │297 + } else { │ │298 + var issues_view = try Issues.View.init(allocator, &data.issues, session); │ │299 + errdefer issues_view.deinit(allocator); │ │300 + try stack.children.put(allocator, issues_view.getFocus().id, .{ .repo_issues = issues_view }); │ │301 + } │ │302 } │ │303 │ │304 // the header only shows the settings tab with a login and the auth │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │354 // the issues tab mirrors this page's tag filter (issue urls │ │355 // themselves never carry the tag). │ │356 .repo_issues => self.session.data.current_page = ui.RoutablePage.repoIssuesRoute(self.data.identity.slice(), .open, self.data.issues.tag, "") orelse self.session.data.current_page,│ │357 + // the comment view mirrors its own content route when built. │ │358 + .repo_comments => {}, │ │359 .home_settings => { │ │360 if (ui.RoutablePage.Array(ui.RoutablePage.repo_route_max_len).from(self.data.identity.slice())) |identity| │ │361 self.session.data.current_page = .{ .repo_settings = identity }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯