╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────╮ │src/test/ui.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │292 // the base at a page boundary must not create an empty next page │ │293 - const full = try Commits.init(kind, opts, &arena, &repo, io, allocator, null, location, .object, &previous, content, &base); │ │293 + const full = try Commits.init(kind, opts, &arena, &repo, io, allocator, null, location, .object, &previous, content, &base, "", "");│ │294 try std.testing.expectEqual(20, full.commits.len); │ │295 try std.testing.expectEqual(null, full.next_start); │ │296 _ = try repo.addTag(io, allocator, .{ .name = "tip", .message = "annotated" }); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │300 .{ .ref = .tag, .value = "tip" }, │ │301 }; │ │302 for (sources) |source| { │ │303 - const empty = try Commits.init(kind, opts, &arena, &repo, io, allocator, null, location, source.ref, source.value, content, &tip); │ │303 + const empty = try Commits.init(kind, opts, &arena, &repo, io, allocator, null, location, source.ref, source.value, content, &tip, "", "");│ │304 try std.testing.expectEqual(0, empty.commits.len); │ │305 try std.testing.expectEqual(@as(?u64, if (kind == .xit) 0 else null), empty.commit_count); │ │306 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │307 │ │308 // an off-chain stopping point must not hide its parent on this chain │ │309 const other = try repo.commitAtRef(io, allocator, .{ .message = "other", .parent_oids = &.{base} }, null, .{ .kind = .head, .name = "other" }); │ │310 - const off_chain = try Commits.init(kind, opts, &arena, &repo, io, allocator, null, location, .object, last.commits[0].oid, content, &other); │ │310 + const off_chain = try Commits.init(kind, opts, &arena, &repo, io, allocator, null, location, .object, last.commits[0].oid, content, &other, "", "");│ │311 try std.testing.expectEqual(2, off_chain.commits.len); │ │312 try std.testing.expectEqualStrings(&base, off_chain.commits[1].oid); │ │313 try std.testing.expectEqual(null, off_chain.commit_count); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭─────────────────────────────────╮ │13 const obj = xit.object; │ │14 const ui = hx.ui; │ │15 const find = hx.find; │ │16 +const cms = hx.search_commit;│ │17 const fork = hx.fork; │ │18 const pch = hx.pch; │ │19 │ ╰─────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │823 try evt.consume(.local, .repo, .xit, .{}, io, allocator, &template_repo, evt.events_ref, &discussion_comment_events);│ │824 try template_repo.patchAll(io, allocator, null); │ │825 try template_repo.addConfig(io, allocator, .{ .name = "core.bare", .value = "true" }); │ │825 - // fixtures commit directly, so index the branch tips by hand │ │826 + // fixtures commit directly, so index the ref tips by hand │ │827 try find.refresh(.{}, io, allocator, &template_repo); │ │828 + try cms.refresh(.{}, io, allocator, &template_repo, null); │ │829 } │ │830 │ │831 // copy the template to each repo's on-disk location, named by its │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │193 │ │194 // the "key:value" segments of a url tail, collected in any order │ │195 const Params = struct { │ │196 - const ParamKey = enum { start, line, branch, tag, object, base, patchrev, theirs, find }; │ │196 + const ParamKey = enum { start, line, branch, tag, object, base, patchrev, theirs, find, search, from };│ │197 │ │198 // a branch:/tag:/object: param; the value stays url-encoded │ │199 const RefParam = struct { kind: RefOrOid, value: []const u8 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────╮ │272 const start_seg = @tagName(Params.ParamKey.start) ++ ":"; │ │273 const line_seg = @tagName(Params.ParamKey.line) ++ ":"; │ │274 const find_seg = @tagName(Params.ParamKey.find) ++ ":"; │ │275 + const search_seg = @tagName(Params.ParamKey.search) ++ ":";│ │276 + const from_seg = @tagName(Params.ParamKey.from) ++ ":"; │ │277 const base_seg = @tagName(Params.ParamKey.base) ++ ":"; │ │278 const theirs_seg = @tagName(Params.ParamKey.theirs) ++ ":";│ │279 const issue_seg = "issue:"; │ ╰────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │311 // caps the files tab's url-encoded search term. │ │312 pub const find_route_max_len = 100 * 3; │ │313 │ │314 + // caps the commits tab's url-encoded search query. │ │315 + pub const search_route_max_len = 100 * 3; │ │316 + │ │317 // the identity stored by every repo route. Local routes elide it.│ │318 pub const RepoIdentity = struct { │ │319 identity: []const u8, // "owner/name" │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │369 ref_or_oid: ?RefOrOid = null, │ │370 value: Array(ref_route_max_len) = .{}, │ │371 base_oid: Array(ref_route_max_len) = .{}, │ │372 + // the url-encoded query this page holds the results of ("" = the plain│ │373 + // log). only a branch or tag can carry one. │ │374 + search: Array(search_route_max_len) = .{}, │ │375 + // the commit the list starts at ("" = the ref's own commit). │ │376 + from: Array(ref_route_max_len) = .{}, │ │377 // what the pane shows for the commit the log walks from. │ │378 content: Content = .{ .diff = .{} }, │ │379 │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │540 │ │541 // carry a search term on a files route, url-encoding it into the route. │ │542 // null when it doesn't fit. │ │533 - pub fn withFind(self: RoutablePage, search: []const u8) ?RoutablePage { │ │534 - var find: Array(find_route_max_len) = .{}; │ │535 - var writer: std.Io.Writer = .fixed(&find.bytes); │ │536 - std.Uri.Component.percentEncode(&writer, search, isUnreserved) catch return null;│ │537 - find.len = @intCast(writer.buffered().len); │ │543 + pub fn withFind(self: RoutablePage, file_name: []const u8) ?RoutablePage { │ │544 + const find = encodeParam(find_route_max_len, file_name) orelse return null; │ │545 var route = self; │ │546 switch (route) { │ │547 .repo_files => |*f| f.find = find, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯