Summary
The clipboard event pipeline in src/app.rs uses async_channel::unbounded for both the clipboard event channel (ClipboardEvent) and the UI notification channel (()). This creates two related issues:
- Unbounded memory growth under load: Some applications (clipboard managers, paste-heavy IDEs, scripts) write to the clipboard several times per second. With unbounded channels, if the consumer momentarily falls behind (e.g. a slow
repo.save_* write or a UI refresh on a large list), pending events can accumulate without limit.
- Redundant full-list refreshes: Each saved record sends a single
() notification, and each notification triggers a full get_display_records(max_history_records) read from the repository plus a full GPUI re-render. Rapid copies fan out into N redundant refreshes when a single coalesced refresh would yield the same UI state.
Steps to Reproduce
- Launch Ropy.
- Run a script that writes to the system clipboard 20+ times per second for a few seconds.
- Observe (via
tracing logs / instrumentation) that every event triggers an independent full-list refresh, and that clipboard_rx / notify_rx channel depth can grow unboundedly if the foreground task is briefly stalled.
Expected Behavior
- Both channels are bounded (capacity 256). When full, oldest-style pressure is logged (dropped events for clipboard channel; coalesced/no-op for the notification channel).
- The UI refresh task drains all pending
() notifications before doing a single repository read + UI refresh (classic coalescing/debounce pattern).
Actual Behavior
let (clipboard_tx, clipboard_rx) = async_channel::unbounded::<ClipboardEvent>(); — unbounded.
let (notify_tx, notify_rx) = async_channel::unbounded::<()>(); — unbounded.
- Every
notify_rx.recv().await causes one full get_display_records(...) + GPUI refresh, with no coalescing.
Ropy Version
HEAD of main (pre-fix)
Operating System
All (cross-platform code path in src/app.rs)
Logs / Screenshots
N/A — issue identified by code review (doc/CODE_REVIEW.md §2.1).
Scope
clipboard
Summary
The clipboard event pipeline in
src/app.rsusesasync_channel::unboundedfor both the clipboard event channel (ClipboardEvent) and the UI notification channel (()). This creates two related issues:repo.save_*write or a UI refresh on a large list), pending events can accumulate without limit.()notification, and each notification triggers a fullget_display_records(max_history_records)read from the repository plus a full GPUI re-render. Rapid copies fan out into N redundant refreshes when a single coalesced refresh would yield the same UI state.Steps to Reproduce
tracinglogs / instrumentation) that every event triggers an independent full-list refresh, and thatclipboard_rx/notify_rxchannel depth can grow unboundedly if the foreground task is briefly stalled.Expected Behavior
()notifications before doing a single repository read + UI refresh (classic coalescing/debounce pattern).Actual Behavior
let (clipboard_tx, clipboard_rx) = async_channel::unbounded::<ClipboardEvent>();— unbounded.let (notify_tx, notify_rx) = async_channel::unbounded::<()>();— unbounded.notify_rx.recv().awaitcauses one fullget_display_records(...)+ GPUI refresh, with no coalescing.Ropy Version
HEAD of
main(pre-fix)Operating System
All (cross-platform code path in
src/app.rs)Logs / Screenshots
N/A — issue identified by code review (
doc/CODE_REVIEW.md§2.1).Scope
clipboard