Terminal construction previously accepted GhosttyTerminalOptions with
dimensions and one scrollback byte limit. Remove the options struct from
the ABI and make ghostty_terminal_new accept columns and rows directly.
Add byte and line limit options to ghostty_terminal_set and forward them
to the runtime Terminal setters. NULL removes a limit, while zero bytes
disables scrollback. Update type metadata, tests, and all API examples.
Scrollback limits were fixed when a terminal screen was initialized.
Move byte and line state and enforcement into a shared Limits type so
PageList can update both constraints after initialization and resize.
Add runtime setters to PageList and Terminal. Lowering a limit prunes
eligible history immediately, while zero bytes switches the primary
screen to no-scrollback behavior and clears retained history. Keep
alternate screens unchanged.
This adds a new config `scrollback-limit-lines` to limit scrollback by
lines instead of bytes. This also renames `scrollback-limit` to
`scrollback-limit-bytes` to make it clear what it does but we have a
compatibility entry so old configurations will continue to work, so its
not breaking.
**This is NOT exclusive to `scrollback-limit-bytes`**. When both are
set, then the _first limit reached_ is used. Since lines is affected by
viewport size and bytes are affected by entries (more styles, more
graphemes, etc.), they serve somewhat different purposes and it might be
useful to set both.
The default remains 50MB of bytes, unlimited lines.
This is not exposed to libghostty yet. I have that coming as a follow up
change.
Was brought up as possibly being a build issue here:
https://codeberg.org/vancluever/translate-c/pulls/1
I do think that this is the better approach and seems to be the close
equivalent of the `.zig_ilb` option that's coming with `LazyPath` in
0.17.0 (which is how translate-c behaves there).
I was looking for something like this initially and I _think_ I might
have passed over it to start with because it was a bit hard to determine
the circumstances that `b.graph.zig_lib_directory` would be null, but
upon further examination, I think such cases would be rare if they
happened at all. Rather than default to the cwd in this event though I
just get it to error out - that way we'll know if it ever is the case!
Move DECRQSS response encoding into the terminal DCS handler so both the
full termio path and libghostty-vt terminal stream emit the same
replies. The C API stream now maintains and releases DCS parser state
and forwards responses through write_pty.
Move DECRQSS response encoding into the terminal DCS handler so both
the full termio path and libghostty-vt terminal stream emit the same
replies. The C API stream now maintains and releases DCS parser state
and forwards responses through write_pty.
The custom memset accepted its fill value as u8 even though C callers
pass int. Accept c_int and explicitly truncate it to the low byte, which
is what other implementations of this do.
DECRQSS previously serialized every active underline as SGR 4, which
caused double, curly, dotted, and dashed styles to round-trip as single
underlines.
Emit the 4:n form for extended underline styles while retaining the
legacy 4 form for single underlines, and cover every supported style.
Since the renderer thread now emits scrollbar events on almost every
frame, there's always a `.scrollbar` message for the dying surface in
the app mailbox.
The OS runtime seems to schedule `appTick` and `ghostty_surface_free`
differently across macOS pre-26, 26 and 27.
On macOS 26.x, `ghostty_app_free` happens after
`App.scrollbar(_:target:v:)`, leaving `surface.userdata` pointing at a
freed `SurfaceView`.
When `deinit` runs on the main thread, free the surface synchronously
instead of detaching to a task. This fixes both crashes mentioned in
https://github.com/ghostty-org/ghostty/pull/9512 and
https://github.com/ghostty-org/ghostty/issues/13359.
### AI Disclosure
I used Claude to analyze the backtrace, but the code is written and
tested by myself.
DECRQSS previously serialized every active underline as SGR 4,
which caused double, curly, dotted, and dashed styles to round-trip
as single underlines.
Emit the 4:n form for extended underline styles while retaining the
legacy 4 form for single underlines, and cover every supported style.
The custom memset accepted its fill value as u8 even though C callers
pass int. Accept c_int and explicitly truncate it to the low byte, which
is what other implementations of this do.
This PR provides an implementation for the
[vicinae-hotkey-v1](https://github.com/vicinaehq/vicinae-wayland-protocols/tree/main/staging/vicinae-hotkey)
protocol, as discussed
[here](https://github.com/ghostty-org/ghostty/discussions/13453).
This is a wayland protocol that allows the client to dynamically
negotiate global shortcuts with the compositor. Unlike the portal, the
clients are free to bind, rebind, and unbind global shortcuts they
reserve.
Here are a few advantages of using this over the global shortcut portal
for ghostty specifically:
- `vicinae-hotkey-v1` lets the client know the state of its bindings at
all time, if a global bind is not granted by the compositor the cllient
is notified with a descriptive error message which is designed to help
the user understand what the problem might be. In my implementation, I
decided I would show a desktop notification to the user in case a global
shortcut reservation fails.
- Global binds set in the config cannot drift from what is actually
registered, cannot be unilaterally changed by the user in compositor
settings, and do not pollute the global shortcut namespace permanently.
Reservations are only active while ghostty is running.
- The protocol provides the client with an input serial that can be used
to generate an `xdg_activation` token, allowing ghostty to steal focus
when one of its global shortcut is used. Currently ghostty doesn't have
an input serial to pass to `xdg_activation`. I didn't wire it for now,
in order keep things simple. But I guess it will be a nice to have.
---
AI disclosure: most of the code was written by Fable 5 (Claude Code), as
zig is not my primary language.
From an implementation perspective: I made it so that
`vicinae-hotkey-v1` is used to manage global shortcuts over the portal
when the global is advertised by the compositor. If it's not available,
we fallback on the portal like before.
At this time the protocol is implemented by Hyprland (since
[v0.56.0](https://github.com/hyprwm/Hyprland/pull/15010)) and there is
an open PR for [niri](https://github.com/niri-wm/niri/pull/4145). There
is also an official [wayland-protocols
proposal](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/525).
As for the clients, for now the only implementer (that I know of) is
[vicinae](https://github.com/vicinaehq/vicinae).
The idea would be to merge this `vicinae-hotkey-v1` implementation and
then have it be superseded by the upstream version later, assuming it is
turned into an official extension protocol following the
wayland-protocols process.
PS: sorry for the diff noise about all the .po changes, I'm not sure
whether this is intended or not, but I did regenerate the translations
as asked
Resizing tabstops to an already-supported width previously allocated and
copied an equally sized dynamic buffer because the capacity check
excluded equality. Treat an exactly sized buffer as sufficient, avoiding
the temporary allocation and copy.
Add a fixed-buffer regression test so an unnecessary second allocation
fails the test.
Environment variables from the "real" environment leaked into the test
after the Zig 0.16 update which would cause them to fail if you ran them
on a Gnome system.
Environment variables from the "real" environment leaked into the test
after the Zig 0.16 update which would cause them to fail if you ran them
on a Gnome system.
Replaces: https://github.com/ghostty-org/ghostty/pull/13427
Zig's Mach-O linker does not emit LC_ENCRYPTION_INFO_64 for physical iOS
dylibs. This allows libghostty-vt to build successfully but causes
frameworks containing it to fail App Store validation.
I think it'd be cleaner to always just build Apple targets on Apple
hosts with the native linker. We don't need to rely on Zig being correct
and this helps ensure compatibility for details like this.
Replaces: https://github.com/ghostty-org/ghostty/pull/13427
Zig's Mach-O linker does not emit LC_ENCRYPTION_INFO_64 for physical
iOS dylibs. This allows libghostty-vt to build successfully but causes
frameworks containing it to fail App Store validation.
I think it'd be cleaner to always just build Apple targets on Apple hosts
with the native linker. We don't need to rely on Zig being correct and
this helps ensure compatibility for details like this.
Xcode 27's math.h uses the __need_infinity_nan protocol provided by
matching Clang resource headers. Zig 0.16's bundled float.h predates
that protocol, causing the bundled libc++ compilation to fail.
Overlay the SDK math.h through the Apple SDK libc include path and
provide the missing infinity and NaN definitions. The compatibility
header can be removed once Zig's bundled Clang headers support the
protocol.
Xcode 27's math.h uses the __need_infinity_nan protocol provided by
matching Clang resource headers. Zig 0.16's bundled float.h predates
that protocol, causing the bundled libc++ compilation to fail.
Overlay the SDK math.h through the Apple SDK libc include path and
provide the missing infinity and NaN definitions. The compatibility
header can be removed once Zig's bundled Clang headers support the
protocol.