╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │241 const edit_files = [_][]const u8{ "src/alpha.txt", "src/beta.txt", "src/gamma.txt" };│ │242 // cycled through to pad each line into prose-like content. │ │243 const words = [_][]const u8{ │ │244 - "lorem", "ipsum", "dolor", "sit", "amet", "consectetur", │ │245 - "quantum", "vector", "matrix", "buffer", "kernel", "socket", │ │246 - "falcon", "otter", "badger", "walrus", "ferret", "marmot", │ │247 - "scatter", "gather", "encode", "decode", "render", "commit", │ │244 + "lorem", "ipsum", "dolor", "sit", "amet", "consectetur", │ │245 + "quantum", "vector", "matrix", "buffer", "kernel", "socket", │ │246 + "falcon", "otter", "badger", "walrus", "ferret", "marmot", │ │247 + "scatter", "gather", "encode", "decode", "render", "commit", │ │248 + }; │ │249 + // commit subjects, cycled then padded to a varying length. │ │250 + const subjects = [_][]const u8{ │ │251 + "fix off-by-one in scatter loop", │ │252 + "encode and decode buffers", │ │253 + "tune kernel socket timeouts", │ │254 + "render matrix vector product", │ │255 + "gather falcon and otter stats", │ │256 + "refactor badger walrus module", │ │257 + "drop dead ferret marmot branch", │ │258 }; │ │259 var c: usize = 0; │ │260 while (c < 30) : (c += 1) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │267 defer file.close(io); │ │268 var writer = std.Io.Writer.Allocating.init(allocator); │ │269 defer writer.deinit(); │ │260 - // every 8th line (offset per file) encodes the commit │ │261 - // number; the rest stay constant. the changed lines sit │ │262 - // far enough apart that diff renders each as its own hunk. │ │263 - // each line is padded with cycled words to a per-line │ │264 - // length, capped at 120 characters. │ │270 + // every 8th line is edited by this commit; the stride │ │271 + // offset shifts with c so consecutive commits touch │ │272 + // different lines, and the edited text carries a │ │273 + // c-dependent word, so each commit's diff is a distinct │ │274 + // scatter of hunks. untouched lines stay byte-identical │ │275 + // across commits (their padding ignores c) so they don't │ │276 + // all change every commit. each line is padded with │ │277 + // cycled words to a per-line length, capped at 120. │ │278 for (0..40) |line| { │ │279 const start = writer.written().len; │ │267 - if ((line + fi) % 8 == 0) { │ │268 - try writer.writer.print("line {d}: rev {d}", .{ line, c }); │ │280 + if ((line + fi + c) % 8 == 0) { │ │281 + const tag = words[(line + fi + c * 3) % words.len]; │ │282 + try writer.writer.print("line {d}: rev {d} {s}", .{ line, c, tag });│ │283 } else { │ │284 try writer.writer.print("line {d}", .{line}); │ │285 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │297 } │ │298 } │ │299 try repo_i.add(io, allocator, &edit_files); │ │286 - const message = try std.fmt.allocPrint(arena.allocator(), "scattered edits {d}", .{c + 1}); │ │300 + // a cycling subject padded to a c-varying length so the commit │ │301 + // list shows messages of different widths, capped at 120. │ │302 + var msg_writer = std.Io.Writer.Allocating.init(allocator); │ │303 + defer msg_writer.deinit(); │ │304 + try msg_writer.writer.print("{s}", .{subjects[c % subjects.len]}); │ │305 + const msg_target = 16 + (c * 41) % 96; │ │306 + var mw = c; │ │307 + while (true) : (mw += 1) { │ │308 + const word = words[mw % words.len]; │ │309 + const len = msg_writer.written().len; │ │310 + if (len >= msg_target or len + 1 + word.len > 120) break; │ │311 + try msg_writer.writer.print(" {s}", .{word}); │ │312 + } │ │313 + const message = try arena.allocator().dupe(u8, msg_writer.written()); │ │314 _ = try repo_i.commit(io, allocator, .{ .message = message, .timestamp = base_ts + c * std.time.s_per_day });│ │315 } │ │316 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────╮ │275 │ │276 const list_index: usize = 0; │ │277 const diff_index: usize = 1; │ │278 - // min widths for the two panes │ │279 - const list_width: usize = 40; │ │280 - const diff_width: usize = 40; │ │278 + const list_max_width: usize = 40; │ │279 + const diff_min_width: usize = 40; │ │280 // how many rows a page up/down jumps, and the scroll-wheel step.│ │281 const page_rows = 10; │ │282 │ ╰──────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │283 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { │ │285 - const aa = session.page_arena.allocator(); │ │286 - │ │284 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .horiz });│ │285 errdefer box.deinit(allocator); │ │286 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │290 var list_box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .vert }); │ │291 errdefer list_box.deinit(allocator); │ │292 for (data.commits) |commit| { │ │296 - const label = try std.fmt.allocPrint(aa, "{s} {s}", .{ commit.date, commit.message }); │ │297 - try addRow(allocator, &list_box, label, ""); │ │293 + try addRow(allocator, &list_box, commit.message, ""); │ │294 } │ │295 if (data.next_start) |next| { │ │296 try addRow(allocator, &list_box, "next", try commitsPageLink(session.page_arena, data.identity, next));│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │299 break :blk try wgt.Scroll(ui.Widget).init(allocator, .{ .box = list_box }, .{ .direction = .vert }); │ │300 }; │ │301 errdefer list_scroll.deinit(allocator); │ │306 - try box.children.put(allocator, list_scroll.getFocus().id, .{ .widget = .{ .scroll = list_scroll }, .rect = null, .min_size = .{ .width = list_width, .height = null } }); │ │302 + try box.children.put(allocator, list_scroll.getFocus().id, .{ .widget = .{ .scroll = list_scroll }, .rect = null, .min_size = .{ .width = list_max_width, .height = null }, .max_size = .{ .width = list_max_width, .height = null } });│ │303 } │ │304 │ │305 // the diff pane — a frame around a scroll of the hunks │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │317 break :blk outer; │ │318 }; │ │319 errdefer diff_outer.deinit(allocator); │ │324 - try box.children.put(allocator, diff_outer.getFocus().id, .{ .widget = .{ .box = diff_outer }, .rect = null, .min_size = .{ .width = diff_width, .height = null } }); │ │320 + try box.children.put(allocator, diff_outer.getFocus().id, .{ .widget = .{ .box = diff_outer }, .rect = null, .min_size = .{ .width = diff_min_width, .height = null } });│ │321 } │ │322 │ │323 box.getFocus().child_id = box.children.keys()[list_index]; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │334 } │ │335 │ │336 fn addRow(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), label: []const u8, link: []const u8) !void { │ │341 - var row = try wgt.TextBox(ui.Widget).init(allocator, label, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .none });│ │337 + var row = try wgt.TextBox(ui.Widget).init(allocator, label, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word });│ │338 errdefer row.deinit(allocator); │ │339 row.getFocus().focusable = true; │ │340 if (link.len != 0) row.getFocus().kind = .{ .custom = link }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │345 - try box.children.put(allocator, row.getFocus().id, .{ .widget = .{ .text_box = row }, .rect = null, .min_size = null }); │ │341 + try box.children.put(allocator, row.getFocus().id, .{ .widget = .{ .text_box = row }, .rect = null, .min_size = null, .max_size = .{ .width = null, .height = 5 } });│ │342 } │ │343 │ │344 // one hunk as a focusable multi-line text box. its lines sit flush (the │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯