Skip to content

Commit d7ae203

Browse files
zcutlipryoppippi
andauthored
fix(terminal): use max line width for multiline table cells (#1192)
- The Models column used visible_width_sum (sum of all lines) instead of visible_width_max_line (widest single line) - This caused columns with multiline cells to be far wider than necessary - Remove the special-cased column-index-1 logic and use uniform visible_width_max_line for all columns - Remove the now-unused visible_width_sum function from width.rs - Update snapshot to reflect narrower Models column Co-authored-by: ryoppippi <1560508+ryoppippi@users.noreply.github.com>
1 parent 72e2372 commit d7ae203

3 files changed

Lines changed: 55 additions & 31 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
---
22
source: crates/ccusage-terminal/src/table.rs
3-
assertion_line: 465
43
expression: "table.render_lines().join(\"\\n\")"
54
---
6-
┌─────────────────────────┬──────────────────────────────────┬───────────┬───────────┬─────────────┐
7-
DateModels InputOutputCost (USD) │
8-
├─────────────────────────┼──────────────────────────────────┼───────────┼───────────┼─────────────┤
9-
2026-05-18- claude-sonnet-4 1,23456$0.42
10-
│ │ - gpt-5.2-codex │ │ │ │
11-
├─────────────────────────┼──────────────────────────────────┼───────────┼───────────┼─────────────┤
12-
│ (assuming cache warmup) │ 00$0.00
13-
├─────────────────────────┼──────────────────────────────────┼───────────┼───────────┼─────────────┤
14-
Total 1,23456$0.42
15-
└─────────────────────────┴──────────────────────────────────┴───────────┴───────────┴─────────────┘
5+
┌─────────────────────────┬───────────────────┬───────────┬───────────┬─────────────┐
6+
DateModelsInputOutputCost (USD) │
7+
├─────────────────────────┼───────────────────┼───────────┼───────────┼─────────────┤
8+
2026-05-18- claude-sonnet-41,23456$0.42
9+
│ │ - gpt-5.2-codex │ │ │ │
10+
├─────────────────────────┼───────────────────┼───────────┼───────────┼─────────────┤
11+
│ (assuming cache warmup) │ │ 00$0.00
12+
├─────────────────────────┼───────────────────┼───────────┼───────────┼─────────────┤
13+
Total │ │ 1,23456$0.42
14+
└─────────────────────────┴───────────────────┴───────────┴───────────┴─────────────┘

rust/crates/ccusage-terminal/src/table.rs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use std::io::{self, Write};
33
use crate::{
44
style::{color, Color, TerminalStyle},
55
terminal::DEFAULT_TERMINAL_WIDTH,
6-
width::{
7-
char_display_width, contains_ansi, visible_width, visible_width_max_line, visible_width_sum,
8-
},
6+
width::{char_display_width, contains_ansi, visible_width, visible_width_max_line},
97
};
108

119
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -103,23 +101,12 @@ impl SimpleTable {
103101
let content_widths = self
104102
.headers
105103
.iter()
106-
.enumerate()
107-
.map(|(index, header)| {
108-
if index == 1 {
109-
visible_width_sum(header)
110-
} else {
111-
visible_width_max_line(header)
112-
}
113-
})
104+
.map(|header| visible_width_max_line(header))
114105
.collect::<Vec<_>>();
115106
let mut content_widths = content_widths;
116107
for row in self.rows.iter().flatten() {
117108
for (index, cell) in row.iter().enumerate() {
118-
let cell_width = if index == 1 {
119-
visible_width_sum(cell)
120-
} else {
121-
visible_width_max_line(cell)
122-
};
109+
let cell_width = visible_width_max_line(cell);
123110
if let Some(width) = content_widths.get_mut(index) {
124111
*width = (*width).max(cell_width);
125112
}
@@ -502,4 +489,46 @@ mod tests {
502489
fn snapshots_ansi_truncation_boundary() {
503490
insta::assert_snapshot!(truncate_visible("\x1b[33mvery-long-value\x1b[0m", 8));
504491
}
492+
493+
#[test]
494+
fn column_widths_uses_max_line_not_sum_for_multiline_cells() {
495+
let mut table = SimpleTable::new(
496+
vec!["Date", "Models", "Input", "Output", "Cost (USD)"],
497+
vec![
498+
Align::Left,
499+
Align::Left,
500+
Align::Right,
501+
Align::Right,
502+
Align::Right,
503+
],
504+
TerminalStyle {
505+
no_color: true,
506+
..TerminalStyle::default()
507+
},
508+
)
509+
.with_terminal_width(200);
510+
// 5 models — a realistic single-agent scenario where the bug would be severe
511+
table.push(vec![
512+
"2026-05-18".to_string(),
513+
"- claude-sonnet-4-20250514 (self-serve)\n- claude-opus-4-5\n- gpt-5.2-codex\n- gemini-3.0-pro-wildly-long\n- claude-haiku-3-5-sonnet".to_string(),
514+
"1,234".to_string(),
515+
"56".to_string(),
516+
"$0.42".to_string(),
517+
]);
518+
let widths = table.column_widths();
519+
let models_width = widths[1];
520+
let cell = "- claude-sonnet-4-20250514 (self-serve)\n- claude-opus-4-5\n- gpt-5.2-codex\n- gemini-3.0-pro-wildly-long\n- claude-haiku-3-5-sonnet";
521+
let widest_line = visible_width_max_line(cell);
522+
let sum_of_lines = cell.lines().map(visible_width).sum::<usize>();
523+
// If visible_width_sum were still used, models_width would be ~180
524+
// With visible_width_max_line, it should be ~widest_line + padding
525+
assert!(
526+
models_width < sum_of_lines,
527+
"Models column width ({models_width}) should be based on widest line ({widest_line}), not sum of all lines ({sum_of_lines})"
528+
);
529+
assert!(
530+
models_width <= widest_line + 3,
531+
"Models width ({models_width}) should be close to widest line width ({widest_line}), not {sum_of_lines}"
532+
);
533+
}
505534
}

rust/crates/ccusage-terminal/src/width.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ pub(crate) fn visible_width_max_line(value: &str) -> usize {
3737
value.lines().map(visible_width).max().unwrap_or_default()
3838
}
3939

40-
pub(crate) fn visible_width_sum(value: &str) -> usize {
41-
value.lines().map(visible_width).sum()
42-
}
43-
4440
#[cfg(test)]
4541
mod tests {
4642
use super::*;

0 commit comments

Comments
 (0)