mirror of
https://github.com/openai/codex.git
synced 2026-04-28 10:21:06 +03:00
3.7 KiB
3.7 KiB
DOs
- Bold: Debounce redraws via a request event: Introduce
RequestRedrawand scheduleRedrawafter ~100 ms.
// app_event.rs
pub(crate) enum AppEvent {
// ...
RequestRedraw,
Redraw,
// ...
}
// app.rs
const REDRAW_DEBOUNCE: Duration = Duration::from_millis(100);
- Bold: Scope locks tightly: Lock only to check/set the pending flag, then drop it before spawning the worker.
fn schedule_redraw(&self) {
{
let mut flag = self.pending_redraw.lock().unwrap();
if *flag {
return;
}
*flag = true;
} // lock dropped here
let tx = self.app_event_tx.clone();
let pending_redraw = self.pending_redraw.clone();
std::thread::spawn(move || {
std::thread::sleep(REDRAW_DEBOUNCE);
tx.send(AppEvent::Redraw);
let mut f = pending_redraw.lock().unwrap();
*f = false;
});
}
- Bold: Prefer
.clone()ergonomics: CloneArcs and senders with.clone()before moving into threads.
let tx = self.app_event_tx.clone();
let pending_redraw = self.pending_redraw.clone();
std::thread::spawn(move || {
// use tx, pending_redraw here
});
- Bold: Convert producers to
RequestRedraw: Replace directRedrawsends in all producers.
// On startup
self.app_event_tx.clone().send(AppEvent::RequestRedraw);
// On terminal resize
crossterm::event::Event::Resize(_, _) => {
app_event_tx.send(AppEvent::RequestRedraw);
}
// Bottom pane / widgets
self.app_event_tx.send(AppEvent::RequestRedraw);
- Bold: Handle the request distinctly: Turn
RequestRedrawinto a debouncedRedrawin the main loop.
while let Ok(event) = self.app_event_rx.recv() {
match event {
AppEvent::RequestRedraw => self.schedule_redraw(),
AppEvent::Redraw => self.draw_next_frame(terminal)?,
_ => {}
}
}
- Bold: Keep helpers near first use: Place
schedule_redrawjust above the match block that calls it for readability.
impl App<'_> {
// ... fields, new(), etc.
// place here (near run/loop)
fn schedule_redraw(&self) { /* as above */ }
pub(crate) fn run(&mut self, terminal: &mut tui::Tui, mouse_capture: &mut MouseCapture) -> Result<()> {
// uses schedule_redraw in match
}
}
DON’Ts
- Bold: Don’t hold locks across work: Avoid sleeping, sending, or spawning while a
MutexGuardis alive.
// BAD: lock held far too long
fn schedule_redraw_bad(&self) {
let mut flag = self.pending_redraw.lock().unwrap();
if *flag { return; }
*flag = true;
std::thread::sleep(REDRAW_DEBOUNCE); // holding the lock
self.app_event_tx.send(AppEvent::Redraw); // still holding the lock
}
- Bold: Don’t emit
Redrawdirectly from producers: Always sendRequestRedrawso the app can debounce.
// BAD
app_event_tx.send(AppEvent::Redraw);
// GOOD
app_event_tx.send(AppEvent::RequestRedraw);
- Bold: Don’t reschedule when one is pending: Guard with a boolean to coalesce rapid requests.
// Inside schedule_redraw
let mut flag = self.pending_redraw.lock().unwrap();
if *flag { return; } // don't stack timers
*flag = true;
- Bold: Don’t bury relevant helpers: Avoid scattering debounce logic far from where events are handled.
// BAD: helper lives in a distant module/file, hard to follow
// GOOD: helper is defined in the same impl, just above its call sites
- Bold: Don’t prefer long-lived patterns when simple clones work: Use
.clone()in place ofArc::clone(&x)when clarity is equal.
// Preferred here
let pending_redraw = self.pending_redraw.clone();
// Avoid when it adds noise
let pending_redraw = std::sync::Arc::clone(&self.pending_redraw); // noisier