refactor(terminal): split terminal helpers into modules - #1127
Conversation
Break the ccusage-terminal crate out of the single lib.rs file while keeping the public exports unchanged. Move table rendering, terminal styling, title rendering, width handling, and terminal width discovery into focused private modules so future terminal work has clearer ownership. The snapshot outputs are unchanged; their files move only because the tests now live beside the extracted modules.
📝 WalkthroughWalkthroughThis PR refactors the ChangesTerminal Module Organization
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes The PR involves substantial refactoring of a monolithic module into five focused modules with significant implementation density. Review requires understanding the data shapes (Color, TerminalStyle, Align, SimpleTable), the width calculation logic (ANSI-aware visible width, char display width rules), conditional styling based on environment variables, terminal detection via ioctl and TTY checks, table rendering pipeline with column sizing and fitting heuristics, ANSI-aware truncation edge cases, and the public API re-export structure. The variety and interdependencies across modules demand reasoning for each layer, though homogeneous patterns within table rendering (wrapping, padding, truncation) provide some repetition. Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai please review this PR. The terminal crate has been split into focused modules while keeping the public API and snapshot-rendered output unchanged. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | d8c775e | Commit Preview URL Branch Preview URL |
May 23 2026, 01:36 PM |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 53546
Public API — fully preserved ✅ All 7 public symbols ( Module dependency graph — acyclic ✅ graph TD
lib["lib.rs (re-exports)"]
table["table.rs"]
style["style.rs"]
terminal["terminal.rs"]
title["title.rs"]
width["width.rs"]
lib --> table
lib --> style
lib --> terminal
lib --> title
table --> style
table --> terminal
table --> width
title --> style
title --> width
No circular dependencies; leaf modules ( Visibility modifiers — correct ✅
Snapshot files — correctly renamed ✅ All 4 snapshot files renamed to match new module paths ( Tests redistributed to their respective modules ✅ Everything looks good. Approving. [approve] |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rust/crates/ccusage-terminal/src/table.rs`:
- Around line 142-149: The compact-dates path sets first_column_min to 12 which
prevents the later narrowing to <=10; change the minimum passed to
fit_widths_to_terminal when self.compact_dates is true from 12 to 10 (i.e. let
first_column_min = if self.compact_dates { 10 } else { 10 } or simply use 10 for
the compact case), so that widths (the first column produced by
fit_widths_to_terminal) can be reduced to 10 and allow
compact_date_row()/with_date_compaction(true) to take effect; keep the existing
follow-up branch that applies widths.first_mut().max(10) if you want to enforce
the 10 floor.
In `@rust/crates/ccusage-terminal/src/width.rs`:
- Around line 30-35: Add the unicode-width crate to the crate dependencies and
replace the ad-hoc ASCII check in char_display_width with the unicode-width API:
import unicode_width::UnicodeWidthChar and return
UnicodeWidthChar::width_cjk(ch).map(|w| w as usize).unwrap_or(0) (or use
.unwrap_or(0) on UnicodeWidthChar::width if you prefer non-CJK semantics) so
combining marks return 0 and proper CJK/ambiguous widths return 2; update any
uses of char_display_width/visible_width to rely on this corrected width
calculation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c715bac3-eb14-401e-9f4c-66a31686e28c
⛔ Files ignored due to path filters (4)
rust/crates/ccusage-terminal/src/snapshots/ccusage_terminal__table__tests__snapshots_ansi_truncation_boundary.snapis excluded by!**/*.snaprust/crates/ccusage-terminal/src/snapshots/ccusage_terminal__table__tests__snapshots_full_table_with_multiline_cells_and_separators.snapis excluded by!**/*.snaprust/crates/ccusage-terminal/src/snapshots/ccusage_terminal__table__tests__snapshots_narrow_table_with_wrapping_truncation_and_compact_dates.snapis excluded by!**/*.snaprust/crates/ccusage-terminal/src/snapshots/ccusage_terminal__title__tests__snapshots_multiline_box_title_layout.snapis excluded by!**/*.snap
📒 Files selected for processing (6)
rust/crates/ccusage-terminal/src/lib.rsrust/crates/ccusage-terminal/src/style.rsrust/crates/ccusage-terminal/src/table.rsrust/crates/ccusage-terminal/src/terminal.rsrust/crates/ccusage-terminal/src/title.rsrust/crates/ccusage-terminal/src/width.rs
There was a problem hiding this comment.
1 issue found across 10 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="rust/crates/ccusage-terminal/src/table.rs">
<violation number="1" location="rust/crates/ccusage-terminal/src/table.rs:147">
P2: `compact_dates` fallback uses `max(10)`, which does not reduce the first column width, so date compaction may never activate in narrow tables.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| fit_widths_to_terminal(widths, &self.aligns, self.terminal_width, first_column_min); | ||
| if self.compact_dates && total_required > self.terminal_width { | ||
| if let Some(width) = widths.first_mut() { | ||
| *width = (*width).max(10); |
There was a problem hiding this comment.
P2: compact_dates fallback uses max(10), which does not reduce the first column width, so date compaction may never activate in narrow tables.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage-terminal/src/table.rs, line 147:
<comment>`compact_dates` fallback uses `max(10)`, which does not reduce the first column width, so date compaction may never activate in narrow tables.</comment>
<file context>
@@ -0,0 +1,508 @@
+ fit_widths_to_terminal(widths, &self.aligns, self.terminal_width, first_column_min);
+ if self.compact_dates && total_required > self.terminal_width {
+ if let Some(width) = widths.first_mut() {
+ *width = (*width).max(10);
+ }
+ }
</file context>
ccusage
@ccusage/ccusage-darwin-arm64
@ccusage/ccusage-darwin-x64
@ccusage/ccusage-linux-arm64
@ccusage/ccusage-linux-x64
@ccusage/ccusage-win32-arm64
@ccusage/ccusage-win32-x64
commit: |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
|
@coderabbitai I split the two behavior changes into follow-up PR #1129. Please re-check #1127 as a mechanical module split with unchanged rendered snapshots and public API. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 50841
Public API — preserved ✅ All 7 symbols ( Logic — zero changes ✅ Every function body, struct field, match arm, and algorithm in Visibility promotions — structural only ✅
Neither change affects runtime behavior. Snapshot files — rendered content unchanged ✅ All 4 snapshots were renamed to match new module paths ( No behavior changes in this PR. Approving. [approve] |
Splits the ccusage-terminal Rust crate out of its single lib.rs file into focused private modules for table rendering, styling, terminal width detection, title rendering, and display width helpers.
The public exports remain unchanged from lib.rs, and the terminal snapshots keep the same rendered output with only their module paths updated.
@coderabbitai please review this refactor, especially that the module split preserves the existing public API and snapshot output.
Testing:
Summary by cubic
Split the
ccusage-terminalcrate’s singlelib.rsinto focused internal modules with no public API or terminal output changes.table,style,title,terminal, andwidth.lib.rsre-exports.Written for commit d8c775e. Summary will update on new commits. Review in cubic
Summary by CodeRabbit