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.
* Use HarfRust for shaping
* Replace ttf-parser with skrifa entirely
* Fix clippy lints
* Add shape plan cache
* Bump harfrust and skrifa
* Fix no_std build
* Simplify the shape plan cache
* Please the paperclip
* Cache font ID with plan
* Tune shape plan cache for "BiDi Processing" bench
- Fix string formatting with modern interpolation syntax
- Improve Debug implementation with finish_non_exhaustive()
- Fix function placement in shape.rs to avoid items_after_statements warning
- Use more idiomatic Rust patterns (map_or_else, next_back)
- Clean up conditional imports in vi.rs
- Convert multiple methods to `const` functions for optimization and consistency
- Introduce `core_maths` for enhanced no-std compatibility
- Update `Cargo.toml` for the new optional dependency and feature adjustments
* Optimize BidiParagraphs with ASCII fast path - Added fast path for ASCII text that avoids BidiInfo allocation - Added some text shaping benchmarks
* refactor: fix clippy warnings and cleanup imports