mirror of
https://github.com/openai/codex.git
synced 2026-04-29 00:55:38 +00:00
259 lines
14 KiB
Markdown
259 lines
14 KiB
Markdown
# PR #1683: fix: crash on resize
|
|
|
|
- URL: https://github.com/openai/codex/pull/1683
|
|
- Author: nornagon-openai
|
|
- Created: 2025-07-25 20:47:32 UTC
|
|
- Updated: 2025-07-25 21:23:45 UTC
|
|
- Changes: +44/-32, Files changed: 1, Commits: 2
|
|
|
|
## Description
|
|
|
|
Without this, resizing the terminal prints "Error: The cursor position could not be read within a normal duration" and quits the app.
|
|
|
|
## Full Diff
|
|
|
|
```diff
|
|
diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs
|
|
index 4e2133a6be..e7097e6af0 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
|
|
}
|
|
}
|
|
});
|
|
```
|
|
|
|
## Review Comments
|
|
|
|
### codex-rs/tui/src/app.rs
|
|
|
|
- Created: 2025-07-25 21:12:39 UTC | Link: https://github.com/openai/codex/pull/1683#discussion_r2232016460
|
|
|
|
```diff
|
|
@@ -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)) {
|
|
```
|
|
|
|
> This is...surprising. Maybe link to https://github.com/ratatui/ratatui/blob/9836f0760d4a053d9d1eba78171be89cb22dc850/examples/apps/inline/src/main.rs#L98-L118 to cite an example from Ratatui itself?
|
|
|
|
- Created: 2025-07-25 21:12:49 UTC | Link: https://github.com/openai/codex/pull/1683#discussion_r2232017016
|
|
|
|
```diff
|
|
@@ -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
|
|
```
|
|
|
|
> 2 sec or 100ms?
|
|
|
|
- Created: 2025-07-25 21:14:37 UTC | Link: https://github.com/openai/codex/pull/1683#discussion_r2232019640
|
|
|
|
```diff
|
|
@@ -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)) {
|
|
```
|
|
|
|
> Also, it looks like that example is doing something slightly different: should we be modeling it more closely? |