Skip to content

fix(review): reserve folder-emoji prefix width before truncating the worktree row - #574

Merged
jlong merged 1 commit into
mainfrom
jlong/review-sidebar-folder-row-clips-the-worktree-name-off-the-end-prefix-width-not-reserved-before-truncation
Aug 17, 2026
Merged

fix(review): reserve folder-emoji prefix width before truncating the worktree row#574
jlong merged 1 commit into
mainfrom
jlong/review-sidebar-folder-row-clips-the-worktree-name-off-the-end-prefix-width-not-reserved-before-truncation

Conversation

@jlong

@jlong jlong commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Task

The review pane's sidebar folder row shows a worktree path that is elided on the front AND clipped on the back, so the final folder name — the one identifying part a reviewer cares about — is lost. Observed on the contextstore review pane: the row reads 📁 ...els/ContextStore/.shelbi/wt/rev for the worktree /Users/jlong/Workspaces/32pixels/ContextStore/.shelbi/wt/review — the trailing review is cut to rev.

Current Behavior

crates/shelbi-tui/src/review_panel.rs, render_row, PanelRow::Folder (~line 633):

let label = truncate_left(&app.worktree, width.max(1));
...
ListItem::new(Line::from(Span::styled(format!("📂 {label}"), style)))

truncate_left is given the FULL row width and correctly keeps the tail (...wt/review). But the rendered line then prepends "📂 " (a 2-cell emoji + a space ≈ 3 display columns). The composed 📂 <label> line is now ~3 columns wider than width, so ratatui / the terminal clips the RIGHT edge — eating the tail that truncate_left just preserved. The path ends up elided on both ends and the worktree folder name is gone. The existing truncate_left unit test passes because it exercises the function in isolation, never the emoji-prefixed composed line.

Expected Behavior

The folder row shows the worktree's final segment(s) intact — e.g. 📂 ...ContextStore/.shelbi/wt/review, ending in review — front-elided with ... only as needed, and the composed line (emoji + space + path) never exceeds the row width.

Technical Details

Reserve the prefix's display width before truncating, e.g.:

// "📂 " = 2-cell emoji + 1 space. Prefer computing via unicode-width on the
// literal prefix rather than hardcoding, since emoji cell width is finicky.
let prefix = "📂 ";
let budget = width.saturating_sub(display_width(prefix)).max(1);
let label = truncate_left(&app.worktree, budget);

Use the same unicode-width helper the TUI already uses elsewhere for column math (grep the crate for how other rows measure display width) rather than assuming 1 col/char — the emoji is the whole reason the current code overruns. Double-check the emoji renders as the assumed cell count in the target terminals; if width is ambiguous, reserve the safe (larger) value.

Note: the screenshot header shows 📁 while the code uses 📂; the fix is the same regardless of which folder glyph is used — reserve the prefix's actual display width.

Acceptance Criteria

  • At realistic narrow sidebar widths, the review folder row shows the worktree's final segment intact (ends with the actual folder name, e.g. wt/review, never a clipped wt/rev).
  • The composed 📂 <path> line's display width is ≤ the row width — no right-edge clipping of the tail.
  • Front elision with ... still happens when the (prefix-reserved) budget requires it.
  • A unit test renders PanelRow::Folder at a narrow width and asserts (a) the rendered line's display width ≤ budget AND (b) it ends with the full final path segment — i.e. it exercises the composed emoji-prefixed line, not just truncate_left in isolation.
  • No regression to existing truncate_left behavior/tests.

Auto-opened by Shelbi — review at: /Users/jlong/.shelbi/projects/shelbi/tasks/review-sidebar-folder-row-clips-the-worktree-name-off-the-end-prefix-width-not-reserved-before-truncation.md

…worktree row

The sidebar folder row handed the full row width to `truncate_left` and
then prepended `"📂 "`, so the composed line ran ~3 display columns past
the row width and the terminal clipped the tail — the final worktree
segment a reviewer cares about (`wt/review` shown as `wt/rev`). The path
ended up elided on the front (by truncate_left) AND clipped on the back.

Reserve the prefix's true display width first, then left-truncate the
path into the remaining budget so the composed `📂 <path>` line always
fits the row and the trailing segment survives.

Decisions:
- Added `unicode-width` (already a workspace dep, used by shelbi-cli) to
  shelbi-tui and measure the emoji with `UnicodeWidthStr::width` rather
  than hardcoding 3. The existing `sidebar::display_width` is
  `chars().count()`, which under-counts the 2-cell emoji by a column and
  is the exact source of this class of bug — so I did not reuse it.
- Extracted `folder_row_text()` so the fix is unit-testable against the
  composed emoji-prefixed line (not `truncate_left` in isolation, which
  is what let the original bug slip past its passing test). New test
  asserts display width <= row width AND the trailing `wt/review`
  segment survives across a range of narrow widths, plus that front
  elision still engages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
shelbi Ready Ready Preview Aug 16, 2026 10:47pm

Request Review

@jlong
jlong merged commit 3d80ca5 into main Aug 17, 2026
3 checks passed
@jlong
jlong deleted the jlong/review-sidebar-folder-row-clips-the-worktree-name-off-the-end-prefix-width-not-reserved-before-truncation branch August 17, 2026 00:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant