╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │70 const user_moment = if (user_repo_maybe) |*user_repo| try evt.userMoment(user_repo) else null; │ │71 │ │72 const search: ?[]const u8 = if (repos_search.len == 0) null else std.Uri.percentDecodeInPlace(try arena.allocator().dupe(u8, repos_search));│ │73 - const prefix = search orelse ""; │ │73 │ │74 var repos: std.ArrayList(evt.Repo.Record) = .empty; │ │75 var repos_next_start: ?usize = null; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 76 if (user_moment) |moment| { │ │ 78 - if (try moment.getCursor(hash.hashInt(hash_kind, evt.Repo.name_index_key))) |index_cursor| { │ │ 79 - const index = try DB.SortedMap(.read_only).init(index_cursor); │ │ 77 + if (search) |prefix| { │ │ 78 + if (try moment.getCursor(hash.hashInt(hash_kind, evt.Repo.name_index_key))) |index_cursor| { │ │ 79 + const index = try DB.SortedMap(.read_only).init(index_cursor); │ │ 80 │ │ 81 - // the names with the prefix are contiguous from its rank, so the │ │ 82 - // window is one seek then a walk that stops at the first name without it │ │ 83 - var taken: usize = 0; │ │ 84 - var repos_iter = try index.iteratorFromIndex(try index.rank(prefix) +| repos_start); │ │ 85 - while (try repos_iter.next()) |cursor| { │ │ 86 - const pair = try cursor.readKeyValuePair(); │ │ 87 - const repo_name = try pair.key_cursor.readBytesAlloc(arena.allocator(), null); │ │ 88 - if (!std.mem.startsWith(u8, repo_name, prefix)) break; │ │ 89 - if (taken == page_size) { │ │ 90 - repos_next_start = repos_start + page_size; │ │ 91 - break; │ │ 81 + // the names with the prefix are contiguous from its rank, so the │ │ 82 + // window is one seek then a walk that stops at the first name without it │ │ 83 + var taken: usize = 0; │ │ 84 + var repos_iter = try index.iteratorFromIndex(try index.rank(prefix) +| repos_start); │ │ 85 + while (try repos_iter.next()) |cursor| { │ │ 86 + const pair = try cursor.readKeyValuePair(); │ │ 87 + const repo_name = try pair.key_cursor.readBytesAlloc(arena.allocator(), null); │ │ 88 + if (!std.mem.startsWith(u8, repo_name, prefix)) break; │ │ 89 + if (taken == page_size) { │ │ 90 + repos_next_start = repos_start + page_size; │ │ 91 + break; │ │ 92 + } │ │ 93 + taken += 1; │ │ 94 + var event_id: [evt.event_id_size]u8 = undefined; │ │ 95 + _ = try pair.value_cursor.readBytes(&event_id); │ │ 96 + const repo_event = (try evt.Repo.readById(DB, hash_kind, moment, arena, &event_id)) orelse continue; │ │ 97 + // unreadable repos leave their window short rather than shifting the others │ │ 98 + if (evt.Repo.roleOf(repo_event, session.userId()) == .none) continue; │ │ 99 + try repos.append(arena.allocator(), repo_event); │ │100 + } │ │101 + } │ │102 + } else { │ │103 + // unsearched, the newest activity comes first. its index sits beside the events. │ │104 + const user_repo = if (user_repo_maybe) |*user_repo| user_repo else unreachable; │ │105 + if (try (try user_repo.core.latestMoment()).getCursor(hash.hashInt(hash_kind, evt.recent_repo_id_set_key))) |recent_cursor| {│ │106 + const recent = try DB.SortedSet(.read_only).init(recent_cursor); │ │107 + const count = try recent.count(); │ │108 + const end = @min(repos_start +| page_size, count); │ │109 + var iter = try recent.iteratorFromIndex(repos_start); │ │110 + var i = repos_start; │ │111 + while (i < end) : (i += 1) { │ │112 + const kv_cursor = (try iter.next()) orelse break; │ │113 + const repo_id = try evt.readOrderKeyId(DB, kv_cursor); │ │114 + const repo_event = (try evt.Repo.readById(DB, hash_kind, moment, arena, &repo_id)) orelse continue; │ │115 + if (evt.Repo.roleOf(repo_event, session.userId()) == .none) continue; │ │116 + try repos.append(arena.allocator(), repo_event); │ │117 } │ │ 93 - taken += 1; │ │ 94 - var event_id: [evt.event_id_size]u8 = undefined; │ │ 95 - _ = try pair.value_cursor.readBytes(&event_id); │ │ 96 - const repo_event = (try evt.Repo.readById(DB, hash_kind, moment, arena, &event_id)) orelse continue; │ │ 97 - // unreadable repos leave their window short rather than shifting the others │ │ 98 - if (evt.Repo.roleOf(repo_event, session.userId()) == .none) continue; │ │ 99 - try repos.append(arena.allocator(), repo_event); │ │118 + repos_next_start = if (end < count) end else null; │ │119 } │ │120 } │ │121 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯