╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────╮ │13 const Focus = xitui.focus.Focus; │ │14 const inp = @import("../input.zig"); │ │15 const diff3 = @import("../../diff3.zig"); │ │16 -const Comments = @import("Comments.zig"); │ │16 +const Comment = @import("Comment.zig"); │ │17 │ │18 const wasm = builtin.target.cpu.arch == .wasm32;│ │19 │ ╰────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────╮ │36 author: ui.Author = .unknown, │ │37 // whether the issue has an unresolved merge conflict │ │38 conflicted: bool = false, │ │39 - comments: Comments.Window = .empty, │ │39 + comments: Comment.Window = .empty, │ │40 }; │ │41 │ │42 // one side of a conflicted field: its value and who set it│ ╰───────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │84 // the hex event id of the issue its status's window is rooted at ("" = the│ │85 // first window), mirrored into the url. │ │86 selected_id: []const u8, │ │87 +// the comment shown in the selected issue's detail pane. │ │88 +comment_id: []const u8, │ │89 // the selected issue's comment window (0 = the first window). │ │90 comments_start: usize, │ │91 +// the selected comment and its immediate replies. │ │92 +comment_page: ?Comment.Permalink = null, │ │93 open: Window, │ │94 closed: Window, │ │95 // the conflicted issues' listing; its count also gates the conflicts tab. │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │142 } │ │143 │ │144 // an empty listing, for the wasm / no-repo paths. │ │141 -pub fn emptyResult(aa: std.mem.Allocator, identity: []const u8, tag: []const u8, selected_id: []const u8, comments_start: usize, theirs_picks: []const u8, view: ui.RoutablePage.IssuesView) !Self { │ │145 +pub fn emptyResult(aa: std.mem.Allocator, identity: []const u8, tag: []const u8, selected_id: []const u8, comment_id: []const u8, comments_start: usize, theirs_picks: []const u8, view: ui.RoutablePage.IssuesView) !Self {│ │146 return .{ │ │147 .identity = try aa.dupe(u8, identity), │ │148 .tag = try aa.dupe(u8, tag), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────╮ │149 .selected_id = try aa.dupe(u8, selected_id),│ │150 + .comment_id = try aa.dupe(u8, comment_id), │ │151 .comments_start = comments_start, │ │152 .open = .empty, │ │153 .closed = .empty, │ ╰─────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────╮ │182 identity: []const u8, │ │183 tag: []const u8, │ │184 selected_id: []const u8, │ │185 + comment_id: []const u8, │ │186 comments_start: usize, │ │187 theirs_picks: []const u8, │ │188 view: ui.RoutablePage.IssuesView,│ ╰──────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │189 ) !Self { │ │184 - const empty = try emptyResult(arena.allocator(), identity, tag, selected_id, comments_start, theirs_picks, view); │ │190 + const empty = try emptyResult(arena.allocator(), identity, tag, selected_id, comment_id, comments_start, theirs_picks, view);│ │191 │ │192 const aa = arena.allocator(); │ │193 const DB = evt.EventDB(repo_opts.hash); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │302 } │ │303 } │ │304 │ │299 - const open_window = try loadWindow(repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_issue, open_set, open_root, conflict_set, empty.selected_id, comments_start); │ │300 - const closed_window = try loadWindow(repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_issue, closed_set, closed_root, conflict_set, empty.selected_id, comments_start); │ │301 - const conflicts_window = try loadWindow(repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_issue, conflict_set, conflicts_root, conflict_set, empty.selected_id, comments_start); │ │305 + const thread_comments_start = if (empty.comment_id.len == 0) comments_start else 0; │ │306 + const open_window = try loadWindow(repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_issue, open_set, open_root, conflict_set, empty.selected_id, thread_comments_start); │ │307 + const closed_window = try loadWindow(repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_issue, closed_set, closed_root, conflict_set, empty.selected_id, thread_comments_start); │ │308 + const conflicts_window = try loadWindow(repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_issue, conflict_set, conflicts_root, conflict_set, empty.selected_id, thread_comments_start);│ │309 if (view == .conflicts and conflicts_window.count > 0) resolved_view = .conflicts; │ │310 + │ │311 + const comment_page = if (empty.comment_id.len == 0) │ │312 + null │ │313 + else │ │314 + try Comment.init(repo_opts.hash, arena, admin_moment, haxy_moment, empty.selected_id, empty.comment_id, comments_start); │ │315 │ │316 // every tag in the repo, in the tag map's sorted order. the keys are │ │317 // "tag,status", so a tag's entries are adjacent and dedup by prefix. │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────╮ │337 .identity = empty.identity, │ │338 .tag = empty.tag, │ │339 .selected_id = empty.selected_id,│ │340 + .comment_id = empty.comment_id, │ │341 .comments_start = comments_start,│ │342 + .comment_page = comment_page, │ │343 .open = open_window, │ │344 .closed = closed_window, │ │345 .conflicts = conflicts_window, │ ╰──────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │434 .issue = issue_event, │ │435 .author = try ui.Author.initFromEmail(admin_moment, arena, issue_event.author_email),│ │436 .conflicted = if (conflict_set) |cs| try cs.contains(&order_key) else false, │ │423 - .comments = try Comments.loadWindow( │ │437 + .comments = try Comment.loadWindow( │ │438 hash_kind, │ │439 arena, │ │440 admin_moment, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯