Problem / Background
The current TUI loop in src/view/ui_loop.rs is still driven by a fixed polling cadence (event::poll(100ms) plus render interval checks), even when there is no new data and no user interaction.
This has two practical side effects:
- Idle CPU overhead: the UI wakes up repeatedly to do render housekeeping, frame counting, scroll offset updates, and content generation checks even when the screen is effectively idle.
- Input latency coupling: keyboard and mouse responsiveness are partially tied to the poll interval, which makes the interface feel less responsive than it should for a terminal UI.
Although DifferentialRenderer reduces the amount of terminal output, the application still pays the cost of waking up and traversing the render path too often.
Proposed Solution
Convert the UI loop from a fixed poll-driven design to an event-driven wakeup model.
The UI should wake up only for meaningful reasons:
- terminal input events (keyboard / mouse)
- terminal resize events
- fresh data from background collectors
- explicit animation ticks for views that actually need them (loading indicator, marquee scroll, clock, etc.)
A tokio::select!-based coordinator with channels / notifications should replace the current poll + throttle + retry pattern.
Scope
Event-driven UI wakeups
Collector-to-UI notification path
Animation isolation
Input responsiveness
Acceptance Criteria
Integration and Verification Requirements
Technical Considerations
crossterm input handling may need to move to a dedicated forwarding task or EventStream-based adapter depending on feature availability.
- Avoid holding
AppState mutex guards across await points while dispatching events.
- The wakeup model should be designed so later render optimizations can plug into it cleanly.
- This should be treated as the first implementation step for the TUI performance/responsiveness work, because later optimizations benefit from a cleaner event model.
Problem / Background
The current TUI loop in
src/view/ui_loop.rsis still driven by a fixed polling cadence (event::poll(100ms)plus render interval checks), even when there is no new data and no user interaction.This has two practical side effects:
Although
DifferentialRendererreduces the amount of terminal output, the application still pays the cost of waking up and traversing the render path too often.Proposed Solution
Convert the UI loop from a fixed poll-driven design to an event-driven wakeup model.
The UI should wake up only for meaningful reasons:
A
tokio::select!-based coordinator with channels / notifications should replace the currentpoll + throttle + retrypattern.Scope
Event-driven UI wakeups
event::poll()loop with an event-forwarding task or async event streamCollector-to-UI notification path
Animation isolation
Input responsiveness
Acceptance Criteria
Integration and Verification Requirements
Technical Considerations
crossterminput handling may need to move to a dedicated forwarding task orEventStream-based adapter depending on feature availability.AppStatemutex guards across await points while dispatching events.