When a DCS sequence has more than MAX_PARAMS parameters, entering
dcs_passthrough would write to params[params_idx] without a bounds
check, causing an out-of-bounds access. Drop the entire DCS hook
when params overflow, consistent with how csi_dispatch handles it.
Found by AFL fuzzing.
While it was renamed from ko_KR.UTF-8.po to ko.po in #10976, @uhojin,
a Korean locale maintainer, notes [1] that “ko_KR [*South* Korean] makes
more sense in locale context just to avoid any potential confusion
between 한국어 vs 조선어”.
Despite ko_KP (North Korean) not being present in glibc (as of version
2.43), and the ISO639 maintainers expressing disapproval of ko_KP [2],
it is possible opinions may change in the future, and individual
opinions may be contested—disambiguating doesn't hurt.
[1]: https://github.com/ghostty-org/ghostty/pull/10976#discussion_r2861424171
[2]: https://github.com/ghostty-org/ghostty/pull/10976#discussion_r2861359240
Following the discussion at #10852, I believe this is the right default.
I'm willing to continue to revisit this decisions, but Ghostty 1.3 is
around the corner and I don't think such a change like this should be
pushed into it.
I think palette generation is best left as a _theme author_ tool. A
Ghostty color theme could include `palette-generate=true` if it wants
to customize the 256-color palette more easily. Of course, end users can
as well anytime.
Another part of my reasoning is that TUI programs who want this behavior
can already achieve it themselves by mixing dark/light theme detection
via CSI 996 (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
with OSC 4/10/11 color query and change sequences, both of which are
decently supported in the terminal ecosystem and fully supported in
Ghostty.
I'm also open to considering some kind of new sequence to make this
easier for TUIs (probably a mode) where they can opt-in to palette
generation plus "harmonius" palettes (see `palette-harmonius`) and
Ghostty does it on demand then. I think that'd solve the legacy vs new
TUI argument where legacy programs can continue to make assumptions
about the palette and new programs can opt-in to a more dynamic palette
without having to do a lot of work themselves.
## Summary
Ports the phantom mouse-motion position-equality check from the GTK
runtime to the embedded runtime (used by macOS).
On macOS, TUI apps like Zellij that frequently update the window title
cause phantom `mouseMoved` events at the same coordinates. These flow
through `embedded.zig` → `Surface.zig` `cursorPosCallback` →
`showMouse()`, which explicitly calls
`NSCursor.setHiddenUntilMouseMoves(false)` and unhides the cursor,
defeating `mouse-hide-while-typing`.
The GTK runtime already filters these in PR #4973 (for #3345):
```zig
const is_cursor_still = @abs(priv.cursor_pos.x - pos.x) < 1 and
@abs(priv.cursor_pos.y - pos.y) < 1;
if (is_cursor_still) return;
```
This PR adds the same check to `embedded.zig`'s `cursorPosCallback`,
using the already-stored `self.cursor_pos` field.
## Test plan
- [x] Enable `mouse-hide-while-typing = true` in Ghostty config
- [ ] Run a TUI app that updates the window title frequently (e.g.
Zellij)
- [ ] Type — cursor should hide and stay hidden despite title updates
- [ ] Move the mouse — cursor should reappear normally
- [ ] Verify no regressions with normal mouse movement,
focus-follows-mouse, or link hovering
Implements parsing for OSC 3008, which allows terminal emulators to keep
track of the stack of processes that have current control over the tty.
The implementation mirrors existing `semantic_prompt.zig` architecture
and natively maps UAPI definitions to Zig structures with lazy
evaluation for optional metadata.
Fixes#10900
On macOS, TUI apps like Zellij that frequently update the window title
cause phantom mouse-move events to be generated at the same coordinates.
These phantom events reach cursorPosCallback in the core, which calls
showMouse() and explicitly unhides the cursor via
NSCursor.setHiddenUntilMouseMoves(false), defeating the
mouse-hide-while-typing feature.
This ports the same position-equality check already present in the GTK
runtime (added in PR #4973 for issue #3345) to the embedded runtime used
by macOS. If the cursor position hasn't changed by more than 1px, the
event is discarded.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use `std.meta.stringToEnum` in ContextType and ExitStatus
- Ensure `parseInt` only accepts digits for pids
- Use `@tagName` for string representation in Field
- Rename `fields_raw` to `metadata`
- Rename `readField` to `readOption`
Implements parsing for OSC 3008, which allows terminal emulators to keep track of the stack of processes that have current control over the tty. The implementation mirrors existing `semantic_prompt.zig` architecture and natively maps UAPI definitions to Zig structures with lazy evaluation for optional metadata.
Fixes#10900
* ensure that `ghostty.h` compiles during basic Zig tests
* ensure that non-exhaustive enums are kept synchronized between
`ghostty.h` and their respective Zig counterpart.
* adjust some enums that varied from established conventions
With zsh, when installing the ghostty terminfo on a server via the
ssh-terminfo shell integration, parts of the terminfo get mangled. In
particular, the newline escape sequence in
```
> infocmp -0 -x xterm-ghostty | grep ind=
...,ind=\n,indn=...
```
gets interpreted by `print` as a literal newline, which then just gets ignored / does not have the intended effect.
Documentation for the `-r` flag of `print` used in the fix is [here](https://zsh.sourceforge.io/Doc/Release/Shell-Builtin-Commands.html#:~:text=Ignore%20the%20escape%20conventions%20of%20echo.).
### Testing locally
You can directly demonstrate this locally. This outputs a host of warning messages:
```
ssh_terminfo=$(infocmp -0 -x xterm-ghostty 2>/dev/null)
print "$ssh_terminfo" | tic -x -
```
Whereas
```print -r "$ssh_terminfo" | tic -x -```
or
```infocmp -0 -x xterm-ghostty | tic -x -```
work without issue.
### Testing remotely
The most visible way is to observe the output of `htop` before and after the change.
More directly, the output of `infocmp -x xterm-ghostty | grep " ind="` should be
```ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=\n,```
instead of
```ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=,```
---
Discussed in #11031.
---
AI disclosure: I used Claude for parts of figuring out what was going on. The fix itself and the rest was written and tested by myself.
The C struct Palette.C declared colors as [265]Color.C, but the
terminal palette is 256 colors (terminal.color.Palette = [256]RGB)
and the C header ghostty_config_palette_s correctly uses colors[256].
The mismatch causes ghostty_config_get to write 265×3 = 795 bytes
through a pointer sized for 256×3 = 768 bytes, producing a 27-byte
buffer overflow. On macOS Release builds with stack protector enabled,
this triggers __stack_chk_fail → SIGABRT on launch.
Fixes#10406
ImGui_ImplOpenGL3_Shutdown() calls imgl3wShutdown() which dlcloses the
GL library handles but does not zero out the imgl3w function pointer
table (imgl3wProcs). When a GLArea is re-realized (e.g. during
reparenting), ImGui_ImplOpenGL3_Init() calls ImGui_ImplOpenGL3_InitLoader()
which checks "if (glGetIntegerv == nullptr)". Since the stale pointers
are non-null, it skips re-initialization. The next GL call through a
dangling function pointer causes a SIGSEGV.
Fix this by introducing ImGui_ImplOpenGL3_ShutdownWithLoaderCleanup()
which calls the normal shutdown and then zeroes the imgl3wProcs table,
forcing the next Init to reload GL function pointers via imgl3wInit().
Also properly destroy the ImGui context and reset widget state in
glAreaUnrealize so re-realize starts clean. This was extra but was
probably leaking memory.
Specifically:
iCurrentCursorStyle
iPreviousCursorStyle
iCurrentCursorVisible
iPreviousCursorVisible
Visibility calculated and updated independently from the typical cursor
unifrom updates to preserve cursor style even when not in the viewport
or set to be hidden
The PR introduces `lib-vt` Android support as discussed in #10902.
A few more notes:
- Introduces new CI for Android builds as a change requires NDK to be
configured.
- To build locally, it is required to have the NDK installed in the
system and either have the path exported via `ANDROID_NDK_HOME` pointing
to the exact NDK path or `ANDROID_HOME` or `ANDROID_SDK_ROOT` pointing
at the Android SDK path from which the build system will infer the NDK
path and version.
- 16kb page size alignment is configured for Android 15+. Builds are
backward compatible with 4kb page size devices.
Fixes#10548
Escaped characters in selection-word-chars are now correctly parsed,
allowing for characters like `\t` to be included in the set of word
characters.
Fixes#10680
The image state is used for drawing, so when we update it, we need to
acquire the draw mutex. All our other state updates already acquire the
draw mutex but Kitty images are odd in that they happen in the critical
area (due to their size).
I mostly did this to familiarize myself with the codebase and figured it
doesn't hurt to cover this with tests if more added logic in this area,
despite this logic receiving indirect coverage elsewhere. [Here's my
related
proposal](https://github.com/ghostty-org/ghostty/discussions/10807).
I gave more thought around how to expose some of these config values and
their metadata in the C api to eventually drive a settings UI and was
hoping for feedback before I proceed.
The cleanest path forward feels like annotating config values with
formal metadata around things like: supported platforms, whether or not
a restart is required, presentation metadata like grouping + ordering,
tolerated ranges for values, possible enum values, etc. My intent is
that Swift & other consumers can enumerate potential settings values
with metadata such as to drive the UI from the metadata.
---
AI Disclosure: I used Codex 5.3 to help me understand how the config
subsystem in zig is exposed to Swift via the C API. Codex wrote these
tests; but we brainstormed on a pragmatic coverage balance and I
understand how the tests work.
I mostly did this to familiarize myself with the codebase and figured it
doesn't hurt to cover this with tests if I add more in this area,
despite receiving indirect coverage elsewhere.
From #10554
> I can see there being space for some kind of new sequence that tells
the terminal that "hey, I want a semantic palette" or something, that is
better adjusted to themes automatically. But, I don't think we should
this by default.
> So my concrete proposal is to eliminate the inversion and bg => fg
ramp and do a more typical dark => light ramp (still taking into account
bg/fg, but keeping 16 black and 231 white). I think this is the only way
we can really make this a default on feature. I think this would address
all the negative reactions we've gotten to it.
This adds a new `palette-harmonious`, disabled by default, which allows
generated light themes to be inverted.
Implements the `output` option for the `scroll-to-bottom` configuration,
which scrolls the viewport to the bottom when new lines are printed.
Co-Authored-By: Sachin <sachinbeniwal0101@gmail.com>
The space-segment patterns in the path regex (dotted_path_space_segments
and any_path_space_segments) greedily consume text after a space even
when we know that the text is the start of a new independent path (e.g.,
`/tmp/bar` in `/tmp/foo /tmp/bar`).
Fix: Add two negative lookaheads after the space in both patterns:
- `(?!\.{0,2}\/)` → don't match if the next segment starts with `/`,
`./`, or `../`
- `(?!~\/)` → don't match if the next segment starts with `~/`