Files
cmux/Sources/SessionIndexTableMutationScheduler.swift
Austin Wang 5dc99c6da5 Fix Vault sidebar beachball at large session counts (#8680)
* test: require viewport-bounded Vault rows

* fix: keep Vault rendering and scans off main thread

* fix: let the Vault table fill the sidebar viewport

* fix: close Vault CI and review gaps

* fix: preserve bounded Antigravity history paging

* fix: defer Vault table mutations past layout

* fix: close final Vault review feedback

* fix: preserve bounded Antigravity history access

* test: cover Vault paging review regressions

* fix: bound Vault history paging work

* fix: keep Antigravity history single-root

* test: cover Vault byte and viewport boundaries

* fix: preserve Vault boundaries during paging

* chore: leave legacy XCTest suite untouched

* docs: clarify Vault JSONL paging offsets
2026-07-23 14:35:02 -07:00

36 lines
1.1 KiB
Swift

import Foundation
/// Defers and coalesces Vault table mutations past the originating layout callback.
@MainActor
final class SessionIndexTableMutationScheduler {
private var pendingApply: SessionIndexTableApplyInput?
private var isFlushScheduled = false
private let applyFlush: @MainActor (SessionIndexTableApplyInput) -> Void
init(applyFlush: @escaping @MainActor (SessionIndexTableApplyInput) -> Void) {
self.applyFlush = applyFlush
}
func stageApply(_ input: SessionIndexTableApplyInput) {
pendingApply = input
guard !isFlushScheduled else { return }
isFlushScheduled = true
RunLoop.main.perform(inModes: [.common]) { [weak self] in
// RunLoop guarantees main-thread delivery, but Foundation does
// not annotate this callback with MainActor.
MainActor.assumeIsolated {
self?.flushPendingApply()
}
}
}
private func flushPendingApply() {
let input = pendingApply
pendingApply = nil
isFlushScheduled = false
if let input {
applyFlush(input)
}
}
}