-
released this
2026-04-23 23:20:40 +02:00 | 0 commits to local/pr-503 since this releaseReplaces the previous heuristic (font_monospace_em_width.is_none() ⇒ 2
cells) which was reviewed as unsound: Arabic, dingbats, math symbols and
other narrow scripts pulled from non-monospace fallback fonts would all
have been forced to 2 cells. It also didn't handle ZWJ emoji clusters
or ambiguous-width chars correctly.Proper fix, computed at shape time when
line: &stris in scope:- new ShapeGlyph.terminal_cells: u8 (0, 1 or 2)
- populated via unicode-width crate applied to the cluster text
line[start..end] (harfrust path, uses UnicodeWidthStr) or to the
single codepoint (no-font fallback path, UnicodeWidthChar) - layout_to_buffer consumes it when match_mono_width is Some:
x_advance = cells * mono_width
instead of the previous round(x_advance / mono_width) * mono_width
which produced variable cell counts for fallback glyphs.
Covers:
- ASCII + Latin → width 1 (unchanged visual)
- CJK + fullwidth → width 2 ✓
- Emoji (incl. ZWJ) → width 2 ✓ (cluster text handles the ZWJ case)
- Arabic / Hebrew → width 1 ✓ (was wrongly snapped to 2 before)
- Combining marks → width 0 ✓ (zero-advance, matches terminals)
- Variation selectors → width 0 ✓
Limitations: ambiguous-width chars (EAW=A) resolve to 1 via unicode-width
default; a 'cjk' ambiguous mode (unicode-width::UnicodeWidthChar::width_cjk)
could be exposed later as a Buffer flag if needed — not needed for typical
terminal use, matching most wcwidth implementations.Based on review feedback from lionel@wopr.io on the initial heuristic patch.
Downloads
-
Source code (ZIP)
1 download
-
Source code (TAR.GZ)
1 download