Skip to content

Fix CJK lines wrapping in the overlay (exact wide-char padding) - #180

Open
cocomode18 wants to merge 2 commits into
Morantron:developfrom
cocomode18:fix/cjk-double-width-padding
Open

Fix CJK lines wrapping in the overlay (exact wide-char padding)#180
cocomode18 wants to merge 2 commits into
Morantron:developfrom
cocomode18:fix/cjk-double-width-padding

Conversation

@cocomode18

Copy link
Copy Markdown

Problem

In panes containing CJK text, every line wraps in the fingers overlay, leaving a
blank row beneath it — the visible content appears to grow / become double-spaced
the moment fingers is triggered. ASCII-only lines are unaffected.

Root cause

Hinter#process_line pads each rendered line to the pane width, correcting for
double-width characters with:

double_width_correction = ((line.bytesize - line.size) / 3).round.to_i

This /3 is tuned for 4-byte emoji (3 extra bytes → +1 column) but under-counts
3-byte CJK characters
: a CJK char has bytesize - size == 2, so it contributes
2/3 ≈ 0.67 instead of the 1 extra column it actually occupies.

The correction therefore comes out too small, padding_amount too large, and the
rendered line exceeds the pane width by ~N/3 columns (N = CJK chars on the line).
The terminal wraps it, and the trailing "\n" then lands a row lower — so each
CJK line consumes two rows. Worked example at width 100:

line wide chars rendered display width
最終形: 3 101 → wraps
- リンク開く → Shift+Cmd+Click … 16 105 → wraps
* Crunched for 5s (ASCII) 0 100 → exact

Fix

Count wide characters exactly instead of estimating from byte length, using the
Unicode East Asian Width Wide/Fullwidth ranges plus the common emoji blocks.
Emoji remain wide, so they are unaffected; ambiguous-width symbols (box-drawing,
powerline glyphs) are deliberately excluded because terminals render them one
column wide.

Tests

Adds specs covering CJK line padding (no overflow at the target width), exact
wide-char counting, and emoji non-regression. crystal spec spec/lib/fingers/hinter_spec.cr
passes (6 examples, 0 failures).

cocomode18 and others added 2 commits June 29, 2026 16:36
The padding correction for double-width characters used
`(line.bytesize - line.size) / 3`, which is tuned for 4-byte emoji
and under-counts 3-byte CJK characters. The shortfall over-padded
every line containing CJK text, pushing it past the pane width so it
wrapped, leaving a blank row beneath each line in the fingers overlay.

Replace the heuristic with an exact wide-character count based on the
Unicode East Asian Width Wide/Fullwidth ranges plus the common emoji
blocks (emoji stay wide, so they are unaffected). Ambiguous-width
symbols such as box-drawing and powerline glyphs are deliberately
excluded since terminals render them one column wide.

Add specs covering CJK padding, exact wide-char counting, and emoji
non-regression.
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