╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Patches.zig│ ╰───────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │281 const drafts_window = if (admin_moment) |admin| │ │282 if (repo_id_maybe) |repo_id| │ │283 if (session.data.user_id != null and session.repos_dir != null) │ │280 - try loadDraftWindow(arena, session, admin, &repo_id, empty.selected_id) │ │284 + try loadDraftWindow(repo_kind, repo_opts, arena, session, admin, &repo_id, empty.selected_id, repo, target_branch)│ │285 else │ │286 Window.empty │ │287 else │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────╮ │446 } │ │447 │ │448 fn loadDraftWindow( │ │449 + comptime repo_kind: rp.RepoKind, │ │450 + comptime repo_opts: rp.RepoOpts(repo_kind), │ │451 arena: *std.heap.ArenaAllocator, │ │452 session: *ui.Session, │ │453 admin_moment: evt.AdminDB.HashMap(.read_only),│ ╰───────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────╮ │454 repo_id: *const [evt.event_id_size]u8, │ │455 selected_id: []const u8, │ │456 + target_repo: *rp.Repo(repo_kind, repo_opts), │ │457 + default_target_branch: []const u8, │ │458 ) !Window { │ │459 const user_id = session.data.user_id orelse return .empty;│ │460 if (user_id.len != evt.event_id_size) return .empty; │ ╰───────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │506 const path = try fork.forkPath(aa, repos_dir, &id_hex); │ │507 var fork_repo = rp.Repo(.xit, .{}).open(io, arena.child_allocator, .{ .path = path, .require_repo_root = true }) catch continue;│ │508 defer fork_repo.deinit(io, arena.child_allocator); │ │509 + const fork_oid = (try fork_repo.readRef(io, fork.ref)) orelse continue; │ │510 const moment = evt.currentMoment(.{}, &fork_repo) catch continue; │ │511 const patch = (try evt.Patch.readById(evt.EventDB(.sha1), .sha1, moment, arena, &id)) orelse continue; │ │512 var revision_ready = false; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │513 + var target_branch = default_target_branch; │ │514 if (patch.event.revision) |revision| { │ │515 + const target_ref = rf.Ref.initFromPath(revision.target_ref, null) orelse continue; │ │516 + target_branch = switch (target_ref.kind) { │ │517 + .head => target_ref.name, │ │518 + else => continue, │ │519 + }; │ │520 const revision_id = evt.parseEventId(&revision.id) catch continue; │ │521 if (try evt.PatchRev.readById(evt.EventDB(.sha1), .sha1, moment, arena, &revision_id)) |record|│ │522 revision_ready = revision.matches(record); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │523 } │ │524 + const target_oid = if (target_branch.len != 0) │ │525 + try target_repo.readRef(io, .{ .kind = .head, .name = target_branch })│ │526 + else │ │527 + null; │ │528 try items.append(aa, .{ │ │529 .id = try aa.dupe(u8, &id_hex), │ │530 .record = patch, │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │531 .author = try ui.Author.initFromEmail(admin_moment, arena, patch.author_email), │ │532 .draft = true, │ │533 .revision_ready = revision_ready, │ │534 + .fork_oid = try aa.dupe(u8, &fork_oid), │ │535 + .target_branch = try aa.dupe(u8, target_branch), │ │536 + .no_changes = if (target_oid) |oid| std.mem.eql(u8, &oid, &fork_oid) else false,│ │537 }); │ │538 } │ │539 return .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │547 pub const View = Threads.View(.patch, Self); │ │548 │ │549 pub const Header = Threads.Header; │ │550 + │ │551 +pub fn cloneDirectoryName(allocator: std.mem.Allocator, title: []const u8) ![]const u8 { │ │552 + var name: [64]u8 = undefined; │ │553 + var len: usize = 0; │ │554 + var pending: ?u8 = null; │ │555 + │ │556 + for (title) |char| { │ │557 + if (std.ascii.isAlphanumeric(char)) { │ │558 + const needed: usize = if (pending == null) 1 else 2; │ │559 + if (len + needed > name.len) break; │ │560 + if (pending) |value| { │ │561 + name[len] = value; │ │562 + len += 1; │ │563 + } │ │564 + name[len] = std.ascii.toLower(char); │ │565 + len += 1; │ │566 + pending = null; │ │567 + } else if (char == ' ') { │ │568 + if (len != 0) pending = '-'; │ │569 + } else if (char == '.') { │ │570 + if (len != 0 and pending != '-') pending = '.'; │ │571 + } │ │572 + } │ │573 + if (len == 0) return ""; │ │574 + return allocator.dupe(u8, name[0..len]); │ │575 +} │ │576 │ │577 // tabs switching between the patches page's views │ │578 pub fn initHeader(allocator: std.mem.Allocator, session: *ui.Session, data: *const Self) !Header {│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Threads.zig│ ╰───────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │367 // per-split state, indexed like the stack's split children: the thread the│ │368 // pane shows and its focus ids. │ │369 detailed_index: [view_count]?usize, │ │370 + title_id: [view_count]?usize, │ │371 description_id: [view_count]?usize, │ │372 author_id: [view_count]?usize, │ │373 │ ╰────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────╮ │674 .data = data, │ │675 .session = session, │ │676 .detailed_index = @splat(null),│ │677 + .title_id = @splat(null), │ │678 .description_id = @splat(null),│ │679 .author_id = @splat(null), │ │680 }; │ ╰────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯