• pre-1.7-merge-20260827 63072bbe29

    leyoda released this 2026-04-23 23:20:40 +02:00 | 0 commits to local/pr-503 since this release

    Replaces 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: &str is 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