Skip to content

fix: use display-width-aware text utils for CJK character rendering#39

Merged
eitsupi merged 9 commits intomainfrom
fix/cjk-display-width
Feb 3, 2026
Merged

fix: use display-width-aware text utils for CJK character rendering#39
eitsupi merged 9 commits intomainfrom
fix/cjk-display-width

Conversation

@eitsupi
Copy link
Copy Markdown
Owner

@eitsupi eitsupi commented Feb 3, 2026

No description provided.

eitsupi and others added 3 commits February 3, 2026 13:31
Full-width characters (CJK, emoji) occupy 2 terminal columns but were
counted as 1 by .chars().count(), causing display corruption in the
history browser and help browser.

Add unicode-width crate and a shared pager/text_utils module that
performs all width calculations in display columns. Remove duplicated
truncate_str/is_truncated/scroll_display_str from both help.rs and
history_browser.rs in favor of the shared utilities.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Fix skip_columns overshoot: return actual columns skipped so callers
  can compensate when a wide char straddles the column boundary. Update
  scroll_display to pad with spaces when overshoot occurs, maintaining
  exact output width.
- Add doc note to pad_to_width clarifying intentional no-ellipsis
  truncation behavior.
- Add emoji tests (display_width, truncate_to_width) to document
  expected behavior and catch regressions on unicode-width upgrades.
- Remove stray blank line in help.rs.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Pin exact expected values in tests instead of permissive range/property
checks, so they can actually detect regressions on unicode-width upgrades.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds display-width-aware text handling for the pager UI so CJK/full-width characters render and truncate correctly in terminal columns.

Changes:

  • Introduces text_utils module implementing display-width-aware width, truncation, scrolling, and padding utilities (with tests).
  • Updates help/history pager rendering to use the new utilities instead of character-count-based logic.
  • Adds unicode-width as a workspace dependency and wires it into arf-console.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
crates/arf-console/src/pager/text_utils.rs New display-width-aware text utilities + unit tests.
crates/arf-console/src/pager/mod.rs Exposes the new text_utils module to sibling pager modules.
crates/arf-console/src/pager/history_browser.rs Switches truncation/padding/scrolling to display-width-aware utilities.
crates/arf-console/src/pager/help.rs Switches truncation/padding/scrolling to display-width-aware utilities.
crates/arf-console/Cargo.toml Adds unicode-width dependency via workspace.
Cargo.toml Pins workspace unicode-width version.
Cargo.lock Records the new dependency in the lockfile.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- truncate_to_width: return empty string when max_width==0 instead of
  returning "…" which violates the width contract
- scroll_display: add early guard for max_width==0 to prevent underflow
  panic on the bare `max_width - 1` subtraction
- scroll_display: pad the eff==0 (start) branch output when a wide char
  straddles the boundary, matching the behavior of middle and end branches
- Add tests for all three edge cases

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

- Assert exact string value for scroll_start_cjk_boundary_padding
  no-padding sub-case instead of width-only check
- Add non-zero scroll_pos case to scroll_zero_width test to confirm
  the early guard catches all paths

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…th==0

The previous commit changed truncate_to_width to return "" for
max_width==0 but missed updating the corresponding test in help.rs.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

eitsupi and others added 2 commits February 3, 2026 14:10
- scroll_display: add early guard for max_width==1 (always return "…")
- scroll_display: clamp overshoot to inner_cols in middle branch so
  output never exceeds max_width (e.g. max_width==2 with CJK text)
- help.rs: build footer as plain text before padding, apply dark_grey
  after pad_to_width to avoid ANSI escape sequences being counted as
  visible columns

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Assert exact output strings (" …", "……", "… ") in addition to
display_width checks, consistent with previous review feedback.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@eitsupi eitsupi merged commit 9857fc6 into main Feb 3, 2026
10 checks passed
@eitsupi eitsupi deleted the fix/cjk-display-width branch February 3, 2026 14:16
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.

2 participants