From c66c99c5b544a3334a3ee84c3cf28187438e7715 Mon Sep 17 00:00:00 2001 From: Jeremy Rose <172423086+nornagon-openai@users.noreply.github.com> Date: Fri, 25 Jul 2025 14:23:38 -0700 Subject: [PATCH] fix: crash on resize (#1683) Without this, resizing the terminal prints "Error: The cursor position could not be read within a normal duration" and quits the app. --- codex-rs/tui/src/app.rs | 76 ++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 4e2133a6..e7097e6a 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -88,39 +88,51 @@ impl App<'_> { { let app_event_tx = app_event_tx.clone(); std::thread::spawn(move || { - while let Ok(event) = crossterm::event::read() { - match event { - crossterm::event::Event::Key(key_event) => { - app_event_tx.send(AppEvent::KeyEvent(key_event)); - } - crossterm::event::Event::Resize(_, _) => { - app_event_tx.send(AppEvent::RequestRedraw); - } - crossterm::event::Event::Mouse(MouseEvent { - kind: MouseEventKind::ScrollUp, - .. - }) => { - scroll_event_helper.scroll_up(); - } - crossterm::event::Event::Mouse(MouseEvent { - kind: MouseEventKind::ScrollDown, - .. - }) => { - scroll_event_helper.scroll_down(); - } - crossterm::event::Event::Paste(pasted) => { - // Many terminals convert newlines to \r when - // pasting, e.g. [iTerm2][]. But [tui-textarea - // expects \n][tui-textarea]. This seems like a bug - // in tui-textarea IMO, but work around it for now. - // [tui-textarea]: https://github.com/rhysd/tui-textarea/blob/4d18622eeac13b309e0ff6a55a46ac6706da68cf/src/textarea.rs#L782-L783 - // [iTerm2]: https://github.com/gnachman/iTerm2/blob/5d0c0d9f68523cbd0494dad5422998964a2ecd8d/sources/iTermPasteHelper.m#L206-L216 - let pasted = pasted.replace("\r", "\n"); - app_event_tx.send(AppEvent::Paste(pasted)); - } - _ => { - // Ignore any other events. + loop { + // This timeout is necessary to avoid holding the event lock + // that crossterm::event::read() acquires. In particular, + // reading the cursor position (crossterm::cursor::position()) + // needs to acquire the event lock, and so will fail if it + // can't acquire it within 2 sec. Resizing the terminal + // crashes the app if the cursor position can't be read. + if let Ok(true) = crossterm::event::poll(Duration::from_millis(100)) { + if let Ok(event) = crossterm::event::read() { + match event { + crossterm::event::Event::Key(key_event) => { + app_event_tx.send(AppEvent::KeyEvent(key_event)); + } + crossterm::event::Event::Resize(_, _) => { + app_event_tx.send(AppEvent::RequestRedraw); + } + crossterm::event::Event::Mouse(MouseEvent { + kind: MouseEventKind::ScrollUp, + .. + }) => { + scroll_event_helper.scroll_up(); + } + crossterm::event::Event::Mouse(MouseEvent { + kind: MouseEventKind::ScrollDown, + .. + }) => { + scroll_event_helper.scroll_down(); + } + crossterm::event::Event::Paste(pasted) => { + // Many terminals convert newlines to \r when + // pasting, e.g. [iTerm2][]. But [tui-textarea + // expects \n][tui-textarea]. This seems like a bug + // in tui-textarea IMO, but work around it for now. + // [tui-textarea]: https://github.com/rhysd/tui-textarea/blob/4d18622eeac13b309e0ff6a55a46ac6706da68cf/src/textarea.rs#L782-L783 + // [iTerm2]: https://github.com/gnachman/iTerm2/blob/5d0c0d9f68523cbd0494dad5422998964a2ecd8d/sources/iTermPasteHelper.m#L206-L216 + let pasted = pasted.replace("\r", "\n"); + app_event_tx.send(AppEvent::Paste(pasted)); + } + _ => { + // Ignore any other events. + } + } } + } else { + // Timeout expired, no `Event` is available } } });