╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │467 // js off (the browser follows it, rooting the list there); │ │468 // with wasm the click just selects it and swaps the diff pane. │ │469 const content = if (index == 0) data.content else Content{ .diff = .{} }; │ │438 - try addRow(allocator, &list_box, firstLine(commit.message), try commitRowLink(session.page_arena, data, commit, content)); │ │470 + try addRow(allocator, &list_box, firstLine(commit.message), try commitRowLink(session.page_arena, data, commit, content), if (commit.merge) "(merge)" else "");│ │471 } │ │472 if (data.next_start) |next| { │ │441 - try addRow(allocator, &list_box, "next →", try nextPageLink(session.page_arena, data, next)); │ │473 + try addRow(allocator, &list_box, "next →", try nextPageLink(session.page_arena, data, next), ""); │ │474 } │ │475 if (list_box.children.count() > 0) list_box.getFocus().child_id = list_box.children.keys()[0]; │ │476 break :blk try wgt.Scroll(ui.Widget).init(allocator, .{ .box = list_box }, .{ .direction = .vert, .web_native = !session.is_terminal, .fill = true }); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │514 }; │ │515 } │ │516 │ │485 - fn addRow(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, link: []const u8) !void { │ │486 - var row = try wgt.TextBox.init(allocator, label, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word }); │ │517 + fn addRow(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, link: []const u8, bottom_label: []const u8) !void { │ │518 + var row = try wgt.TextBox.init(allocator, label, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word, .bottom_label = bottom_label });│ │519 errdefer row.deinit(allocator); │ │520 row.getFocus().mode = .all; │ │521 if (link.len != 0) row.getFocus().kind = .{ .custom = link }; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │522 try box.children.put(allocator, row.getFocus().id, .{ .widget = .{ .text_box = row }, .rect = null, .min_size = null, .max_size = .{ .width = null, .height = 5 } });│ │523 } │ │524 │ │493 - // a focusable window-navigation row ("previous"/"next"). it's a link to this │ │494 - // commit's route at `target_start`, so activating it (the host follows the │ │495 - // "a:" link) reloads the page on the adjacent window — same on TUI and web. │ │496 - fn addNavLink(self: *View, allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, oid: []const u8, target_start: usize, path: []const u8) !void { │ │497 - const link = try commitsLink(self.session.page_arena, self.data, oid, target_start, path); │ │525 + // a focusable row following the "a:" `link`. │ │526 + fn addLink(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, link: []const u8) !void { │ │527 var tb = try wgt.TextBox.init(allocator, label, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); │ │499 - errdefer tb.deinit(allocator); │ │500 - tb.getFocus().mode = .all; │ │501 - tb.getFocus().kind = .{ .custom = link }; │ │502 - try box.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │503 - } │ │504 - │ │505 - // a focusable row for the top of the diff pane linking to the files tab at │ │506 - // this commit's tree, so its files are always viewable as of this object. │ │507 - fn addViewFilesLink(self: *View, allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), oid: []const u8) !void { │ │508 - const link = try filesObjectLink(self.session.page_arena, self.data.location, oid); │ │509 - var tb = try wgt.TextBox.init(allocator, "view files at this commit", .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); │ │528 errdefer tb.deinit(allocator); │ │529 tb.getFocus().mode = .all; │ │530 tb.getFocus().kind = .{ .custom = link }; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │684 │ │685 switch (self.paneContent(sel)) { │ │686 .message => { │ │669 - try self.addNavLink(allocator, inner, "← back to diff", commit.oid, 0, ""); │ │687 + try addLink(allocator, inner, "← back to diff", try commitsLink(self.session.page_arena, self.data, commit.oid, 0, ""));│ │688 try self.addMessageBox(allocator, inner, commit, .whole); │ │689 }, │ │690 .diff => |d| { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │713 tb.getFocus().mode = .all; │ │714 try inner.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │715 } │ │716 + if (commit.merge) if (self.data.location.commitsMergeRoute(commit.oid)) |route| { │ │717 + try addLink(allocator, inner, "view commits from this merge", try std.fmt.allocPrint(self.session.page_arena.allocator(), "a:{s}", .{try route.toUrl(self.session.page_arena)}));│ │718 + }; │ │719 if (commit.stats) |stats| { │ │720 var text: std.Io.Writer.Allocating = .init(allocator); │ │721 defer text.deinit(); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │732 tb.getFocus().mode = .all; │ │733 try inner.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │734 } │ │714 - try self.addViewFilesLink(allocator, inner, commit.oid); │ │735 + try addLink(allocator, inner, "view files at this commit", try filesObjectLink(self.session.page_arena, self.data.location, commit.oid));│ │736 } │ │737 │ │738 try (Diff{ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯