mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
fix(tui): align table emoji widths with terminals
Compute markdown table cell widths with per-character terminal cell widths so boxed table padding matches xterm.js for emoji presentation, keycap, and ZWJ sequences. This keeps emoji tables rendered as boxed tables while preventing border columns from drifting during resize in xterm-based terminals.
This commit is contained in:
@@ -63,7 +63,7 @@ use std::ops::Range;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
use url::Url;
|
||||
|
||||
struct MarkdownStyles {
|
||||
@@ -1172,7 +1172,7 @@ where
|
||||
if word_count > 0 {
|
||||
total_words += word_count;
|
||||
total_cells += 1;
|
||||
total_cell_width += plain.width();
|
||||
total_cell_width += Self::terminal_cell_width(&plain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1182,7 +1182,7 @@ where
|
||||
total_words as f64 / total_cells as f64
|
||||
};
|
||||
let avg_cell_width = if total_cells == 0 {
|
||||
header_plain.width() as f64
|
||||
Self::terminal_cell_width(&header_plain) as f64
|
||||
} else {
|
||||
total_cell_width as f64 / total_cells as f64
|
||||
};
|
||||
@@ -1504,7 +1504,10 @@ where
|
||||
|
||||
#[inline]
|
||||
fn spans_display_width(spans: &[Span<'_>]) -> usize {
|
||||
spans.iter().map(|span| span.content.width()).sum()
|
||||
spans
|
||||
.iter()
|
||||
.map(|span| Self::terminal_cell_width(&span.content))
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1523,7 +1526,17 @@ where
|
||||
|
||||
#[inline]
|
||||
fn longest_token_width(text: &str) -> usize {
|
||||
text.split_whitespace().map(str::width).max().unwrap_or(0)
|
||||
text.split_whitespace()
|
||||
.map(Self::terminal_cell_width)
|
||||
.max()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn terminal_cell_width(text: &str) -> usize {
|
||||
text.chars()
|
||||
.map(|ch| UnicodeWidthChar::width(ch).unwrap_or(0))
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn push_inline_style(&mut self, style: Style) {
|
||||
@@ -2176,6 +2189,15 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_cell_width_matches_xterm_table_cases() {
|
||||
assert_eq!(W::terminal_cell_width("🅰️"), 1);
|
||||
assert_eq!(W::terminal_cell_width("↔️"), 1);
|
||||
assert_eq!(W::terminal_cell_width("1️⃣"), 1);
|
||||
assert_eq!(W::terminal_cell_width("👩💻"), 4);
|
||||
assert_eq!(W::terminal_cell_width("🔤"), 2);
|
||||
}
|
||||
|
||||
// ===== Column-metrics unit tests =====
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -4,7 +4,7 @@ use ratatui::text::Line;
|
||||
use ratatui::text::Span;
|
||||
use ratatui::text::Text;
|
||||
use std::path::Path;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use crate::markdown_render::COLON_LOCATION_SUFFIX_RE;
|
||||
use crate::markdown_render::HASH_LOCATION_SUFFIX_RE;
|
||||
@@ -16,6 +16,12 @@ fn render_markdown_text_for_cwd(input: &str, cwd: &Path) -> Text<'static> {
|
||||
render_markdown_text_with_width_and_cwd(input, /*width*/ None, Some(cwd))
|
||||
}
|
||||
|
||||
fn terminal_cell_width(text: &str) -> usize {
|
||||
text.chars()
|
||||
.map(|ch| UnicodeWidthChar::width(ch).unwrap_or(0))
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
assert_eq!(render_markdown_text(""), Text::default());
|
||||
@@ -1480,13 +1486,15 @@ fn table_with_emoji_sequence_cells_has_consistent_display_width() {
|
||||
})
|
||||
.map(String::as_str)
|
||||
.collect();
|
||||
let expected_width = table_lines
|
||||
let first_table_line = table_lines
|
||||
.first()
|
||||
.expect("expected unicode table to render as a box")
|
||||
.width();
|
||||
.expect("expected unicode table to render as a box");
|
||||
let expected_width = terminal_cell_width(first_table_line);
|
||||
|
||||
assert!(
|
||||
table_lines.iter().all(|line| line.width() == expected_width),
|
||||
table_lines
|
||||
.iter()
|
||||
.all(|line| terminal_cell_width(line) == expected_width),
|
||||
"expected every rendered table row to have width {expected_width}: {table_lines:?}"
|
||||
);
|
||||
assert!(
|
||||
|
||||
Reference in New Issue
Block a user