╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │371 // the newest commit's message runs past what the detail pane │ │372 // reads, so it shows the truncated message and its link. │ │373 if (c == commit_count - 1) { │ │374 - var line: usize = 0; │ │375 - while (msg_writer.written().len <= ui.Repo.Commits.max_message_size) : (line += 1) { │ │374 + for (0..ui.detail_preview_lines) |line| { │ │375 try msg_writer.writer.print("\n{d} {s}", .{ line, scatter_words[line % scatter_words.len] });│ │376 } │ │377 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │571 // the fifth-newest issue's description runs past what the detail │ │572 // pane shows, so it shows the truncated description and its │ │573 // link. │ │575 - const description = if (i == issue_data.len - 5) desc: { │ │576 - var desc_writer = std.Io.Writer.Allocating.init(allocator); │ │577 - defer desc_writer.deinit(); │ │578 - try desc_writer.writer.print("{s}", .{issue.description}); │ │579 - var line: usize = 0; │ │580 - while (desc_writer.written().len <= ui.Repo.Issues.max_description_size) : (line += 1) { │ │581 - try desc_writer.writer.print("\n{d} {s}", .{ line, scatter_words[line % scatter_words.len] });│ │582 - } │ │583 - break :desc try arena.allocator().dupe(u8, desc_writer.written()); │ │584 - } else issue.description; │ │574 + const description = if (i == issue_data.len - 5) │ │575 + try longDescription(arena.allocator(), issue.description) │ │576 + else │ │577 + issue.description; │ │578 issue_events[i] = .{ │ │579 .id = std.fmt.bytesToHex(evt.EventWithId.randomId(prng.random()), .lower), │ │580 // stepped timestamps so the issues list in a stable order │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │932 "falcon", "otter", "badger", "walrus", "ferret", "marmot", │ │933 "scatter", "gather", "encode", "decode", "render", "commit", │ │934 }; │ │935 + │ │936 +fn longDescription(allocator: std.mem.Allocator, initial: []const u8) ![]u8 { │ │937 + var writer = std.Io.Writer.Allocating.init(allocator); │ │938 + defer writer.deinit(); │ │939 + try writer.writer.print("{s}", .{initial}); │ │940 + for (0..ui.detail_preview_lines) |line| │ │941 + try writer.writer.print("\n{d} {s}", .{ line, scatter_words[line % scatter_words.len] });│ │942 + return writer.toOwnedSlice(); │ │943 +} │ │944 │ │945 // write `path` as 40 lines of mostly-stable filler. revision `c` and file │ │946 // index `fi` shift which lines change and the words used, so each (c, fi) │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1213 var ours_values = values; │ │1214 ours_values[0].title = "Drop the legacy configuration loader"; │ │1215 ours_values[0].tags = "cleanup config breaking"; │ │1214 - ours_values[1].description = "Cache parsed manifests for the lifetime of a command invocation and invalidate entries when their files change.";│ │1216 + const closed_description = try longDescription( │ │1217 + patch_arena.allocator(), │ │1218 + "Cache parsed manifests for the lifetime of a command invocation and invalidate entries when their files change.", │ │1219 + ); │ │1220 + ours_values[1].description = closed_description; │ │1221 ours_values[2].description = "Add JSON output to inspect with versioned field names and deterministic object ordering."; │ │1222 var theirs_values = values; │ │1223 theirs_values[0].title = "Delete compatibility configuration support"; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │39 } │ │40 const clipped = iter.nextCodepointSlice() != null; │ │41 return try std.fmt.bufPrint(buffer, "{s}{s}", .{ text[0..if (clipped) clipped_end else end], if (clipped) ".." else "" });│ │42 +} │ │43 + │ │44 +pub const detail_preview_lines = 50; │ │45 + │ │46 +pub fn detailPreviewEnd(text: []const u8) ?usize { │ │47 + var lines: usize = 1; │ │48 + for (text, 0..) |byte, i| { │ │49 + if (byte != '\n') continue; │ │50 + if (lines == detail_preview_lines and i + 1 < text.len) return i; │ │51 + lines += 1; │ │52 + } │ │53 + return null; │ │54 } │ │55 │ │56 pub const PageKind = enum { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │18 // how many diff hunks one window of a commit's diff shows; "next"/"previous"│ │19 // move to the adjacent window. │ │20 const diff_page = 10; │ │21 -// the largest commit message a log page's detail view reads; a longer one is│ │22 -// cut here, with the message page carrying the whole thing. │ │23 -pub const max_message_size = 2 * 1024; │ │24 -// the same for the message page, which only reads the one commit. │ │25 -const max_full_message_size = 100 * 1024; │ │21 +// the largest message read even when it has fewer than the preview's line │ │22 +// limit. │ │23 +const max_message_size = 100 * 1024; │ │24 │ │25 pub const Hunk = struct { │ │26 path: ?[]const u8 = null, // the file this hunk belongs to │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │33 oid: []const u8, │ │34 date: []const u8, // "YYYY-MM-DD" │ │35 message: []const u8, // trimmed, may be multi-line │ │38 - // whether `message` is only the first line of a message too big to read.│ │36 + // whether `message` is a shortened preview. │ │37 message_truncated: bool = false, │ │38 author: ui.Author = .unknown, │ │39 hunks: []const Hunk, │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │61 const Self = @This(); │ │62 │ │63 // the diff and the message are alternatives, so a filtered diff can't also be│ │66 -// a message. the message is read whole, however big, since it's all its pane │ │67 -// shows. │ │64 +// a message. the message page reads up to the safety limit above. │ │65 pub const Content = union(enum) { │ │66 diff: struct { │ │67 // the file the top commit's diff is filtered to ("" = every file). │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │133 } │ │134 const md = commit_object.content.commit.metadata; │ │135 @memcpy(&oids[count], &commit_object.oid); │ │139 - // only the message the pane shows is read past the log's limit. │ │140 - 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);│ │136 + const text, const truncated = try readMessage(repo_kind, repo_opts, aa, commit_object, root_message and count == 0); │ │137 buf[count] = .{ │ │138 .oid = try aa.dupe(u8, &commit_object.oid), │ │139 .date = try formatDate(aa, md.timestamp), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │340 }); │ │341 } │ │342 │ │347 -// the commit message, trimmed and read into `aa`, plus whether it ran past │ │348 -// `limit` and was cut short there. │ │343 +// the commit message, trimmed and read into `aa`, plus whether its preview was│ │344 +// cut short. │ │345 fn readMessage( │ │346 comptime repo_kind: rp.RepoKind, │ │347 comptime repo_opts: rp.RepoOpts(repo_kind), │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯