cosmic-text/src
leyoda 63072bbe29 yoda: snap monospace cell width via Unicode East Asian Width
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.
2026-04-23 23:20:40 +02:00
..
edit feat: buffer setter methods are now lazy 2026-03-26 20:48:52 -06:00
font Log when default font family match fails due to weight mismatch 2026-03-06 17:01:35 -07:00
attrs.rs fix: find decoration spans in bidi text 2026-02-24 19:34:51 -07:00
bidi_para.rs refactor: address clippy warnings and improve code quality (#409) 2025-08-11 13:58:59 -06:00
buffer.rs fix: clamp scroll.line to a valid range 2026-04-09 16:41:52 -06:00
buffer_line.rs fix: shape_until_scroll if a buffer_line is modified 2026-03-31 14:47:11 -04:00
cached.rs fix: shape_until_scroll if a buffer_line is modified 2026-03-31 14:47:11 -04:00
cursor.rs refactor: address clippy warnings and improve code quality (#409) 2025-08-11 13:58:59 -06:00
glyph_cache.rs refactor: address clippy warnings and improve code quality (#409) 2025-08-11 13:58:59 -06:00
layout.rs chore: porting to decoration span 2026-02-24 19:34:51 -07:00
lib.rs feat: buffer setter methods are now lazy 2026-03-26 20:48:52 -06:00
line_ending.rs refactor: address clippy warnings and improve code quality (#409) 2025-08-11 13:58:59 -06:00
math.rs Support expanding tabs 2024-06-10 08:12:42 -06:00
render.rs fix: find decoration spans in bidi text 2026-02-24 19:34:51 -07:00
shape.rs yoda: snap monospace cell width via Unicode East Asian Width 2026-04-23 23:20:40 +02:00
shape_run_cache.rs resolve all lints, update MSRV 2025-01-22 17:00:01 -07:00
swash.rs Import CoreFloat when no_std is enabled 2026-04-01 10:25:56 -06:00