╭ changed ──────────────╮ │src/ui/Repo/Patches.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────╮ │ 6 const rp = xit.repo; │ │ 7 const hash = xit.hash; │ │ 8 const rf = xit.ref; │ │ 9 +const xitui = xit.xitui; │ │10 +const wgt = xitui.widget; │ │11 const diff3 = @import("../../diff3.zig"); │ │12 const Comment = @import("Comment.zig"); │ │13 const Attachment = @import("Attachment.zig");│ ╰─────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │128 pub const Event = evt.Patch; │ │129 pub const Status = evt.Patch.Status; │ │130 pub const ViewKind = ui.RoutablePage.PatchesView; │ │131 +pub const thread_name = "patch"; │ │132 +pub const header_widget_name = "repo_patches_header"; │ │133 + │ │134 +pub fn listRoute(identity: []const u8, status: Status, tag: []const u8, selected: []const u8) ?ui.RoutablePage {│ │135 + return ui.RoutablePage.repoPatchesRoute(identity, status, tag, selected); │ │136 +} │ │137 + │ │138 +pub fn draftsRoute(identity: []const u8) ?ui.RoutablePage { │ │139 + return ui.RoutablePage.repoPatchesDraftsRoute(identity); │ │140 +} │ │141 + │ │142 +pub fn conflictsRoute(identity: []const u8, selected: []const u8) ?ui.RoutablePage { │ │143 + return ui.RoutablePage.repoPatchesConflictsRoute(identity, selected); │ │144 +} │ │145 │ │146 +pub fn resolveRoute(identity: []const u8, selected: []const u8, picks: []const u8) ?ui.RoutablePage { │ │147 + return ui.RoutablePage.repoPatchesResolveRoute(identity, selected, picks); │ │148 +} │ │149 + │ │150 pub fn createDraft( │ │151 data: *const Self, │ │152 session: *ui.Session, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │567 │ │568 pub const Header = Threads.Header; │ │569 │ │550 -pub fn cloneDirectoryName(allocator: std.mem.Allocator, title: []const u8) ![]const u8 { │ │570 +pub fn appendDraftDetails(self: *const Self, allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), session: *ui.Session, entry: Entry) !void { │ │571 + const aa = session.page_arena.allocator(); │ │572 + var fields: [2]ui.CopyableText.Choice = undefined; │ │573 + var field_count: usize = 0; │ │574 + │ │575 + if (entry.target_branch.len != 0) if (session.data.git_ssh_port) |port| { │ │576 + const url = try std.fmt.allocPrint(aa, "ssh://localhost:{d}/repo/{s}/patch:{s}/branch:{s}", .{ port, self.identity, entry.id, entry.target_branch }); │ │577 + const push_command = try std.fmt.allocPrint(aa, "git push {s} HEAD:patch", .{url}); │ │578 + const clone_name = try cloneDirectoryName(aa, entry.record.event.title); │ │579 + const clone_command = if (clone_name.len == 0) │ │580 + try std.fmt.allocPrint(aa, "git clone {s}", .{url}) │ │581 + else │ │582 + try std.fmt.allocPrint(aa, "git clone {s} {s}", .{ url, clone_name }); │ │583 + const choices: [2]ui.CopyableText.Choice = .{ │ │584 + .{ │ │585 + .selector = "push", │ │586 + .text = push_command, │ │587 + .copyable_text = try std.fmt.allocPrint(aa, "{s}{s}", .{ session.data.git_ssh_prefix, push_command }), │ │588 + .label = " push to this patch from existing repo ", │ │589 + }, │ │590 + .{ │ │591 + .selector = "clone", │ │592 + .text = clone_command, │ │593 + .copyable_text = try std.fmt.allocPrint(aa, "{s}{s}", .{ session.data.git_ssh_prefix, clone_command }), │ │594 + .label = " clone this patch ", │ │595 + }, │ │596 + }; │ │597 + var copyable_text = try ui.CopyableText.View.init(allocator, session, &choices); │ │598 + errdefer copyable_text.deinit(allocator); │ │599 + try box.children.put(allocator, copyable_text.getFocus().id, .{ .widget = .{ .copyable_text = copyable_text }, .rect = null, .min_size = null }); │ │600 + try addDetailGap(allocator, box); │ │601 + }; │ │602 + if (entry.fork_oid.len != 0) { │ │603 + fields[field_count] = .{ │ │604 + .text = entry.fork_oid, │ │605 + .label = if (entry.no_changes) " object id of this patch (no changes) " else " object id of this patch ", │ │606 + }; │ │607 + field_count += 1; │ │608 + } │ │609 + if (entry.target_branch.len != 0) { │ │610 + fields[field_count] = .{ │ │611 + .text = entry.target_branch, │ │612 + .label = " target branch this patch will go to ", │ │613 + .bottom_label = " (set by the url you push to above) ", │ │614 + }; │ │615 + field_count += 1; │ │616 + } │ │617 + │ │618 + for (fields[0..field_count], 0..) |field, i| { │ │619 + var copyable_text = try ui.CopyableText.View.init(allocator, session, &.{field}); │ │620 + errdefer copyable_text.deinit(allocator); │ │621 + try box.children.put(allocator, copyable_text.getFocus().id, .{ .widget = .{ .copyable_text = copyable_text }, .rect = null, .min_size = null }); │ │622 + if (i + 1 < field_count) try addDetailGap(allocator, box); │ │623 + } │ │624 + if (entry.target_branch.len != 0) try addDetailGap(allocator, box); │ │625 +} │ │626 + │ │627 +fn addDetailGap(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget)) !void { │ │628 + var spacer = try ui.Spacer.init(allocator); │ │629 + errdefer spacer.deinit(allocator); │ │630 + try box.children.put(allocator, spacer.getFocus().id, .{ .widget = .{ .spacer = spacer }, .rect = null, .min_size = .{ .width = null, .height = 1 }, .max_size = .{ .width = null, .height = 1 } });│ │631 +} │ │632 + │ │633 +fn cloneDirectoryName(allocator: std.mem.Allocator, title: []const u8) ![]const u8 { │ │634 var name: [64]u8 = undefined; │ │635 var len: usize = 0; │ │636 var pending: ?u8 = null; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯