Commit Graph

46 Commits

Author SHA1 Message Date
Mitchell Hashimoto
86f81fb5b1 terminal: expose scrollback line limit 2026-07-26 20:13:45 -07:00
Chris Marchesi
e8525c0fd9 Update to Zig 0.16.0
This commit represents the majority of the work necessary to upgrade
Ghostty to use Zig 0.16.0.

Key parts:

* In addition to its previous responsibilities, the global state now
  houses state for global I/O implementations and the process
  environment. It is now also utilized in the main application along
  with the C library. Where necessary, global state is isolated from key
  parts of the implementation (e.g., in libghostty subsystems), and it's
  expected that this list will grow.

* We currently manage our own C translation layer where necessary. In
  these cases, cImport has been removed in favor of the new external
  translate-c package. Due to fixes that have needed be made to properly
  translate the dependencies that were swapped out, as mentioned, we
  have had to backport fixes from the current translate-c package (and
  the upstream Arocc dependency). We will host this ourselves until Zig
  0.17.0 is released with these fixes.

* Where necessary (only a small number of cases), some stdlib code from
  0.15.2 (and even from 0.17.0) has been taken, adopted, and vendored in
  lib/compat.

Co-authored-by: Leah Amelia Chen <hi@pluie.me>
2026-07-21 12:35:05 -07:00
Mitchell Hashimoto
c9ad708ef7 terminal: validate flattened highlight generations
RenderState applied flattened highlights after releasing the terminal
lock and matched them to copied rows by node address alone. A recycled
address could therefore make a stale asynchronous highlight decorate
unrelated content.

Capture the live node generation with each render row and require both
the pointer and copied generation to match. Validation remains lock-
free and never dereferences a potentially stale node.
2026-07-10 07:34:01 -07:00
Mitchell Hashimoto
421fe8dabe terminal: integrate compressed pages into PageList
PageList nodes previously exposed Page directly, so introducing a
compressed representation would require every consumer to understand its
state and ownership.

Add resident and compressed node states behind a page access boundary.
Content access transparently recommits and restores retained mappings,
while metadata traversal stays compressed and lifecycle paths can
discard encoded contents without decoding. Compression borrows pool
memory for standard scratch and uses temporary aligned storage for
oversized pages.

Migrate terminal, rendering, search, formatting, and C API consumers to
the new boundary. Hot grow, scroll, and print paths reuse resolved
pages, with an explicit resident-only accessor where live cursor
pointers prove that the page cannot be compressed.

The compression entry point remains private with no production callers,
so normal terminal behavior and scrollback accounting are unchanged.
ReleaseFast terminal-stream comparisons across bulk output, scrolling,
redraw, and erase workloads remain within 2% of the parent revision.
2026-07-09 09:47:11 -07:00
Mitchell Hashimoto
446f80f4ed terminal: render state update optimizations (~2.7x to ~11x less lock hold)
This optimizes `RenderState.update`, the per-frame call that snapshots
terminal state for the renderer and is the main reason the renderer
thread holds the terminal lock. 

Lock hold time is reduced ~2.7x to ~11x depending on the frame.

## The changes

1. iterate page chunks instead of rows in `update`
2. classify cells with masked vector compares. 
3. split the update into `beginUpdate`/`endUpdate` phases. There's a 
   lot to be gained by accumulating data with the lock held and then
   processing it out of the lock.
4. generalize the masked-compare scans into `page.Mask`. This is just
   a really common pattern we're doing now and it yields a ton of great
   value. Its error prone so lets make it a tested helper.

## Benchmarks

Measured with the new `ghostty-bench +screen-clone` modes (`render`,
`render-locked`, `render-clean`, `render-partial`), 120x80 terminal, M4
Max, macOS 26, ReleaseFast, hyperfine means of 10+ runs, per-update
times derived from fixed-count update loops with process startup
subtracted. "Lock held" is the time the terminal lock must be held per
update; "before" held the lock for the entire update.

| scenario | before (lock held) | after (lock held) | after (total) | lock change |
|----------|--------------------|-------------------|---------------|-------------|
| clean frame (nothing dirty) | 202 ns | 19 ns | 19 ns | 10.9x |
| partial frame (1 dirty row) | 290 ns | 54 ns | 54 ns | 5.4x |
| full rebuild, lightly styled | 6.9 µs | 2.5 µs | 3.0 µs | 2.7x |
| full rebuild, fully styled | 9.3 µs | 2.4 µs | 8.0 µs | 3.8x |
| full rebuild, fully styled, 250x150 | 49.9 µs | 9.4 µs | 31.6 µs | 5.3x |
| full rebuild, plain text | 1.9 µs | 1.9 µs | 1.9 µs | 1.0x (memcpy floor) |

The clean and partial cases are the steady-state frame costs (cursor
blink, mouse movement, typing). The full-rebuild cases are the contended
ones: colored scrolling output (build logs, htop, vim) moves the
viewport pin every frame, forcing a full rebuild exactly when the IO
thread is busiest, so that row of the table is where lock contention
actually hurts. Plain text was already at the memcpy floor and is
unchanged.

## LLM Notes

This work was driven by Fable 5: benchmarks, optimizations, the property
test, and the measurements above. I reviewed every line, simplified the
design in a few places (API naming, the Mask helper shape), and re-ran
the verifications myself.
2026-07-06 19:57:04 -07:00
Mitchell Hashimoto
f50aa90ced terminal: add lib.zig to centralize lib target and re-exports
Previously every file in the terminal package independently imported
build_options and ../lib/main.zig, then computed the same
lib_target constant. This was repetitive and meant each file needed
both imports just to get the target.

Introduce src/terminal/lib.zig which computes the target once and
re-exports the commonly used lib types (Enum, TaggedUnion, Struct,
String, checkGhosttyHEnum, structSizedFieldFits). All terminal
package files now import lib.zig and use lib.target instead of the
local lib_target constant, removing the per-file boilerplate.
2026-03-25 07:25:16 -07:00
Mitchell Hashimoto
32c97a019f terminal: default render state foreground to white
Fixes #11704

The RenderState empty initializer set both background and foreground
to the default RGB value of black (0, 0, 0), making text unreadable
when a caller has not explicitly configured terminal colors via
DynamicRGB. This is the common case for libghostty consumers.

Default the foreground to white so that the initial render state
provides readable white-on-black text out of the box.

Long term we also need to expose setting the default colors for a
Terminal instance but this is a workable fix in the mean time.
2026-03-21 20:24:02 -07:00
Mitchell Hashimoto
2876fb7a55 vt: expose dirty state in C API
Switch RenderState.Dirty to lib.Enum so it uses C-compatible enum
backing when building the C ABI target. Add GhosttyRenderStateDirty and
new ghostty_render_state_dirty_get/set declarations to the render header,
then wire both functions through src/terminal/c/main.zig and the lib_vt
export table.
2026-03-19 20:13:14 -07:00
Kat
6fabf775bb Lots of duplicate word typos + typo. 2026-03-16 09:19:09 +11:00
Mitchell Hashimoto
2044e5030f terminal: make stream processing infallible
The terminal.Stream next/nextSlice functions can now no longer fail.
All prior failure modes were fully isolated in the handler `vt`
callbacks. As such, vt callbacks are now required to not return an error
and handle their own errors somehow.

Allowing streams to be fallible before was an incorrect design. It
caused problematic scenarios like in `nextSlice` early terminating
processing due to handler errors. This should not be possible.

There is no safe way to bubble up vt errors through the stream because
if nextSlice is called and multiple errors are returned, we can't
coalesce them. We could modify that to return a partial result but its
just more work for stream that is unnecessary. The handler can do all of
this.

This work was discovered due to cleanups to prepare for more C APIs.
Less errors make C APIs easier to implement! And, it helps clean up our
Zig, too.
2026-03-13 13:56:14 -07:00
Mitchell Hashimoto
2a62f21bf0 fix tests 2026-02-19 14:10:33 -08:00
Mitchell Hashimoto
26b104c9e0 terminal: Fix possible crash on RenderState with invalid mouse point
Fixes #10032
2025-12-26 10:45:15 -08:00
Mitchell Hashimoto
5a2f5a6b9e terminal: RenderState linkCells needs to use Page y not Viewport y
Fixes #9957

Our `Page.getRowAndCell` uses a _page-relative_ x/y coordinate system
and we were passing in viewport x/y. This has the possibility to leading
to all sorts of bugs, including the crash found in #9957 but also simply
reading the wrong cell even in single-page scenarios.
2025-12-18 13:54:35 -08:00
Mitchell Hashimoto
d7087627d7 terminal: renderstate needs to reset highlights on dirty
This fixes memory corruption where future matches on a fully dirty row
would write highlights out of bounds. It was easy to reproduce in debug
by searching for `$` in `ghostty +boo`
2025-11-30 07:18:42 -08:00
Mitchell Hashimoto
10f19ebdc3 search: handle soft-wrapped lines in sliding window properly
Fixes #9752
2025-11-29 07:32:06 -08:00
Mitchell Hashimoto
b96b55ebde terminal: RenderState must consider first row in dirty page dirty 2025-11-26 13:20:16 -08:00
Mitchell Hashimoto
880db9fdd0 renderer: hook up search selection match highlighting 2025-11-25 11:05:38 -08:00
Mitchell Hashimoto
a4e40c7567 set proper dirty state to redo viewport search 2025-11-24 19:55:27 -08:00
Mitchell Hashimoto
dd9ed531ad render viewport matches 2025-11-24 19:55:27 -08:00
Mitchell Hashimoto
df466f3c73 renderer: make cursorStyle depend on RenderState
This makes `cursorStyle` utilize `RenderState` to determine the
appropriate cursor style. This moves the cursor style logic outside the
critical area, although it was cheap to begin with.

This always removes `viewport_is_bottom` which had no practical use.
2025-11-22 14:36:53 -08:00
Mitchell Hashimoto
82f5c1a13c renderer: clear renderstate memory periodically 2025-11-21 09:03:03 -08:00
Mitchell Hashimoto
c892599385 terminal: cache some selection state to make render state faster 2025-11-20 22:00:44 -08:00
Mitchell Hashimoto
7728620ea8 terminal: render state dirty state 2025-11-20 22:00:44 -08:00
Mitchell Hashimoto
86fcf9ff4a terminal: render state selection 2025-11-20 22:00:44 -08:00
Mitchell Hashimoto
a15f13b962 terminal: renderstate tests 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
5d58487fb8 terminal: update renderstate to use new assert 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
6e5e24c3ca terminal: fix lib-vt test builds 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
cd00a8a2ab renderer: handle normal non-osc8 links with new render state 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
fa26e9a384 terminal: OSC8 hyperlinks in render state 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
81142265aa terminal: renderstate stores pins 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
b8363a8417 terminal: update render state for new dirty tracking 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
07115ce9a9 terminal: render state contains raw row data 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
d1e87c73fb terminal: renderstate now has terminal colors 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
ebc8bff8f1 renderer: switch to using render state 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
9162e71bcc terminal: render state contains cursor state 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
29db3e0295 terminal: setup selection state on render state 2025-11-20 22:00:43 -08:00
Mitchell Hashimoto
0e13fd6b73 terminal: add more render state tests 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
4caefb807c terminal: fix up some performance issues with render state 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
5d85f2382e terminal: render state needs to preserve as much allocation as possible 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
a860801323 terminal: updating render state with tests 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
3f7cee1e99 terminal: render state fixes for empty cells 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
a66963e3f8 terminal: full redraw state tracking on render state 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
bbbeacab79 terminal: renderstate needs dirty state 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
60fe4af8ac terminal: render state style get requires non-default style 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
789b3dd38d terminal: RenderState.row_data is a MultiArrayList 2025-11-20 22:00:42 -08:00
Mitchell Hashimoto
a90fe1656a terminal: RenderState 2025-11-20 22:00:42 -08:00