From 1ad261d6810b4f166c04cb660473a0e2136c027c Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Fri, 12 Dec 2025 23:47:37 -0600 Subject: [PATCH] Changed default wrap algorithm from OptimalFit to FirstFit (#7960) Codex identified this as the cause of a reported hang: https://github.com/openai/codex/issues/7822. Apparently, the wrapping algorithm we're using has known issues and bad worst-case behaviors when OptimalFit is used on certain strings. It recommended switching to FirstFit instead. --- codex-rs/tui/src/history_cell.rs | 4 ++-- codex-rs/tui/src/markdown_render.rs | 4 ++-- codex-rs/tui/src/wrapping.rs | 17 ++++++----------- codex-rs/tui2/src/history_cell.rs | 4 ++-- codex-rs/tui2/src/markdown_render.rs | 4 ++-- codex-rs/tui2/src/wrapping.rs | 17 ++++++----------- 6 files changed, 20 insertions(+), 30 deletions(-) diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index dffe7eba2..5440040f6 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -1664,8 +1664,8 @@ mod tests { assert_eq!( rendered, vec![ - "✔ You approved codex".to_string(), - " to run echo something".to_string(), + "✔ You approved codex to".to_string(), + " run echo something".to_string(), " really long to ensure".to_string(), " wrapping happens this".to_string(), " time".to_string(), diff --git a/codex-rs/tui/src/markdown_render.rs b/codex-rs/tui/src/markdown_render.rs index 19cf94492..4ba7b6131 100644 --- a/codex-rs/tui/src/markdown_render.rs +++ b/codex-rs/tui/src/markdown_render.rs @@ -595,8 +595,8 @@ mod tests { lines, vec![ "- outer item with".to_string(), - " several words".to_string(), - " to wrap".to_string(), + " several words to".to_string(), + " wrap".to_string(), " - inner item".to_string(), " that also".to_string(), " needs wrapping".to_string(), diff --git a/codex-rs/tui/src/wrapping.rs b/codex-rs/tui/src/wrapping.rs index 561da78b4..c29106651 100644 --- a/codex-rs/tui/src/wrapping.rs +++ b/codex-rs/tui/src/wrapping.rs @@ -3,7 +3,6 @@ use ratatui::text::Span; use std::borrow::Cow; use std::ops::Range; use textwrap::Options; -use textwrap::wrap_algorithms::Penalties; use crate::render::line_utils::push_owned_lines; @@ -92,11 +91,7 @@ impl<'a> RtOptions<'a> { subsequent_indent: Line::default(), break_words: true, word_separator: textwrap::WordSeparator::new(), - wrap_algorithm: textwrap::WrapAlgorithm::OptimalFit(Penalties { - // ~infinite overflow penalty, we never want to overflow a line. - overflow_penalty: usize::MAX / 4, - ..Default::default() - }), + wrap_algorithm: textwrap::WrapAlgorithm::FirstFit, word_splitter: textwrap::WordSplitter::HyphenSplitter, } } @@ -641,11 +636,11 @@ mod tests { let joined: String = wrapped.iter().map(ToString::to_string).join("\n"); assert_eq!( joined, - r#"Years passed, and Willowmere thrived -in peace and friendship. Mira’s herb -garden flourished with both ordinary and -enchanted plants, and travelers spoke -of the kindness of the woman who tended + r#"Years passed, and Willowmere thrived in +peace and friendship. Mira’s herb garden +flourished with both ordinary and +enchanted plants, and travelers spoke of +the kindness of the woman who tended them."# ); } diff --git a/codex-rs/tui2/src/history_cell.rs b/codex-rs/tui2/src/history_cell.rs index dffe7eba2..5440040f6 100644 --- a/codex-rs/tui2/src/history_cell.rs +++ b/codex-rs/tui2/src/history_cell.rs @@ -1664,8 +1664,8 @@ mod tests { assert_eq!( rendered, vec![ - "✔ You approved codex".to_string(), - " to run echo something".to_string(), + "✔ You approved codex to".to_string(), + " run echo something".to_string(), " really long to ensure".to_string(), " wrapping happens this".to_string(), " time".to_string(), diff --git a/codex-rs/tui2/src/markdown_render.rs b/codex-rs/tui2/src/markdown_render.rs index 19cf94492..4ba7b6131 100644 --- a/codex-rs/tui2/src/markdown_render.rs +++ b/codex-rs/tui2/src/markdown_render.rs @@ -595,8 +595,8 @@ mod tests { lines, vec![ "- outer item with".to_string(), - " several words".to_string(), - " to wrap".to_string(), + " several words to".to_string(), + " wrap".to_string(), " - inner item".to_string(), " that also".to_string(), " needs wrapping".to_string(), diff --git a/codex-rs/tui2/src/wrapping.rs b/codex-rs/tui2/src/wrapping.rs index 561da78b4..c29106651 100644 --- a/codex-rs/tui2/src/wrapping.rs +++ b/codex-rs/tui2/src/wrapping.rs @@ -3,7 +3,6 @@ use ratatui::text::Span; use std::borrow::Cow; use std::ops::Range; use textwrap::Options; -use textwrap::wrap_algorithms::Penalties; use crate::render::line_utils::push_owned_lines; @@ -92,11 +91,7 @@ impl<'a> RtOptions<'a> { subsequent_indent: Line::default(), break_words: true, word_separator: textwrap::WordSeparator::new(), - wrap_algorithm: textwrap::WrapAlgorithm::OptimalFit(Penalties { - // ~infinite overflow penalty, we never want to overflow a line. - overflow_penalty: usize::MAX / 4, - ..Default::default() - }), + wrap_algorithm: textwrap::WrapAlgorithm::FirstFit, word_splitter: textwrap::WordSplitter::HyphenSplitter, } } @@ -641,11 +636,11 @@ mod tests { let joined: String = wrapped.iter().map(ToString::to_string).join("\n"); assert_eq!( joined, - r#"Years passed, and Willowmere thrived -in peace and friendship. Mira’s herb -garden flourished with both ordinary and -enchanted plants, and travelers spoke -of the kindness of the woman who tended + r#"Years passed, and Willowmere thrived in +peace and friendship. Mira’s herb garden +flourished with both ordinary and +enchanted plants, and travelers spoke of +the kindness of the woman who tended them."# ); }