feat(font): add run iterator, shared grid set and config integration
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)
This commit is contained in:
1 parent
b64a2886ec
commit
7b408257c4
19 files changed
+3204
-554
No files matched your search
@@ -6,12 +6,10 @@ Collected from agent reports; resolve during integration phases.
|
||||
- [ ] os `locale::ensure_locale` no-op → call setlocale from apprt-gtk (unsafe allowed) at startup, as Ghostty's global.zig does.
|
||||
- [ ] os `passwd` Flatpak branch needs termio Pty.
|
||||
- [ ] os `open::OpenUrlKind` → replace with core apprt action type.
|
||||
- [ ] font `sprite/face.rs`: local `Presentation`/`RenderOptions` stand-ins → real font types (Phase 3).
|
||||
- [ ] font crate: re-add deps on config/unicode/terminal in Phase 3.
|
||||
- [ ] terminal crate: re-add deps on unicode/datastruct once those land.
|
||||
- [ ] input: key_encode::Options / paste::Options from terminal modes (Zig `fromTerminal`) — in terminal or core.
|
||||
- [ ] input: `binding::set::EntryFormatter` must be implemented by config formatter.
|
||||
- [ ] config: font_types.rs (Variation, CodepointMap, Descriptor), clipboard_codepoint_map::Entry, CursorStyle are local copies → unify with font/terminal.
|
||||
- [ ] config: clipboard_codepoint_map::Entry and CursorStyle are local copies → unify with terminal/formatter (font types are unified: canonical in ghostty-config, re-exported by ghostty-font).
|
||||
- [ ] config: url::REGEX needs onig (lookbehind) in renderer/core link matching.
|
||||
- [ ] config: theme::open needs resources dir from ghostty_os.
|
||||
- NOTE: Ghostty 1.3.1 is installed at /usr/bin/ghostty — use it as reference oracle (e.g. +show-config, +list-actions, terminfo).
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# ghostty-font — F2 (config integration, run iterator, SharedGridSet, terminal-dependent shaper tests)
|
||||
|
||||
## Done
|
||||
* Deps `ghostty-config`, `ghostty-terminal` re-added (+ dev-dep `ghostty-vt` for 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::toFcPattern` is now the free fn `discovery::to_fc_pattern(&Descriptor)`.
|
||||
* `codepoint_map::{CodepointMap, Entry}` = config's `CodepointMap`/`CodepointMapEntry` (`range: [u32; 2]`).
|
||||
* `metrics::Modifier` = `ghostty_config::metric_modifier::MetricModifier` (type alias; `ModifierParseError` and `Modifier::format_entry/parse_cli` removed, use `parse`/`parse_cli_value` and the config `ConfigField` impl). `ModifierSet`/`Key` stay in font (+ new `Key::ALL`). Config's `apply_i32` out-of-range now yields `-i32::MAX` like Zig (only config edit besides doc comment in `font_types.rs`).
|
||||
* `config_types.rs` is now only re-exports (`FreetypeLoadFlags`, `FontSyntheticStyle`, `FontShapingBreak`, `FontStyle`, `GraphemeWidthMethod`); `face::FreetypeLoadFlags` re-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`, `RunIteratorHook` trait (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.rs` re-exports `TextRun/RunIterator/RunOptions/RunIteratorHook`.
|
||||
* `shared_grid_set.rs` (SharedGridSet.zig): `SharedGridSet` (`new`, `ref_` (Zig `ref`), `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 are `Arc<SharedGrid>`; the set drops its Arc at ref-count 0. `discovery::Fontconfig` is now `Clone` (Arc inside) so the resolver shares the set's discoverer.
|
||||
* `harfbuzz::Shaper::shape_run(&SharedGrid, &TextRun)` = Zig `shape(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 (always `error.SkipZigTest` upstream, 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 and `formatconfig_*` in metrics.rs (still covered by ghostty-config tests); adapted `modifier_parse_errors`.
|
||||
|
||||
## Deviations / TODO(integration)
|
||||
* `Terminal`/`RenderState` do not exist (usable) in ghostty-terminal yet, so the tests use a small `Term` helper over `Screen` (`shaper/test_util.rs`): `test_write_string` for text, own grapheme-cluster attach via `ghostty_unicode::grapheme_break` for tests that enable `grapheme_cluster` mode, `Screen::set_attribute` for SGR, `cursor_right` for `\e[5C`. `RunCell::from_page_row(page, y)` replaces `RenderState` cells (`TODO(integration)`: switch to the terminal render-state cell type). Once `Terminal` is final the tests can be rewritten to drive it with the VT stream.
|
||||
* `TextRun` has no `grid` field (keeps it `Copy`); the iterator's `RunOptions.grid` is `&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::CellSize` still stands in for `renderer::CellSize`.
|
||||
* Quality gate: `cargo build/test` ok; clippy with `-D warnings` for ghostty-font passes with `--no-deps` (the dependency ghostty-terminal currently fails clippy in its in-progress `terminal.rs`, not my crate); fmt applied.
|
||||
Reference in new issue
Block a user