╭ changed ───────────╮ │src/ui/Repo/Diff.zig│ ╰────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────╮ │1 const std = @import("std"); │ │2 +const evt = @import("../../event.zig");│ │3 const ui = @import("../../ui.zig"); │ │4 const xit = @import("xit"); │ │5 const rp = xit.repo; │ ╰──────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │29 │ │30 pub const Route = union(enum) { │ │31 commit: struct { location: ui.RoutablePage.RepoLocation, oid: []const u8, base_oid: []const u8 = "" }, │ │32 + repo: struct { identity: []const u8, ref_or_oid: ui.RoutablePage.RefOrOid, value: []const u8, base_oid: []const u8 },│ │33 + patchrev: struct { identity: []const u8, id: []const u8 }, │ │34 fork: struct { identity: []const u8, id: []const u8 }, │ │35 │ │33 - fn link(self: Route, arena: *std.heap.ArenaAllocator, start: usize, path: []const u8) ![]const u8 { │ │34 - const route = switch (self) { │ │36 + pub fn page(self: Route, start: usize, path: []const u8) ?ui.RoutablePage { │ │37 + return switch (self) { │ │38 .commit => |c| c.location.commitsRoute(.object, c.oid, start, path, c.base_oid), │ │39 + .repo => |r| ui.RoutablePage.repoDiffRoute(r.identity, r.ref_or_oid, r.value, start, path, r.base_oid), │ │40 + .patchrev => |r| ui.RoutablePage.repoPatchRevDiffRoute(r.identity, r.id, start, path), │ │41 .fork => |f| ui.RoutablePage.forkDiffRoute(f.identity, f.id, start, path), │ │37 - } orelse return error.RouteTooLong; │ │42 + }; │ │43 + } │ │44 + │ │45 + fn link(self: Route, arena: *std.heap.ArenaAllocator, start: usize, path: []const u8) ![]const u8 { │ │46 + const route = self.page(start, path) orelse return error.RouteTooLong; │ │47 return std.fmt.allocPrint(arena.allocator(), "a:{s}", .{try route.toUrl(arena)}); │ │48 } │ │49 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 50 │ │ 42 -// render a window of the net diff between two commits │ │ 51 +pub fn init( │ │ 52 + comptime repo_kind: rp.RepoKind, │ │ 53 + comptime repo_opts: rp.RepoOpts(repo_kind), │ │ 54 + arena: *std.heap.ArenaAllocator, │ │ 55 + repo: *rp.Repo(repo_kind, repo_opts), │ │ 56 + io: std.Io, │ │ 57 + gpa: std.mem.Allocator, │ │ 58 + route: ui.RoutablePage.RepoDiffRoute, │ │ 59 +) !Self { │ │ 60 + const aa = arena.allocator(); │ │ 61 + const oid_len = comptime xit.hash.hexLen(repo_opts.hash); │ │ 62 + const identity = try aa.dupe(u8, route.name.slice()); │ │ 63 + const base_oid, const head_oid, const diff_route = if (route.patchrev_id.len != 0) blk: { │ │ 64 + const id = evt.parseEventId(route.patchrev_id.slice()) catch return error.NotFound; │ │ 65 + const record = (try evt.readFromRepo(evt.PatchRev, repo_kind, repo_opts, io, gpa, arena, repo, &id)) orelse return error.NotFound; │ │ 66 + if (record.removed) return error.NotFound; │ │ 67 + if (record.base_tree_oid.len != oid_len or record.head_tree_oid.len != oid_len) return error.NotFound; │ │ 68 + break :blk .{ │ │ 69 + record.base_tree_oid[0..oid_len].*, │ │ 70 + record.head_tree_oid[0..oid_len].*, │ │ 71 + Route{ .patchrev = .{ .identity = identity, .id = try aa.dupe(u8, route.patchrev_id.slice()) } }, │ │ 72 + }; │ │ 73 + } else blk: { │ │ 74 + const resolved = (try ui.ResolvedRefOrOid(repo_kind, repo_opts).init(repo, io, aa, route.ref_or_oid, route.value.slice())) orelse return error.NotFound; │ │ 75 + evt.PatchRev.validateOid(repo_opts.hash, &resolved.oid) catch return error.NotFound; │ │ 76 + evt.PatchRev.validateOid(repo_opts.hash, route.base_oid.slice()) catch return error.NotFound; │ │ 77 + │ │ 78 + var moment = try repo.core.latestMoment(); │ │ 79 + const state = rp.Repo(repo_kind, repo_opts).State(.read_only){ .core = &repo.core, .extra = .{ .moment = &moment } }; │ │ 80 + // peel annotated tags before comparing their trees │ │ 81 + var tip = try xit.object.Object(repo_kind, repo_opts).initCommit(state, io, gpa, &resolved.oid); │ │ 82 + defer tip.deinit(); │ │ 83 + break :blk .{ │ │ 84 + route.base_oid.slice()[0..oid_len].*, │ │ 85 + tip.oid, │ │ 86 + Route{ .repo = .{ │ │ 87 + .identity = identity, │ │ 88 + .ref_or_oid = resolved.ref_or_oid, │ │ 89 + .value = resolved.value, │ │ 90 + .base_oid = try aa.dupe(u8, route.base_oid.slice()), │ │ 91 + } }, │ │ 92 + }; │ │ 93 + }; │ │ 94 + const path = try aa.dupe(u8, route.path.slice()); │ │ 95 + return .{ │ │ 96 + .route = diff_route, │ │ 97 + .path = path, │ │ 98 + .window = try render(repo_kind, repo_opts, io, gpa, aa, repo, if (std.mem.allEqual(u8, &base_oid, '0')) null else &base_oid, head_oid, route.start, path),│ │ 99 + }; │ │100 +} │ │101 + │ │102 +// render a window of the net diff between two commits or trees │ │103 pub fn render( │ │104 comptime repo_kind: rp.RepoKind, │ │105 comptime repo_opts: rp.RepoOpts(repo_kind), │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯