╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │ 94 + │ │ 95 + // the walk root's message replaces its diff, so it's read whole and its │ │ 96 + // hunks aren't rendered. the window and the filter are its diff's. │ │ 97 + const root_message = std.meta.activeTag(content) == .message; │ │ 98 + const root_start: usize = switch (content) { │ │ 99 + .diff => |d| d.start, │ │100 + .message => 0, │ │101 + }; │ │102 + const root_path: []const u8 = switch (content) { │ │103 + .diff => |d| d.path.slice(), │ │104 + .message => "", │ │105 + }; │ │106 │ │107 // resolve the requested ref (or the default branch) to the commit oid to│ │108 // walk from. an explicitly named ref that doesn't resolve is a bad url │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │109 // (NotFound -> 404); the default-branch path falls through to empty. │ │110 const resolved = (try ui.ResolvedRefOrOid(repo_kind, repo_opts).init(repo, io, aa, requested_ref_or_oid, requested_value)) orelse {│ │111 if (requested_ref_or_oid != null) return error.NotFound; │ │ 86 - return emptyResult(aa, identity, .branch, requested_value, path); │ │112 + return emptyResult(aa, identity, .branch, requested_value, content); │ │113 }; │ │114 var start_arr = [1][hex_len]u8{resolved.oid}; │ │115 const start_oids: []const [hex_len]u8 = start_arr[0..1]; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │122 var count: usize = 0; │ │123 var next_start: ?[]const u8 = null; │ │124 { │ │ 99 - var iter = repo.log(io, gpa, start_oids) catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, path); │ │125 + var iter = repo.log(io, gpa, start_oids) catch return emptyResult(aa, identity, resolved.ref_or_oid, resolved.value, content);│ │126 defer iter.deinit(); │ │127 while (try iter.next(gpa)) |commit_object| { │ │128 defer commit_object.deinit(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │132 } │ │133 const md = commit_object.content.commit.metadata; │ │134 @memcpy(&oids[count], &commit_object.oid); │ │135 + // only the message the pane shows is read past the log's limit. │ │136 + const text, const truncated = try readMessage(repo_kind, repo_opts, aa, commit_object, if (root_message and count == 0) max_full_message_size else max_message_size);│ │137 buf[count] = .{ │ │138 .oid = try aa.dupe(u8, &commit_object.oid), │ │139 .date = try formatDate(aa, md.timestamp), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │112 - .message = try readMessage(repo_kind, repo_opts, aa, commit_object),│ │140 + .message = text, │ │141 + .message_truncated = truncated, │ │142 .hunks = &.{}, │ │143 .window_start = 0, │ │144 .has_prev = false, │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │153 // renders from the snapshot), so gate it out of the wasm build. │ │154 if (!builtin.cpu.arch.isWasm()) { │ │155 for (buf[0..count], oids[0..count], 0..) |*commit, oid, i| { │ │127 - // the selected commit (the first, == start_oid) shows the window the │ │128 - // url asks for; the rest show their first window. │ │129 - // the path filter only applies to the top commit (the walk root). │ │130 - const window_start = if (i == 0) start else 0; │ │131 - const rendered = renderCommitDiff(repo_kind, repo_opts, io, gpa, aa, repo, oid, window_start, diff_page, if (i == 0) path else "") catch │ │156 + if (root_message and i == 0) continue; │ │157 + // the walk root shows the window the url asks for and its filter; │ │158 + // the rest show their first window, unfiltered. │ │159 + const window_start = if (i == 0) root_start else 0; │ │160 + const rendered = renderCommitDiff(repo_kind, repo_opts, io, gpa, aa, repo, oid, window_start, diff_page, if (i == 0) root_path else "") catch│ │161 RenderedDiff{ .hunks = &.{}, .has_prev = false, .has_more = false }; │ │162 commit.hunks = rendered.hunks; │ │163 commit.window_start = window_start; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │170 .identity = try aa.dupe(u8, identity), │ │171 .ref_or_oid = resolved.ref_or_oid, │ │172 .ref_or_oid_value = resolved.value, │ │144 - .path = try aa.dupe(u8, path), │ │173 .commits = try aa.dupe(Commit, buf[0..count]), │ │174 .next_start = next_start, │ │175 + .content = try pageContent(aa, content), │ │176 .header = try Header.init(aa, resolved.ref_or_oid, resolved.value),│ │177 }; │ │178 } │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │179 │ │180 // an empty listing pinned to a ref, for the wasm / no-repo / unresolved paths. │ │152 -pub fn emptyResult(aa: std.mem.Allocator, identity: []const u8, ref_or_oid: ui.RoutablePage.RefOrOid, value: []const u8, path: []const u8) !Self { │ │181 +pub fn emptyResult(aa: std.mem.Allocator, identity: []const u8, ref_or_oid: ui.RoutablePage.RefOrOid, value: []const u8, content: ui.RoutablePage.RepoCommitsRoute.Content) !Self {│ │182 return .{ │ │183 .identity = try aa.dupe(u8, identity), │ │184 .ref_or_oid = ref_or_oid, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │185 .ref_or_oid_value = try aa.dupe(u8, value), │ │157 - .path = try aa.dupe(u8, path), │ │186 .commits = &.{}, │ │187 .next_start = null, │ │188 + .content = try pageContent(aa, content), │ │189 .header = try Header.init(aa, ref_or_oid, value), │ │190 + }; │ │191 +} │ │192 + │ │193 +// the page's content for a route's, duped into `aa`. the diff window doesn't │ │194 +// carry over: each commit holds the one its pane shows as `window_start`. │ │195 +fn pageContent(aa: std.mem.Allocator, content: ui.RoutablePage.RepoCommitsRoute.Content) !Content {│ │196 + return switch (content) { │ │197 + .diff => |d| .{ .diff = .{ .path = try aa.dupe(u8, d.path.slice()) } }, │ │198 + .message => .message, │ │199 }; │ │200 } │ │201 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │339 }); │ │340 } │ │341 │ │304 -// the whole commit message, trimmed and duped into `aa`. an oversized │ │305 -// message falls back to that first line. │ │342 +// the commit message, trimmed and read into `aa`, plus whether it ran past│ │343 +// `limit` and was cut short there. │ │344 fn readMessage( │ │345 comptime repo_kind: rp.RepoKind, │ │346 comptime repo_opts: rp.RepoOpts(repo_kind), │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯