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>
The renderer state mutex is unfair on all platforms (os_unfair_lock
on macOS, a futex based lock elsewhere). A thread that unlocks and
right away locks again wins over a sleeping waiter, because the
waiter first has to be woken up and scheduled. The termio parse
thread does exactly this under heavy pty output: it relocks the
mutex for every batch and never sleeps in between, so the renderer
can starve in updateFrame for as long as the output lasts.
Fix this by letting the parse thread stay off the lock until the
renderer had its turn. `renderer.State` gets two atomics: a waiter
count (`demand`) and a generation counter (`handoff_gen`). The renderer
takes the mutex through lockDemand/unlockDemand which update these,
and the parse thread calls yieldToDemand between batches. If a
waiter exists it sleeps on a futex until the renderer took and
released the lock, with a 1ms timeout so a lost wake can not stall
IO forever.
All the atomics are monotonic on purpose: they are only a hint for
scheduling, the mutex still protects the terminal state itself.
When the renderer is not waiting the cost for the parse loop is a
single relaxed atomic load per batch.
Fixes#882
We previously had a hardcoded limit of 16 codepoints. In #882, a user
pointed out that in Chinese, is reasonable for a preedit input to be
longer than this.
To avoid any future issues, this commit moves to a heap-allocated
variant. Preedits aren't that common, they aren't high throughput, and
they're generally pretty small, so using a heap allocation is fine. The
memory is owned by the person who set it.
This makes a few major changes:
- cursor style on terminal is single source of stylistic truth
- cursor style is split between style and style request
- cursor blinking is handled by the renderer thread
- cursor style/visibility is no longer stored as persistent state on
renderers
- cursor style computation is extracted to be shared by all renderers
- mode 12 "cursor_blinking" is now source of truth on whether blinking
is enabled or not
- CSI q and mode 12 are synced like xterm