Files
ghostty/src
Mitchell Hashimoto b9d88292be terminal: speed up formatting anywhere from ~1.5x to ~8x (#13587)
This PR speeds up our formatting (plain text, html, and VT) by anywhere
from ~1.5x to ~8x.

The formatter is the hot path behind multiple features in Ghostty GUI:
clipboard copy (plain/VT/HTML), `write_screen_file`, `selectionString`,
and terminal search sliding window. It's also the hot path for
libghostty users, namely people like
[zmx](https://github.com/neurosnap/zmx) which utilize the VT formatter
to restore a terminal.

This PR also adds the benchmarking infrastructure for the formatter.

## How

- **Fast cell-run optimization.** For simple cells (single codepoint, no
style/hyperlink) we encode them as a single run rather than one at a
time.
- **Make some arguments comptime.** Generates more code but benchmarks
show it improves things, specifically for per-format switches that we do
a LOT.
- **Interned style id fast path.** Styles are interned per page, so id
equality implies style equality. We track the id of the active style and
skip the per-cell `Style` copy + `eql` when it matches.
- **Fast printing.** Avoid `std.fmt` where possible and assemble
integers, RGB colors, codepoints in fixed-width buffers with a single
memcpy. This was extracted partially to `fastprint.zig` so we can reuse
it.
- **Avoid double-formatting for tracked pins.** Previously we formatted
twice (once through a `Discarding` writer to count bytes) for pin maps.
Now I'm smarter about it and do a single pass.

## Performance

All on my machine, 80x24 terminal, 10K lines of scrollback.

| workload              | main     | this PR  | speedup | throughput |
| --------------------- | -------- | -------- | ------- | ---------- |
| plain / plain         | 5.74 ms  | 1.67 ms  | 3.4x    | 364 MB/s   |
| plain / vt            | 6.46 ms  | 1.04 ms  | 6.2x    | 596 MB/s   |
| plain / html          | 7.39 ms  | 2.32 ms  | 3.2x    | 308 MB/s   |
| unicode / plain       | 9.74 ms  | 5.42 ms  | 1.8x    | 276 MB/s   |
| unicode / vt          | 10.42 ms | 5.53 ms  | 1.9x    | 275 MB/s   |
| unicode / html        | 12.53 ms | 7.35 ms  | 1.7x    | 509 MB/s   |
| styled / plain        | 5.65 ms  | 1.69 ms  | 3.4x    | 360 MB/s   |
| styled / vt           | 9.07 ms  | 4.20 ms  | 2.2x    | 409 MB/s   |
| styled / html         | 10.78 ms | 6.64 ms  | 1.6x    | 740 MB/s   |
| mixed / plain         | 8.59 ms  | 4.81 ms  | 1.8x    | 226 MB/s   |
| mixed / vt            | 11.25 ms | 6.65 ms  | 1.7x    | 250 MB/s   |
| mixed / html          | 14.47 ms | 10.52 ms | 1.4x    | 414 MB/s   |
| wrapped / plain       | 7.30 ms  | 1.11 ms  | 6.6x    | 733 MB/s   |
| wrapped / vt          | 8.14 ms  | 1.04 ms  | 7.8x    | 789 MB/s   |
| wrapped / html        | 9.00 ms  | 2.12 ms  | 4.2x    | 465 MB/s   |
| pin-map / plain       | 12.51 ms | 3.80 ms  | 3.3x    |            |
| pin-map / vt          | 13.12 ms | 2.99 ms  | 4.4x    |            |
| active screen / plain | 12.5 µs  | 2.7 µs   | 4.6x    |            |
| active screen / vt    | 18.4 µs  | 6.8 µs   | 2.7x    |            |

Workloads: 
- `plain` is ASCII lines
- `unicode` is 2/3/4-byte codepoints with 10% grapheme clusters
- `styled` is heavy SGR churn
- `mixed` is styles + Unicode + hyperlinks
-  `wrapped` is a continuous soft-wrapped stream
- `pin-map`/`active screen` are the selectionString/search-style and
visible-screen-only cases respectively.
2026-08-03 20:56:46 -07:00
..
2026-08-02 20:24:30 -07:00
2026-08-02 20:24:30 -07:00
2026-08-02 20:24:30 -07:00
2026-03-15 20:58:43 -04:00
2026-07-21 12:35:05 -07:00
2026-07-30 08:51:38 -07:00
2026-08-02 20:24:30 -07:00
2026-07-21 17:19:16 -07:00
2025-10-03 18:52:26 +02:00
2026-07-21 12:35:05 -07:00
2026-07-21 17:19:16 -07:00
2026-07-21 12:35:05 -07:00
2025-11-27 13:37:53 -08:00
2025-11-27 13:37:53 -08:00
2026-08-03 20:10:19 -07:00
2026-08-02 20:24:30 -07:00
2026-07-21 12:35:05 -07:00
2026-07-21 17:19:16 -07:00
2026-07-21 12:35:05 -07:00
2026-07-21 17:19:16 -07:00
2026-07-21 17:19:16 -07:00
2024-08-16 14:35:10 -07:00
2026-07-21 17:19:16 -07:00
2022-08-18 11:42:32 -07:00
2026-03-20 10:37:42 -05:00
2026-07-21 12:35:05 -07:00
2026-07-21 12:35:05 -07:00