mirror of
https://github.com/openai/codex.git
synced 2026-11-01 19:33:35 +00:00
fix(tui): wrap fallback tables and clamp narrow stream widths
This commit is contained in:
committed by
Felipe Coury
parent
31bd54d7a2
commit
27ed715de7
@@ -4192,7 +4192,13 @@ impl ChatWidget {
|
||||
self.last_rendered_width
|
||||
.get()
|
||||
.or_else(|| terminal::size().ok().map(|(w, _)| usize::from(w)))
|
||||
.and_then(|w| crate::width::usable_content_width(w, reserved_cols))
|
||||
.and_then(|w| {
|
||||
if w == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(crate::width::usable_content_width(w, reserved_cols).unwrap_or(1))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn on_terminal_resize(&mut self, width: u16) {
|
||||
|
||||
@@ -113,14 +113,14 @@ async fn turn_started_uses_runtime_context_window_before_first_token_count() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn current_stream_width_returns_none_when_reserved_columns_exhaust_width() {
|
||||
async fn current_stream_width_clamps_to_minimum_when_reserved_columns_exhaust_width() {
|
||||
let (chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
|
||||
chat.last_rendered_width.set(Some(2));
|
||||
assert_eq!(chat.current_stream_width(2), None);
|
||||
assert_eq!(chat.current_stream_width(2), Some(1));
|
||||
|
||||
chat.last_rendered_width.set(Some(4));
|
||||
assert_eq!(chat.current_stream_width(4), None);
|
||||
assert_eq!(chat.current_stream_width(4), Some(1));
|
||||
|
||||
chat.last_rendered_width.set(Some(5));
|
||||
assert_eq!(chat.current_stream_width(4), Some(1));
|
||||
|
||||
@@ -195,11 +195,13 @@ impl TableState {
|
||||
|
||||
/// Rendered table output split by wrapping behavior.
|
||||
///
|
||||
/// `table_lines` are grid/fallback rows that are already width-laid-out and
|
||||
/// should bypass paragraph wrapping. `spillover_lines` are prose rows extracted
|
||||
/// from parser artifacts and should be routed through normal wrapping.
|
||||
/// `table_lines` are either prewrapped grid rows (box rendering) or pipe
|
||||
/// fallback rows that should still pass through normal wrapping.
|
||||
/// `spillover_lines` are prose rows extracted from parser artifacts and should
|
||||
/// be routed through normal wrapping.
|
||||
struct RenderedTableLines {
|
||||
table_lines: Vec<Line<'static>>,
|
||||
table_lines_prewrapped: bool,
|
||||
spillover_lines: Vec<Line<'static>>,
|
||||
}
|
||||
|
||||
@@ -810,11 +812,17 @@ where
|
||||
|
||||
let RenderedTableLines {
|
||||
table_lines,
|
||||
table_lines_prewrapped,
|
||||
spillover_lines,
|
||||
} = self.render_table_lines(table_state);
|
||||
let mut pending_marker_line = self.pending_marker_line;
|
||||
for line in table_lines {
|
||||
self.push_prewrapped_line(line, pending_marker_line);
|
||||
if table_lines_prewrapped {
|
||||
self.push_prewrapped_line(line, pending_marker_line);
|
||||
} else {
|
||||
self.push_line(line);
|
||||
self.flush_current_line();
|
||||
}
|
||||
pending_marker_line = false;
|
||||
}
|
||||
self.pending_marker_line = false;
|
||||
@@ -945,6 +953,7 @@ where
|
||||
if column_count == 0 {
|
||||
return RenderedTableLines {
|
||||
table_lines: Vec::new(),
|
||||
table_lines_prewrapped: true,
|
||||
spillover_lines: Vec::new(),
|
||||
};
|
||||
}
|
||||
@@ -989,6 +998,7 @@ where
|
||||
&rows,
|
||||
&table_state.alignments,
|
||||
),
|
||||
table_lines_prewrapped: false,
|
||||
spillover_lines,
|
||||
};
|
||||
};
|
||||
@@ -1014,6 +1024,7 @@ where
|
||||
out.push(self.render_border_line('└', '┴', '┘', &column_widths, border_style));
|
||||
RenderedTableLines {
|
||||
table_lines: out,
|
||||
table_lines_prewrapped: true,
|
||||
spillover_lines,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1461,6 +1461,23 @@ fn table_falls_back_to_pipe_rendering_if_it_cannot_fit() {
|
||||
assert!(!lines.iter().any(|line| line.contains('┌')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_pipe_fallback_rows_wrap_in_narrow_width() {
|
||||
let md = "| c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 |\n|---|---|---|---|---|---|---|---|---|---|\n| 111111 | 222222 | 333333 | 444444 | 555555 | 666666 | 777777 | 888888 | 999999 | 101010 |\n";
|
||||
let text = crate::markdown_render::render_markdown_text_with_width(md, Some(20));
|
||||
let lines: Vec<String> = text
|
||||
.lines
|
||||
.iter()
|
||||
.map(|line| line.spans.iter().map(|span| span.content.clone()).collect())
|
||||
.collect();
|
||||
|
||||
assert!(lines.first().is_some_and(|line| line.starts_with('|')));
|
||||
assert!(
|
||||
lines.len() > 3,
|
||||
"expected wrapped pipe-fallback rows at narrow width, got {lines:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_pipe_fallback_escapes_literal_pipes_in_cell_content() {
|
||||
let md = "| c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 |\n|---|---|---|---|---|---|---|---|---|---|\n| keep | keep | keep | keep | keep | keep | keep | keep | a \\| b | keep |\n";
|
||||
@@ -1472,7 +1489,10 @@ fn table_pipe_fallback_escapes_literal_pipes_in_cell_content() {
|
||||
.collect();
|
||||
|
||||
assert!(lines.first().is_some_and(|line| line.starts_with('|')));
|
||||
assert!(lines.iter().any(|line| line.contains("a \\| b")));
|
||||
assert!(
|
||||
lines.iter().any(|line| line.contains("\\|")),
|
||||
"expected escaped pipe marker to be preserved in wrapped fallback rows: {lines:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -306,9 +306,10 @@ impl StreamCore {
|
||||
};
|
||||
|
||||
let mut stable_prefix_render = Vec::new();
|
||||
append_markdown_agent(
|
||||
append_markdown_agent_with_cwd(
|
||||
&self.raw_source[..last_nonblank_start],
|
||||
self.width,
|
||||
Some(self.cwd.as_path()),
|
||||
&mut stable_prefix_render,
|
||||
);
|
||||
self.rendered_lines
|
||||
|
||||
Reference in New Issue
Block a user