Repository navigation
Merge upstream 2026 10 29 - #11
Merged
Merged
Conversation
Also clamp keyboard split resizes to the split size, which fixed an assertion failure when resize_split moved past the edge of a split. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Zig 0.17 port replaced the absolute path to the executable in the desktop file, D-Bus services and systemd user service with a bare `ghostty`, since the install prefix is no longer known while the build is configured. systemd resolves a bare ExecStart= name against a fixed search path rather than PATH: /usr/bin and /usr/local/bin on most systems, and only systemd's own directory on NixOS. So the service failed to start for any install outside those directories, including every Nix one. -Dinstalled-exe-path gives the absolute path to write into those files. Without it they still name the executable alone, which is right for packages installing to /usr. The Nix package passes its output path, and the Flatpak manifests pass /app/bin/ghostty, which is what they produced before the port.
Run `systemd-analyze verify` on the systemd user service, and check that every Exec= and TryExec= in the D-Bus service and desktop file is an absolute path to an executable, so a build that stops passing -Dinstalled-exe-path fails instead of shipping a service systemd can't start. The verifier starts a user manager, which needs a writable runtime directory that the sandbox doesn't have, so it gets one under $TMPDIR.
While a chunked Kitty graphics load was in progress, every transmit or animation frame command was treated as its next chunk, regardless of its transmission medium. A file (`t=f`), temporary file (`t=t`), or shared memory (`t=s`) command arriving mid-load had its encoded path appended to the partial image as pixel data. This diverged from Kitty. The spec only defines chunking for direct data, and continuation chunks must carry only the `m` and `q` keys, so a command with another medium can never be a continuation. Kitty abandons the in-progress load and handles the command as a new transmission, for both image and animation frame loads. A client that interrupts a load this way now gets the image or frame it asked for instead of a corrupted or failed one. `execute` now destroys the in-progress load before dispatching any non-direct transmit or frame command, so the command is handled as a fresh transmission, including its own `q` setting.
ECMA-48 says a control string that is cancelled or aborted is thrown away. xterm only dispatches a control string on ST, and Kitty only ends an APC on ST or BEL, so neither runs the command. https://ecma-international.org/publications-and-standards/standards/ecma-48/
…(#14811) While a chunked Kitty graphics load was in progress, every transmit or animation frame command was treated as its next chunk, regardless of its transmission medium. A file (`t=f`), temporary file (`t=t`), or shared memory (`t=s`) command arriving mid-load had its encoded path appended to the partial image as pixel data. This diverged from Kitty. The spec only defines chunking for direct data, and continuation chunks must carry only the `m` and `q` keys, so a command with another medium can never be a continuation. Kitty abandons the in-progress load and handles the command as a new transmission, for both image and animation frame loads. A client that interrupts a load this way now gets the image or frame it asked for instead of a corrupted or failed one. `execute` now destroys the in-progress load before dispatching any non-direct transmit or frame command, so the command is handled as a fresh transmission, including its own `q` setting.
ECMA-48 says a control string that is cancelled or aborted is thrown away. xterm only dispatches a control string on ST, and Kitty only ends an APC on ST or BEL, so neither runs the command. https://ecma-international.org/publications-and-standards/standards/ecma-48/
A stream continuation that ended after an 8-bit C1 introducer had aborted an APC could not be exported. For example, `ESC _ data 0x9B` ends the APC and starts a CSI, but the tracker only treats ESC as the start of a new sequence, so it kept the aborted APC. Replaying that would end the APC a second time, and validation rejected it. Export now starts at the last C1 introducer that moved the parser into a new sequence and writes it in its 7-bit ESC form.
The Zig 0.17 port replaced the absolute path to the executable in the
desktop file, D-Bus services and systemd user service with a bare
`ghostty`, since the install prefix is no longer known while the build
is configured. systemd resolves a bare ExecStart= name against a fixed
search path rather than PATH: /usr/bin and /usr/local/bin on most
systems, and only systemd's own directory on NixOS. So the service
failed to start for any install outside those directories, including
every Nix one.
-Dinstalled-exe-path gives the absolute path to write into those files.
Without it they still name the executable alone, which is right for
packages installing to /usr. The Nix package passes its output path, and
the Flatpak manifests pass /app/bin/ghostty, which is what they produced
before the port.
Fixes #14805
AI disclosure: Claude Code was used in the preparation of this PR.
A stream continuation that ended after an 8-bit C1 introducer had aborted an APC could not be exported. For example, `ESC _ data 0x9B` ends the APC and starts a CSI, but the tracker only treats ESC as the start of a new sequence, so it kept the aborted APC. Replaying that would end the APC a second time, and validation rejected it. Export now starts at the last C1 introducer that moved the parser into a new sequence and writes it in its 7-bit ESC form.
…`ghostty_osc_free` Signed-off-by: Uzair Aftab <git@uzaaft.me> Change-Id: I4efdf6a51f568b4bc2678ef4a6aa1c106a6a6964
…`ghostty_osc_free` (#14818)
Triggered by [discussion comment](ghostty-org/ghostty#14822 (comment)) from @jcollie. Vouch: @AlJohri Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Implement the kitty_read, kitty_write, and list (paste event) requests in the GTK apprt on top of the existing core protocol support, and wire the confirmation dialog up to Kitty requests, including session-grant remember support. Also fix two adjacent issues found while testing: the clipboard-write signal now carries a "cleared" flag so image-only writes toast as copies instead of clears, and a failed OSC 52 text read now answers with an empty reply instead of leaving the client waiting forever. TODO: the new remember-row strings in the confirmation dialog are deliberately not marked for translation; wrap them in i18n._() and regenerate the translation files once they should be translated.
Decode the first image/* representation of a Kitty clipboard request with gdk_texture_new_from_bytes and show it in the dialog in place of the text preview, falling back to the text preview when there is no decodable image. The picture's paintable and the visible preview page are bound declaratively to the clipboard-image property.
Remembering the denial set clipboard-read to deny before the request was answered, and the OSC 52 reply is written by the same path that serves an allowed read, which asserts reads aren't denied.
A multipart payload was reduced to one preview — the first decodable image, else the first text, else a bare list of MIME types — so the user authorized data they were never shown. The dialog now gives each representation its own page, named by MIME type.
The script exited as soon as it had written the transaction, so the terminal's status packet arrived with nothing left to read it and printed itself on the next shell prompt. It also carries a name and a session password now, so a run exercises the permission prompt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Erasing scrollback (ED3) moved Kitty image placements anchored in the erased rows onto the top-left of the active area, where they became visible again until the next screen clear. PageList.eraseRows moves tracked pins in erased rows to the top-left of the retained rows without marking them garbage, so the image storage never noticed the placement had lost its row. Remove pin-backed placements in the erased history range (and any relative placements orphaned by that) before erasing the rows, while their pins still identify them. The PageList pin semantics are left unchanged since search relies on erased pins not being garbage. Fixes: #14831
Erasing scrollback (ED3) moved Kitty image placements anchored in the erased rows onto the top-left of the active area, where they became visible again until the next screen clear. PageList.eraseRows moves tracked pins in erased rows to the top-left of the retained rows without marking them garbage, so the image storage never noticed the placement had lost its row. Remove pin-backed placements in the erased history range (and any relative placements orphaned by that) before erasing the rows, while their pins still identify them. The PageList pin semantics are left unchanged since search relies on erased pins not being garbage. Fixes: #14831 AI disclosure: Claude Code was used in the preparation of this PR.
StreamHandler.changeConfig queued a color_scheme_report message into the termio mailbox. changeConfig runs on the io thread, which is the only reader of that mailbox, so when the mailbox was full (for example, from a burst of query replies queued by the reader thread) the io thread blocked forever pushing to itself. Every other thread then blocked on its next send to the same mailbox, freezing Ghostty on a config reload. Write the report from Termio.changeConfig instead, using the same colorSchemeReportLocked the message handler uses. The report still follows the config update in order with other output. Fixes: #14833
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes a regression of #1297 on GTK. **Issue** Splits can be dragged or resized down to 0px, which just looks like a thick divider. The 10px minimum from #1323 was lost in the GTK rewrite. **Fix** Splits are now at least one cell plus padding in size, and the divider can't be dragged past that. This also clamps keyboard resizes. Tested on Fedora 44. Dragging and `resize_split` stop at one column or line. I believe that macOS already has its own minimum and is unchanged. First pass written with Claude Code (Claude Opus 5.5), reviewed and reprompted by me.
Triggered by [discussion comment](ghostty-org/ghostty#14844 (comment)) from @jcollie. Denounce: @ifmael Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Fix hexadecimal letter conversion in CommaSplitter's Unicode escape
validation. Letters a-f and A-F were interpreted as 0-5 instead of
10-15, allowing oversized escapes such as \u{aaaaaa} to pass validation.
Add regression tests for lowercase and uppercase escapes.
Validation:
- Standalone tests: 27 passed, 3 Windows tests skipped.
- Formatting: passed.
AI assistance: Used OpenAI Codex for diagnosis, explanations, code/test
suggestions, validation, and PR wording.
These have been broken since Zig 0.17, I think snap since before that. The snap moves to core26 (Ubuntu 26.04), which ships new enough GTK, libadwaita, and harfbuzz. It also uses the system gtk4-layer-shell now that Ubuntu packages it, and redirects `-lbzip2` to `libbz2.so` with a one-line linker script, the same way the flatpak already does.
Add the VT420 horizontal scrolling sequences: - DECIC (CSI Pn ' }) inserts columns at the cursor in every row of the scrolling region. - DECDC (CSI Pn ' ~) deletes columns at the cursor in every row of the scrolling region. - DECBI (ESC 6) moves the cursor left, or at the left margin scrolls the region right. - DECFI (ESC 9) moves the cursor right, or at the right margin scrolls the region left, losing the column at the left margin. DECIC and DECDC do nothing when the cursor is outside the scrolling region. The new stream actions are appended to the C ABI action list so that existing values are unchanged. This fixes 20 esctest failures (DECICTests, DECDCTests, DECBITests, and DECFITests now pass in full).
`CodepointIterator` could panic on incomplete UTF-8, such as a lone 0xC2 byte, when slicing beyond the available input. Check the remaining byte count before slicing and return `InvalidString` for truncated sequences. Test incomplete two-, three-, and four-byte sequences in the iterator and `SelectionWordChars.parseCLI`. Validation: - `zig build test -Dtest-filter=SelectionWordChars -Dtest-filter=codepointIterator -Demit-macos-app=false`: 91 tests passed. - Standalone string helper tests: 13 passed. - Formatting and whitespace checks passed. AI disclosure: OpenAI Codex assisted with the code, tests, and PR description.
Signed-Off-By: Paal Øye-Strømme <paal.o.eye@gmail.com>
goto() indexes the node and spatial slot arrays with `from` unchecked. The only caller (GTK SplitTree.goto) never reaches it with an empty tree, so make the precondition explicit like remove() does instead of silently returning null.
also updated the stale code sources
Just a small update that I did to catch a bit of missing API that I wanted to expose in `Context`, nothing that affects Ghostty, however. Had to skip 0.13.1 because of an issue with my release tooling. :man_facepalming:
Add the VT420 horizontal scrolling sequences: - DECIC (CSI Pn ' }) inserts columns at the cursor in every row of the scrolling region. - DECDC (CSI Pn ' ~) deletes columns at the cursor in every row of the scrolling region. - DECBI (ESC 6) moves the cursor left, or at the left margin scrolls the region right. - DECFI (ESC 9) moves the cursor right, or at the right margin scrolls the region left, losing the column at the left margin. DECIC and DECDC do nothing when the cursor is outside the scrolling region. The new stream actions are appended to the C ABI action list so that existing values are unchanged. This fixes 20 esctest failures (DECICTests, DECDCTests, DECBITests, and DECFITests now pass in full). AI disclosure: Claude Code was used in the preparation of this PR.
`SplitTree.goto()` indexes `self.nodes` / the spatial slots with `from` without checking it. On an empty tree, `.previous_wrapped`, `.next_wrapped` and `.spatial` hit `index out of bounds: index 0, len 0`; `.previous` and `.next` just return null. This is not reachable today: the only caller, the GTK `SplitTree.goto()`, gets `from` from `getActiveSurfaceHandle()`, which returns null for an empty tree, so it bails out first. So this is not a bug fix, only the contract made explicit, the same way `remove()` asserts `at.idx() < self.nodes.len`: - doc comment: `from` must be a valid handle, so the tree must not be empty - `assert(from.idx() < self.nodes.len)` at the top of `goto()` I first sent a `return null` guard with a test and overstated the impact; this replaces it. Can close it if you'd rather not have the assert. Tested: `zig build test -Dtest-filter=SplitTree`, `zig fmt --check`. AI disclosure: written with LM-based assistants - Antigravity for the first version, Opus for the slightly improved rework. I reviewed the changeset of both.
Write map entries directly to the output writer instead of using a 256-byte buffer. Add a regression test for a 300-byte value.
#14908 Replace both deprecated std.fmt.allocPrint calls with alloc.print. AI assistance: Codex updated both calls and ran the targeted tests.
Write map entries directly to the output writer instead of using a 256-byte buffer. Add a regression test for a 300-byte value. <img width="654" height="77" alt="Screenshot 2026-10-29 at 2 50 41 AM" src="https://github.com/user-attachments/assets/82ba4f78-2137-4bc5-bd6f-2f2afe6cd96c" />
The nixpkgs update for Zig 0.17 removed gnome-photos, so evaluating any GNOME VM check fails with "'gnome-photos' has been removed". Excluding a package that no longer exists is unnecessary.
The pinned GNOME starts org.gnome.Shell@user, so the --unsafe-mode override on org.gnome.Shell@wayland never applies. Without it, org.gnome.Shell.Eval returns nothing and basic-window-check-gnome times out waiting for the focused window.
…for tests (#14911) Test on main takes over an hour and I'm tired of it. Almost all of that is one chain: every expensive job waits on `test` (~13 min), and then the arm64 `build-nix` job runs six `nix build`s serially (~50 min), rebuilding the Zig deps derivation every commit because its name embeds the git revision so that forces a rebuild. This breaks that chain up. By commit: - **nix: drop the revision from the zig deps derivation name.** The deps derivation now matches `.#deps`, so it only rebuilds when `build.zig.zon` changes and Cachix actually hits. This was costing ~8 minutes of arm64 time per run. - **ci: gate expensive jobs on a quick build.** A new `build-gate` job (just `zig build`, ~2 min) replaces `needs: test`. Cheap jobs that don't need a compile gate now only wait on `skip`. `test` runs in parallel with everything else. - **ci: split build-nix into one job per target and architecture.** 12 parallel jobs instead of 2 long serial ones. `required` checks them by result like everything else. - **ci: build the source tarball without waiting on its tests.** `build-dist` now runs `zig build dist`, so the Debian, snap, and flatpak jobs get the tarball in a few minutes instead of ~13. The full `distcheck` (unchanged) runs as `test-dist` on an md runner in parallel. - **ci: run the full test suite once across the GTK and SIMD legs.** The x11/wayland options don't change anything the unit tests cover, and `-Dsimd=true` is the default, so we were running the same full suite four extra times. The GTK legs still all build. This saves about 46 runner-minutes per run. Also pins `nix-installer-action` to v23 instead of `@main`. Some tradeoffs worth knowing: - If `test` fails, the expensive jobs still run, since they're only gated on a compile now. Failing PRs cost more compute; passing PRs get much faster feedback. I think that's fine. - The first run after this merges will be a bit slow for Nix since all 12 jobs build the deps derivation cold. After that it comes from Cachix. I plan to continue looking for improvements after this. **AI disclosure:** I used Fable to measure the existing CI runs and propose plans to break it down. I massaged those plans pretty significantly. I used Opus to write YAML because fuck writing YAML. I read it all.
Triggered by [discussion comment](ghostty-org/ghostty#14914 (comment)) from @jcollie. Vouch: @clinta Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The GNOME VM checks fail on main, unnoticed because CI doesn't build them: `gnome-photos` was removed from nixpkgs in 3110fb3, breaking evaluation, and the `--unsafe-mode` override targets `org.gnome.Shell@wayland` while GNOME now starts `org.gnome.Shell@user`, so `Shell.Eval` returns nothing. Dropping the exclude and retargeting the override makes `basic-window-check-gnome` and `bell-leak-check-gnome` pass again. **AI assistance:** I used Claude Code (Claude Opus 5.5) to find and verify this. I reviewed the change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.