Completes the font engine port: - shaper/run.rs ports run.zig: the RunIterator over terminal rows that splits text runs at style/face boundaries, selection and cursor, handles graphemes and ligatures; Shaper::shape_run shapes a run. - shared_grid_set.rs ports SharedGridSet.zig: grids keyed by a config derived key, handed out as Arc<SharedGrid>. - Font-related types now have one canonical definition in ghostty-config (Variation, Descriptor, CodepointMap, metric modifiers, freetype load flags, synthetic style, shaping break) which the font crate re-exports. MetricModifier::apply_i32 now saturates to -i32::MAX like Zig. - The 23 terminal-driven harfbuzz shaper tests are ported, printing via Screen until Terminal lands. Test Plan: - cargo test -p ghostty-font (157 passed, 3 ignored - also skipped in Zig); Devanagari/Chakma/Bengali tests return early without system fonts - cargo test -p ghostty-config (255 passed)
5.0 KiB
5.0 KiB
ghostty-font — F2 (config integration, run iterator, SharedGridSet, terminal-dependent shaper tests)
Done
- Deps
ghostty-config,ghostty-terminalre-added (+ dev-depghostty-vtfor SGR/Rgb in tests). - Type unification (canonical definitions live in
ghostty-config, font re-exports):face::{Variation, VariationId}=ghostty_config::font_types(VariationId(u32);VariationId::init(b"wght"),.0,.str()).discovery::Descriptor= config's;Descriptor::toFcPatternis now the free fndiscovery::to_fc_pattern(&Descriptor).codepoint_map::{CodepointMap, Entry}= config'sCodepointMap/CodepointMapEntry(range: [u32; 2]).metrics::Modifier=ghostty_config::metric_modifier::MetricModifier(type alias;ModifierParseErrorandModifier::format_entry/parse_cliremoved, useparse/parse_cli_valueand the configConfigFieldimpl).ModifierSet/Keystay in font (+ newKey::ALL). Config'sapply_i32out-of-range now yields-i32::MAXlike Zig (only config edit besides doc comment infont_types.rs).config_types.rsis now only re-exports (FreetypeLoadFlags,FontSyntheticStyle,FontShapingBreak,FontStyle,GraphemeWidthMethod);face::FreetypeLoadFlagsre-exports config's.- INTEGRATION_TODO: removed the three font lines; config line narrowed to clipboard map / CursorStyle.
shaper/run.rs(run.zig):TextRun,RunCell,RunOptions,RunIteratorHooktrait (impl for harfbuzz + noop shapers),RunIterator. Full logic ported: invisible-cell skipping, right trim, selection/cursor splitting, spacer skipping, "fl/fi/st" ligature splits, style change splitting (bg ignored), font-style/presentation selection, grapheme font search (index_for_cell), U+FFFD / space fallback, Kitty placeholder, relative-cluster position-independent hash.shape.rsre-exportsTextRun/RunIterator/RunOptions/RunIteratorHook.shared_grid_set.rs(SharedGridSet.zig):SharedGridSet(new,ref_(Zigref),deref(&Key),count),DerivedConfig::new(&Config),Key(descriptors, style offsets, codepoint map, metric modifiers, font size, freetype flags; hashcode-equality like the Zig map), collection building incl. discovery, variation-retry, built-in JetBrains Mono / Nerd symbols / emoji fallbacks. Grids areArc<SharedGrid>; the set drops its Arc at ref-count 0.discovery::Fontconfigis nowClone(Arc inside) so the resolver shares the set's discoverer.harfbuzz::Shaper::shape_run(&SharedGrid, &TextRun)= Zigshape(run)(takes the grid write lock to get the face).
Tests
- SharedGridSet.zig: 5/5 (Key, Key different font points, Key different font DPI, SharedGridSet + extra
key_descriptors_and_modifiers). - All 23 deferred harfbuzz tests ported (in
shaper/harfbuzz.rs), plus F1's terminal-free ones kept. Font crate: 157 pass, 3 ignored. Ignored (alwayserror.SkipZigTestupstream, bodies ported from the commented-out Zig):shape_tai_tham_vowels_position_differs_from_advance,shape_tai_tham_letters_run_offset_y_differs_from_zero,shape_javanese_ligatures. - Tests needing a discovered system font (Devanagari + Bengali = "Arial Unicode MS", Chakma = "Noto Sans Chakma", Tibetan = "Noto Serif Tibetan") return early (Zig
SkipZigTest) when the font is missing; only Tibetan is installed on this machine (verified running); Devanagari/Chakma/Bengali are therefore not exercised here. - Removed duplicate tests that moved to config: F1's
variation_id_*in face.rs andformatconfig_*in metrics.rs (still covered by ghostty-config tests); adaptedmodifier_parse_errors.
Deviations / TODO(integration)
Terminal/RenderStatedo not exist (usable) in ghostty-terminal yet, so the tests use a smallTermhelper overScreen(shaper/test_util.rs):test_write_stringfor text, own grapheme-cluster attach viaghostty_unicode::grapheme_breakfor tests that enablegrapheme_clustermode,Screen::set_attributefor SGR,cursor_rightfor\e[5C.RunCell::from_page_row(page, y)replacesRenderStatecells (TODO(integration): switch to the terminal render-state cell type). OnceTerminalis final the tests can be rewritten to drive it with the VT stream.TextRunhas nogridfield (keeps itCopy); the iterator'sRunOptions.gridis&SharedGrid.RunIterator::next(&mut shaper)takes the shaper (hooks) per call instead of storing it, so the shaper can shape between calls.- Run hash uses std
DefaultHasher(Zig: Wyhash) — only used as a cache key. KITTY_PLACEHOLDER(0x10EEEE) is a local const (TODO(integration): terminal kitty graphics unicode module).- macOS Apple Emoji branch in the collection builder is omitted (Linux only); discovery is always available.
SharedGridSet::ref_holds the set lock while building the collection (as Zig).shared_grid::CellSizestill stands in forrenderer::CellSize.- Quality gate:
cargo build/testok; clippy with-D warningsfor ghostty-font passes with--no-deps(the dependency ghostty-terminal currently fails clippy in its in-progressterminal.rs, not my crate); fmt applied.