feat(tui): optimize performance by caching display lines and token counts, and improve action handling
This commit is contained in:
@@ -76,6 +76,13 @@ fn run_loop(
|
||||
}
|
||||
|
||||
/// The core single-process render/input loop.
|
||||
///
|
||||
/// Performance optimizations applied here:
|
||||
/// - Skip `terminal.draw()` when `state.dirty == false` (nothing changed)
|
||||
/// - Adaptive poll timeout: 50ms when a turn is in-flight (spinner needs
|
||||
/// smooth updates), 200ms when idle (no reason to busy-loop)
|
||||
/// - Toast expiry is drained once here instead of in two places
|
||||
/// - Chat display lines are cached and rebuilt only when content changes
|
||||
fn run_loop_inner(
|
||||
state: &mut AppStateRest,
|
||||
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
|
||||
@@ -84,15 +91,32 @@ fn run_loop_inner(
|
||||
if state.quit {
|
||||
break;
|
||||
}
|
||||
|
||||
// Drain expired toasts exactly once per loop iteration (was being
|
||||
// done here AND in Action::Tick before this fix).
|
||||
let now_ms = chrono::Utc::now().timestamp_millis();
|
||||
state.misc.drain_expired_toasts(now_ms);
|
||||
terminal.draw(|f| {
|
||||
view::draw(f, state);
|
||||
state.dirty = false;
|
||||
})?;
|
||||
|
||||
// Poll terminal with 50 ms timeout
|
||||
if crossterm::event::poll(Duration::from_millis(50))? {
|
||||
// Skip render when nothing has changed — avoids expensive markdown
|
||||
// re-parse and layout recalculation every cycle while idle.
|
||||
if state.dirty {
|
||||
// Pre-warm display caches before entering the terminal.draw closure.
|
||||
// This lets view::draw work with &AppStateRest (no mutation inside draw).
|
||||
view::pre_render(state);
|
||||
terminal.draw(|f| {
|
||||
view::draw(f, state);
|
||||
state.dirty = false;
|
||||
})?;
|
||||
}
|
||||
|
||||
// Adaptive poll: fast when animating, slow when idle.
|
||||
let poll_timeout = if state.turn_in_flight() {
|
||||
Duration::from_millis(50) // smooth spinner @ ~20fps
|
||||
} else {
|
||||
Duration::from_millis(200) // idle: 5fps, saves CPU
|
||||
};
|
||||
|
||||
if crossterm::event::poll(poll_timeout)? {
|
||||
match crossterm::event::read()? {
|
||||
Event::Key(key) => {
|
||||
if key.kind == KeyEventKind::Press || key.kind == KeyEventKind::Repeat {
|
||||
|
||||
Reference in New Issue
Block a user