feat(statusline): wrap onto multiple rows on narrow terminalsFeat/responsive statusline wrapping#130
Open
fawaikuangtuzhangfei wants to merge 3 commits into
Conversation
added 2 commits
June 17, 2026 19:18
Claude Code truncates a single long statusline to `...` on narrow terminals. Since Claude Code renders each stdout line as a separate status row and exposes the terminal width via the COLUMNS env var, wrap the statusline by segment when it would overflow instead of letting it be truncated (which also hid the git branch and its ahead/behind/dirty markers). - Add generate_responsive(), which falls back to the existing single-line output when COLUMNS is unknown or the content fits, so behavior is unchanged for everyone else. - Read COLUMNS in main() to drive the wrapping. - Measure visible text with Unicode display width (unicode-width) so emoji and CJK glyphs count as the two columns they occupy; this also fixes the existing TUI preview wrapping. A one-column safety margin absorbs variation-selector emoji that render wider than the Unicode tables report. - Add unit tests covering the single-line, wide and narrow cases.
`patches.sort_by(|a, b| b.cmp(&a))` trips clippy::unnecessary_sort_by on recent toolchains, which fails CI (`cargo clippy -D warnings`). Use `sort_by_key` with `Reverse` for the same descending order.
Reviewer's GuideImplements responsive, width-aware statusline wrapping based on terminal column count, refactors statusline generation to support both single-line and wrapped output, adds tests for responsive behavior, and makes a small patcher sorting fix plus doc and dependency updates. Sequence diagram for responsive statusline generationsequenceDiagram
participant Main
participant Env
participant StatusLineGenerator
Main->>StatusLineGenerator: new(Config::default())
Main->>Env: detect_terminal_width()
Env-->>Main: Option<usize> max_width
Main->>StatusLineGenerator: generate_responsive(segments_data, max_width)
activate StatusLineGenerator
StatusLineGenerator->>StatusLineGenerator: join_segments(enabled_segments)
StatusLineGenerator->>StatusLineGenerator: visible_width(single_line)
alt max_width unknown or fits
StatusLineGenerator-->>Main: single_line
else exceeds budget
StatusLineGenerator->>StatusLineGenerator: wrap_segments(enabled_segments, budget)
StatusLineGenerator-->>Main: wrapped_lines
end
deactivate StatusLineGenerator
Main->>Main: println(statusline)
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
generate_responsive, segments are rendered once viajoin_segmentsand then re-rendered inwrap_segments; consider restructuring to reuse the already-rendered content to avoid duplicate work on every call. - In
wrap_segments, the use oflines.push(current_line.clone()); current_line.clear();in multiple places could be simplified to avoid unnecessary cloning by moving the string (e.g., viastd::mem::take) when finalizing a line.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `generate_responsive`, segments are rendered once via `join_segments` and then re-rendered in `wrap_segments`; consider restructuring to reuse the already-rendered content to avoid duplicate work on every call.
- In `wrap_segments`, the use of `lines.push(current_line.clone()); current_line.clear();` in multiple places could be simplified to avoid unnecessary cloning by moving the string (e.g., via `std::mem::take`) when finalizing a line.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Address review feedback on the wrapping change: - generate_responsive() rendered segments via join_segments and then re-rendered every segment again in the wrapping path. Extract render_enabled() so segments (and the configs Powerline needs) are produced once and reused by both the single-line join and the wrapped layout. - Use std::mem::take() when finalizing a wrapped line instead of clone() + clear(). As a side effect the Powerline join now indexes configs aligned to the non-empty rendered segments, fixing a latent off-by-one when a segment renders empty.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On narrow terminals the statusline is a single long line, so Claude Code
truncates it to
.... This hides not just usage info but the git branch nameand its ahead/behind/dirty markers.
Solution
Claude Code renders each stdout line as a separate status row and sets the
COLUMNSenv var to the terminal width. When the rendered line would exceedCOLUMNS, wrap it segment-by-segment onto multiple rows instead of letting itbe truncated.
generate_responsive()falls back to the existing single-line output whenCOLUMNSis unknown or the content fits → **noemoji / CJK glyphs count as 2 columns. This also fixes the existing TUI
preview wrapping, which used a character count.
⚡️) thatrender wider than the Unicode tables report.
unicode-widthis already a transitive dependency (via ratatui), so this onlypromotes it to a direct dependency.
The branch also includes a small
fix(patcher)commit to satisfyclippy::unnecessary_sort_byon recent toolchains, so CI stays green.Before / After (COLUMNS≈50)
Before:
🤖 Opus 4.8 | 📁 repo | 🌿 feature_2026…(branch + git status cut off)After:
Notes
COLUMNSis provided by Claude Code v2.1.153+. On older versions the width isunknown and the statusline stays single-line (unchanged).
Summary by Sourcery
Add responsive, multi-line statusline rendering based on terminal width to keep content visible on narrow Claude Code terminals.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation:
Tests: