- RenderState stores styles sparsely (per-cell u16 style ids plus one
Style per distinct run) and skips plain cells with a single mask test
(Cell::is_plain). screen-clone render: 11.5 ms -> 4.1 ms (Zig 4.7).
row::never_extend_bg now takes a style accessor instead of a slice.
- Parser::next_with(byte, |action| ..) hands actions to a closure
instead of moving a 64-byte action array out; Parser::next remains a
wrapper over the same core (equivalence test added).
terminal-parser SGR: 538 ms -> 231 ms (Zig 354).
All Ghostty benchmarks are now at or below Zig's time; table in
docs/rewrite/notes/perf-P1.md (the parser benchmark uses next_with with
a discarding closure, which like Zig's `_ = actions` lets the optimizer
skip unused work).
Test Plan:
- cargo test --workspace
- ghostty-bench +screen-clone --mode=render / +terminal-parser
rustfmt.toml sets group_imports, imports_granularity and imports_layout,
which are nightly-only; agents formatted with stable rustfmt, which
ignored them. This is a formatting-only pass with `cargo +nightly fmt`.
Test Plan:
- cargo clippy --workspace --all-targets -- -D warnings
- cargo test --workspace
Adds crates/ghostty-bench, a port of ZIG/src/benchmark and src/synthetic:
the ghostty-bench binary (terminal-stream, terminal-parser,
codepoint-width, grapheme-break, is-symbol, osc-parser, screen-clone
with Zig's CLI) and ghostty-synthetic data generators (+ascii, +utf8,
+osc, plus a Rust-only +sgr mode).
Measured against Ghostty's own ghostty-bench built with Zig 0.15.2
(ReleaseFast) vs --profile production, the hot paths were optimized
without behaviour changes:
- Terminal::print single-lookup fast path for width-1 chars mid-line
- page grapheme allocator: bitmap first-fit instead of a linear scan
(was 38% of utf8 stream time; randomized equivalence test added)
- plain cells skip per-cell work in clear_cells and row cloning
- ASCII fast path + strict hand-written UTF-8 decoder (exhaustive
equivalence test against std)
- parser/OSC parser split into inlined fast and state-change paths
- RenderState allocates grapheme vectors only for grapheme rows
- Page::assert_integrity no-op stub so the production profile builds
terminal-stream is now at parity (ascii 1.08x, utf8 0.97x, SGR 1.04x of
Zig's time). Still slower: screen-clone (~2.6x, zero-filling fresh
cell Vecs vs Zig's lazily-zeroed mmap), osc-parser (1.9x), and the raw
parser on SGR data (1.5x). Full table in docs/rewrite/notes/perf-P1.md.
Test Plan:
- cargo test --workspace (no failures)
- cargo run --profile production -p ghostty-bench -- +terminal-stream
--data=<file> and compare with Zig's ghostty-bench
Integration pass over the terminal core (Codex/gpt-6-astra, reviewed):
- Screen now owns the real kitty ImageStorage; new/reset/teardown,
erase-display deletes and alternate-screen limit inheritance hook in
where Zig does, and Terminal implements ExecTerminal so kitty APC
commands execute against it. Exec tests use a real Terminal.
- The PageList gains the APIs Screen/Terminal needed (pin iterators,
cross-page row/partial-row clone, string allocator probing, dedup
before allocating hyperlinks, Top viewport fixup after erase, append_
grapheme no longer marking rows dirty), and the Screen/Terminal
workarounds for their absence are removed so the code mirrors Zig.
Public signatures are unchanged; downstream crates build as before.
Test Plan:
- cargo test -p ghostty-terminal (1252 passed, 0 ignored)
- cargo clippy -p ghostty-terminal --all-targets -- -D warnings
- render.rs ports render.zig: RenderState, the per-frame snapshot the
renderer consumes (rows, cells, styles, graphemes, selection,
highlights, cursor, colors), updated incrementally with Zig's full
redraw triggers and per-page/per-row dirty tracking. Cells are stored
struct-of-arrays; use the accessors.
- highlight.rs ports highlight.zig (untracked, tracked, flattened).
- formatter.rs ports formatter.zig: plain, VT and HTML output for
terminal, screen, page list and page, with selection, rectangle,
unwrap, trim, palette, codepoint maps, hyperlinks and pin/point maps.
Screen's test dump helpers now delegate to it.
Cargo.toml also picks up dependencies for the kitty graphics and search
modules that are being ported concurrently.
Test Plan:
- cargo test -p ghostty-terminal --lib (1243 passed; formatter 100/100,
render 15/15 Zig tests)