Commit Graph

17293 Commits

Author SHA1 Message Date
Mitchell Hashimoto
e5747cf0b6 terminal/kitty: abort incomplete graphics loads
Previously, delete left partial bytes alive for the next upload, while
failed or incomplete retransmissions kept stale placements visible.

Abort incomplete chunked image uploads on delete commands and remove an
existing image and its placements when retransmission of an explicit ID
begins.
2026-08-18 10:56:13 -07:00
Mitchell Hashimoto
7e5dfa09eb terminal/kitty: constrain placement offsets to cell bounds (#13891)
Clamp X and Y offsets when a placement is created and normalize them
again against current cell geometry when sizing and rendering. The
protocol requires offsets to remain within the first cell and not
enlarge explicit c/r rectangles:

https://sw.kovidgoyal.net/kitty/graphics-protocol/#controlling-displayed-image-layout

Previously, explicit placements were sized to the full c/r rectangle
before the offset was applied. This extended their far edge into
neighboring cells and let unbounded offsets reach renderer geometry.
2026-08-18 10:31:53 -07:00
Mitchell Hashimoto
c5a3c7e2e5 terminal/kitty: constrain placement offsets to cell bounds
Clamp X and Y offsets when a placement is created and normalize them
again against current cell geometry when sizing and rendering. The
protocol requires offsets to remain within the first cell and not
enlarge explicit c/r rectangles:
https://sw.kovidgoyal.net/kitty/graphics-protocol/#controlling-displayed-image-layout

Previously, explicit placements were sized to the full c/r rectangle
before the offset was applied. This extended their far edge into
neighboring cells and let unbounded offsets reach renderer geometry.
2026-08-18 10:28:03 -07:00
Mitchell Hashimoto
9848cb15fa terminal/kitty: intersect source rectangles before sizing (#13890)
Kitty graphics placements previously calculated pixel and grid geometry
from requested source dimensions before intersecting them with the
image. The renderer clamped explicit dimensions later but treated
omitted source dimensions as the full image.

This stretched clipped crops into incorrectly sized destinations and
exposed inconsistent geometry through storage, rendering, and
libghostty.

Resolve the source rectangle once against the image bounds and reuse it
for placement sizing, renderer preparation, and the C API. Add
regression tests for omitted and explicit dimensions and renderer
geometry.

Spec:
https://sw.kovidgoyal.net/kitty/graphics-protocol/#controlling-displayed-image-layout
Reference:
0ecb10d158/kitty/graphics.c (L1225-L1240)
2026-08-18 10:24:50 -07:00
Mitchell Hashimoto
409e682c83 terminal/kitty: reject conflicting image identifiers (#13889)
Reject Kitty graphics commands that specify both an image ID and an
image number across every protocol action.

These commands previously produced no wire response for transmissions,
while put and delete actions could proceed using one identifier and
mutate terminal state.

Retain the original command identifiers, validate them before action
dispatch, and preserve them in the EINVAL response. Add regression
coverage for every action, response encoding, quiet suppression, and
pre-mutation rejection.


https://sw.kovidgoyal.net/kitty/graphics-protocol/#requesting-image-ids-from-the-terminal
2026-08-18 10:24:42 -07:00
Mitchell Hashimoto
52190a5d8d terminal/kitty: intersect source rectangles before sizing
Kitty graphics placements previously calculated pixel and grid geometry
from requested source dimensions before intersecting them with the image.
The renderer clamped explicit dimensions later but treated omitted
source dimensions as the full image.

This stretched clipped crops into incorrectly sized destinations and
exposed inconsistent geometry through storage, rendering, and
libghostty.

Resolve the source rectangle once against the image bounds and reuse it
for placement sizing, renderer preparation, and the C API. Add
regression tests for omitted and explicit dimensions and renderer
geometry.

Spec: https://sw.kovidgoyal.net/kitty/graphics-protocol/#controlling-displayed-image-layout
Reference: 0ecb10d158/kitty/graphics.c (L1225-L1240)
2026-08-18 10:10:01 -07:00
Mitchell Hashimoto
83145c0a37 terminal/kitty: reject conflicting image identifiers
Reject Kitty graphics commands that specify both an image ID and an
image number across every protocol action.

These commands previously produced no wire response for transmissions,
while put and delete actions could proceed using one identifier and
mutate terminal state.

Retain the original command identifiers, validate them before action
dispatch, and preserve them in the EINVAL response. Add regression
coverage for every action, response encoding, quiet suppression, and
pre-mutation rejection.

https://sw.kovidgoyal.net/kitty/graphics-protocol/#requesting-image-ids-from-the-terminal
2026-08-18 10:07:20 -07:00
Mitchell Hashimoto
d4d72f3205 terminal/kitty: place cursor after tall images properly (#13887)
Supersedes #13886

This fixes an incompatibility between Ghostty and Kitty 0.47.1+.

Previously, Ghostty handled `C=0` by moving down at most one terminal
height and then clamping the horizontal destination to the screen. The
limit protected against an image command requesting billions of rows,
but it counted ordinary movement to the bottom as well as scrolling.

Kitty defines `C=0` as leaving the cursor after the image and implements
the movement as rows minus one, plus one row when the image reaches the
right edge:


https://sw.kovidgoyal.net/kitty/graphics-protocol/#controlling-displayed-image-layout
0ecb10d158/kitty/graphics.c (L1256-L1260)
0ecb10d158/kitty/screen.c (L1903-L1915)

(Had to view Kitty source to verify what the spec meant)

For example, an eight-row, full-width image in a five-row terminal needs
four moves to reach the bottom and four more to scroll. The old limit
allowed only five moves in total, so the next image started four rows
inside the first one. Clamping the horizontal destination also left the
cursor at the final column instead of wrapping to column one of the next
row. Consecutive images could therefore overlap in both directions.
2026-08-18 08:58:46 -07:00
Mitchell Hashimoto
afb61e1b62 terminal/kitty: place cursor after tall images properly
Supersedes #13886

This fixes an incompatibility between Ghostty and Kitty 0.47.1+.

Previously, Ghostty handled `C=0` by moving down at most one terminal
height and then clamping the horizontal destination to the screen. The
limit protected against an image command requesting billions of rows,
but it counted ordinary movement to the bottom as well as scrolling.

Kitty defines `C=0` as leaving the cursor after the image and implements
the movement as rows minus one, plus one row when the image reaches the
right edge:

https://sw.kovidgoyal.net/kitty/graphics-protocol/#controlling-displayed-image-layout
0ecb10d158/kitty/graphics.c (L1256-L1260)
0ecb10d158/kitty/screen.c (L1903-L1915)

(Had to view Kitty source to verify what the spec meant)

For example, an eight-row, full-width image in a five-row terminal needs
four moves to reach the bottom and four more to scroll. The old limit
allowed only five moves in total, so the next image started four rows
inside the first one. Clamping the horizontal destination also left the
cursor at the final column instead of wrapping to column one of the next
row. Consecutive images could therefore overlap in both directions.
2026-08-18 08:46:20 -07:00
Mitchell Hashimoto
0a16db3c68 fix(lib-vt): report size when mode 2048 is enabled (#13885)
Mode 2048 requires terminals to report the current rows, columns, and
pixel dimensions [when the mode is
enabled](https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83#:~:text=When%20first%20enabled%2C%20the%20terminal%20MUST%20send%20a%20report%20of%20the%20current%20size.),
then report updated geometry after later resizes. The native termio
stream already queues the initial report, but the terminal stream only
reported from `resize`, so libghostty consumers that enabled the mode
after committing geometry received nothing until another resize.

This makes the generic handler match termio by requesting current
geometry through the existing size callback and writing the encoded
report through `write_pty` on every enable.
2026-08-18 06:21:50 -07:00
Elias Andualem
5b9a77f203 terminal: document mode 2048 size reports 2026-08-18 15:34:07 +03:00
Elias Andualem
07af4612ba terminal: report size when mode 2048 is enabled 2026-08-18 14:26:37 +03:00
Mitchell Hashimoto
12967b68f7 libghostty: option to retain continuations on snapshot decode (#13878)
Add a snapshot decoder option that leaves continuation tracking enabled
on decoded terminals. This lets caller access the continuation bytes (if
any) that were applied to the terminal.

This lets replay callers export an unfinished parser or UTF-8 sequence
from the returned terminal.

This defaults to off.
2026-08-17 13:39:27 -07:00
Mitchell Hashimoto
9be6c2ea28 libghostty: option to retain continuations on snapshot decode
Add a snapshot decoder option that leaves continuation tracking
enabled on decoded terminals. This lets caller access the continuation
bytes (if any) that were applied to the terminal.

This lets replay callers export an unfinished parser or UTF-8 sequence
from the returned terminal.

This defaults to off.
2026-08-17 13:30:41 -07:00
Mitchell Hashimoto
56e1f3a62e libghostty: buffer the writer adapter used by streaming C APIs (#13877)
The GhosttyWriter adapter was unbuffered, so for streaming writers that
make small writes like the formatter, it produces a crazy amount of
callbacks: one styled HTML page invoked the callback ~50,000 times in a
benchmark lol. This has a particularly large impact on callers who are
supplying callbacks through an expensive FFI interface, like Go.

Change WriterAdapter to have an optional buffer (initBuffered) and use a
4 KB buffer for all current callers. Also optimize single byte splats to
use memset.

Results: that same styled HTML example goes from ~50K callbacks to 124.
And throughput through the C API also improved across every workload I
tested (styled and unstyled text in every format).
2026-08-17 12:54:25 -07:00
Mitchell Hashimoto
846d24e12b libghostty: buffer the writer adapter used by streaming C APIs
The GhosttyWriter adapter was unbuffered, so for streaming writers that
make small writes like the formatter, it produces a crazy amount of callbacks:
one styled HTML page invoked the callback ~50,000 times in a benchmark lol.

Change WriterAdapter to have an optional buffer (initBuffered) and use
a 4 KB buffer for all current callers. Also optimize single byte splats
to use memset.

Results: that same styled HTML example goes from ~50K callbacks to 124.
And throughput through the C API also improved across every workload
I tested (styled and unstyled text in every format).
2026-08-17 12:43:56 -07:00
Mitchell Hashimoto
159cf6d7e7 pkg/wuffs: use C-only mirror of wuffs (#13789)
This prevents us from pulling in test images that trigger some
anti-virus scanners. It's also smaller since it only has the necessary
bits that we need.

This also updates to the latest release: 0.4.0-alpha.10.
2026-08-17 11:19:24 -07:00
Mitchell Hashimoto
385a378fe5 termio: preserve UTF-8 in desktop notification truncation (#13811)
## Summary

- Prevent desktop notification title and body truncation from producing
invalid UTF-8.
- Truncate fixed-size buffers to the longest valid UTF-8 prefix.
- Add regression tests for multibyte characters at the buffer boundary.

Fixes #13795

## Testing

- Confirmed the original reproducer produces `[Invalid UTF-8]` with the
installed Ghostty.
- Confirmed the patched Ghostty displays a valid, truncated
notification.
- Added tests covering both notification title and body truncation.

## AI Usage Disclosure

I used OpenAI Codex to investigate the root cause, implement the fix and
regression tests, run validation, and help prepare the issue and PR
descriptions. I reviewed and understand the submitted change.
2026-08-17 11:18:59 -07:00
Mitchell Hashimoto
4816afc742 macos: simplify command palette sort keys (#13872)
Store the Comparable ObjectIdentifier directly instead of wrapping the
only sort key type in AnySortKey.

The expected deterministic ordering of equal terminal command titles is
also now verified by a unit test.
2026-08-17 10:44:57 -07:00
Mitchell Hashimoto
0073976231 terminal: preserve pending wrap in VT formatter (#13876)
Previously, formatting a cursor at the right edge emitted CUP, which
cleared pending wrap. Replayed output then overwrote the edge cell
instead of wrapping before the next printable character.

When pending wrap is set, move to and reformat the final cell to restore
the flag through normal VT behavior. Emit cursor pen state afterward and
cover replay plus pin-map behavior with a regression test.
2026-08-17 10:00:46 -07:00
Mitchell Hashimoto
997a2aff2a terminal: preserve pending wrap in VT formatter
Previously, formatting a cursor at the right edge emitted CUP, which
cleared pending wrap. Replayed output then overwrote the edge cell
instead of wrapping before the next printable character.

When pending wrap is set, move to and reformat the final cell to restore
the flag through normal VT behavior. Emit cursor pen state afterward and
cover replay plus pin-map behavior with a regression test.
2026-08-17 09:52:14 -07:00
Jon Parise
5c952ac977 macos: simplify command palette sort keys
Store the Comparable ObjectIdentifier directly instead of wrapping the
only sort key type in AnySortKey.

The expected deterministic ordering of equal terminal command titles is
also now verified by a unit test.
2026-08-17 12:50:27 -04:00
Mitchell Hashimoto
ee57b94170 libghostty: C api to stream formatter output through a GhosttyWriter (#13875)
Add `ghostty_formatter_format` which uses a streaming GhosttyWriter type
to write. Update the example to show this.
2026-08-17 09:42:04 -07:00
Mitchell Hashimoto
faaf07e7c0 macos: remove unused hosting window helper (#13873)
Remove the unused SwiftUI environment key intended to expose a hosting
window. Nothing sets or reads the value.
2026-08-17 09:36:11 -07:00
Mitchell Hashimoto
0baa0fd545 inspector: remove obsolete detachable header helper (#13874)
Remove the unused, callback-based detachable header implementation. It
supported the previous terminal inspector, which has since been deleted
(fdbe4343c). The current inspector uses DetachableHeader directly.
2026-08-17 09:36:02 -07:00
Mitchell Hashimoto
924c8a90de libghostty: C api to stream formatter output through a GhosttyWriter
Add `ghostty_formatter_format` which uses a streaming GhosttyWriter
type to write. Update the example to show this.
2026-08-17 09:34:52 -07:00
Mitchell Hashimoto
c8980b853b macos: don't put 0x7F as text in key event (#13871)
Fixes #13869

We already checked `< 0x20` but missed `0x7F` which causes similar
problems.
2026-08-17 09:21:39 -07:00
Jon Parise
d19f8f7f9d macos: remove unused hosting window helper
Remove the unused SwiftUI environment key intended to expose a hosting
window. Nothing sets or reads the value.
2026-08-17 10:58:41 -04:00
Jon Parise
2349e974b8 inspector: remove obsolete detachable header helper
Remove the unused, callback-based detachable header implementation. It
supported the previous terminal inspector, which has since been deleted
(fdbe4343c). The current inspector uses DetachableHeader directly.
2026-08-17 10:49:24 -04:00
trag1c
6c30dc1bff i18n: Update ko_KR translations (#13815)
Update all missing Korean translations for 1.4.

Part of #13766
2026-08-17 15:48:41 +02:00
Mitchell Hashimoto
f4309055fb macos: don't put 0x7F as text in key event
Fixes #13869

We already checked `< 0x20` but missed `0x7F` which causes similar
problems.
2026-08-17 06:44:16 -07:00
ghostty-vouch[bot]
3924a32556 Update VOUCHED list (#13870)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/13838#discussioncomment-18052745)
from @mitchellh.

Vouch: @basteez

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-17 13:22:13 +00:00
trag1c
b97b17f06b i18n: translate v1.4 strings (be) (#13771)
Continues the Belarusian (`be`) translation for v1.4 per #13766.
Translates the remaining 181 strings (mostly the newly-localized command
palette), bringing `be` to 253/253.
2026-08-17 09:13:53 +02:00
Mitchell Hashimoto
e9db8d2b0b libghostty: use custom memory pool for Wasm, reduce terminal memory by ~75% (#13865)
A custom memory pool for Wasm that grows by exactly one item size per
growth and shares the pool across the entire Wasm-module instead of
per-terminal.

Some background on why `std.heap.MemoryPool` is considered harmful for
WebAssembly:

First, the std.heap.MemoryPool grows 1.5x at each growth point. The
backing allocator for that is usually a GPA which is the BrkAllocator
for wasm. This grows by power-of-two big-allocation slots. If you pair
these together you get a massive permanent linear memory growth.

On non-wasm targets, the memory growth doesn't matter because these are
virtual memory mappings that don't cost physical memory, but wasm
doesn't work that way. Also on native targets, the syscalls to allocate
memory are very expensive (relatively), so it makes sense to allocate
large virtual memory chunks and avoid them. Again, wasm doesn't work
this way.

Second, we were using one pool per terminal. On wasm, this meant that we
paid for the free list N times. On non-wasm, this makes sense because
the synchronization overhead has so far been measurable enough under
load to be prohibitive (although, I'm still skeptical about this and
want to look into it). On wasm, we build single-threaded modules, so we
can use a global free list without any extra overhead.

## Benchmarks

80x24 terminal with 1000-line scrollack processing 16MB of plain ASCII.

| Scenario                        |    Before |     After |
| ------------------------------- | --------: | --------: |
| Fresh instance                  |  0.56 MiB |  0.56 MiB |
| First `terminal_new` (delta)    | +3.44 MiB | +0.88 MiB |
| One filled terminal (total)     |  4.00 MiB |  1.88 MiB |
| Each additional filled terminal | +3.00 MiB | +0.44 MiB |
| 5 filled terminals (total)      | 16.00 MiB |  4.06 MiB |

Throughput numbers are unchanged on wasm and native (to be expected in
the latter because this is all gated on
wasm).

Note I'm still very much optimizing the above numbers! This is just my
first big win.

**AI usage:** None used except to validate and judge.
2026-08-16 21:12:59 -07:00
Mitchell Hashimoto
492c26067c libghostty: use custom memory pool for Wasm
A custom memory pool for Wasm that grows by exactly one item size per
growth and shares the pool across the entire Wasm-module instead of 
per-terminal.

Some background on why `std.heap.MemoryPool` is considered harmful for 
WebAssembly:

First, the std.heap.MemoryPool grows 1.5x at each growth point. The backing 
allocator for that is usually a GPA which is the BrkAllocator for wasm. 
This grows by power-of-two big-allocation slots. If you pair these together 
you get a massive permanent linear memory growth. On non-wasm targets,
this doesn't matter because these are virtual memory mappings that don't
cost physical memory, but wasm doesn't work that way.

Second, we were using one pool per terminal. On wasm, this meant that 
we paid for the free list N times. On non-wasm, this makes sense because
the synchronization overhead has so far been measurable enough under
load to be prohibitive (although, I'm still skeptical about this and want
to look into it). On wasm, we build single-threaded modules, so we can use
a global free list without any extra overhead.

## Benchmarks

80x24 terminal with 1000-line scrollack processing 16MB of plain ASCII.

| Scenario                        |    Before |     After |
| ------------------------------- | --------: | --------: |
| Fresh instance                  |  0.56 MiB |  0.56 MiB |
| First `terminal_new` (delta)    | +3.44 MiB | +0.88 MiB |
| One filled terminal (total)     |  4.00 MiB |  1.88 MiB |
| Each additional filled terminal | +3.00 MiB | +0.44 MiB |
| 5 filled terminals (total)      | 16.00 MiB |  4.06 MiB |

Throughput numbers are unchanged on wasm and native (to be expected in
the latter because this is all gated on wasm).
2026-08-16 20:55:09 -07:00
Mitchell Hashimoto
8d70c5dca0 libghostty: reduce Wasm stack reservation (#13864)
Zig default's Wasm stacks to 1MB. Change it to 128 KB instead.

This removes 896 KiB from every Wasm instance's initial linear memory
reservation. That means that simply _loading_ `ghostty-vt.wasm` is down
this much.

Through various workload benchmarks of real terminal snapshots,
artificial worst case full ascii, full styled, full emoji, full mixed,
etc. workloads, I wasn't able to get a stack to go above 17 KB, so 128
KB is VERY generous. Lets start here.
2026-08-16 20:24:36 -07:00
Mitchell Hashimoto
5364e5158f libghostty: reduce Wasm stack reservation
Zig default's Wasm stacks to 1MB. Change it to 128 KB instead.

This removes 896 KiB from every Wasm instance's initial linear memory
reservation. That means that simply _loading_ `ghostty-vt.wasm` is down
this much.

Through various workload benchmarks of real terminal snapshots,
artificial worst case full ascii, full styled, full emoji, full mixed,
etc. workloads, I wasn't able to get a stack to go above 17 KB, so 128 KB
is VERY generous. Lets start here.
2026-08-16 19:42:24 -07:00
Jeffrey C. Ollie
9a770be61c build(deps): bump cachix/install-nix-action from 31.11.0 to 31.11.1 (#13863)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.11.0 to 31.11.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cachix/install-nix-action/releases">cachix/install-nix-action's
releases</a>.</em></p>
<blockquote>
<h2>v31.11.1</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.35.1 -&gt; 2.35.2 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/281">cachix/install-nix-action#281</a>
Fixes a crash (<a
href="https://redirect.github.com/NixOS/nix/issues/16005"><code>Assertion
'!awake.empty()' failed</code></a>) that could abort builds.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31.11.0...v31.11.1">https://github.com/cachix/install-nix-action/compare/v31.11.0...v31.11.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="13d8dd58da"><code>13d8dd5</code></a>
fix(ci): skip latest installer on x86_64-darwin</li>
<li><a
href="875018fe55"><code>875018f</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/281">#281</a>
from cachix/create-pull-request/patch</li>
<li><a
href="6624a11f6c"><code>6624a11</code></a>
nix: 2.35.1 -&gt; 2.35.2</li>
<li>See full diff in <a
href="630ae543ea...13d8dd58da">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cachix/install-nix-action&package-manager=github_actions&previous-version=31.11.0&new-version=31.11.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2026-08-16 19:49:04 -05:00
dependabot[bot]
7a966438fc build(deps): bump cachix/install-nix-action from 31.11.0 to 31.11.1
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.11.0 to 31.11.1.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](630ae543ea...13d8dd58da)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-version: 31.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-17 00:16:28 +00:00
Ilia Kravchenko
820ed688ef i18n(be): fix translation issues per review
- Drop redundant 'было' copula with short-form participles (lines 1767, 1769)
- Use short predicative form 'недаступна' (line 1780)
- 'у двух фарматах:' instead of dash-construction (line 156)
- 'Аднавіць' instead of 'Паўтарыць' for Redo (semantic pair with Undo)
- Fix 'у' → 'ў' after 'ANSI' (7 places)
- Align label/description wording for Split Zoom, Read-Only, Float on Top, Secure Input
- 'усе акны' instead of 'усе вокны' (consistent with 'акно')
- 'калі яна ёсць' instead of 'даступная' (if present ≠ available)
- Infinitive 'Дадаць' instead of imperative 'Дадайце'
2026-08-16 20:33:57 -03:00
Jeffrey C. Ollie
602497e9b9 input: skip text fallback for kitty key releases (#13861)
Key events without a kitty entry fall back to writing their UTF-8 text
directly. On GTK, keys whose unshifted keysym is a dead key or level 5
latch have no unshifted codepoint and take this path. With event type
reporting enabled, releases therefore emitted the same text as presses
and duplicated characters in applications such as Neovim.

Skip the raw text fallback for release events while retaining it for
presses and repeats. Keep the guard in the shared encoder so release
events for identified keys still retain the UTF-8 data used to derive
alternate keys.

Cover releases with and without report-all mode, and verify that repeat
events continue to emit fallback text.

  - https://github.com/ghostty-org/ghostty/discussions/12192
  - https://github.com/ghostty-org/ghostty/discussions/12084
  - https://github.com/ghostty-org/ghostty/discussions/12433
  - https://github.com/ghostty-org/ghostty/discussions/13816

## Testing

  - `zig build test-lib-vt -Dtarget=x86_64-linux-gnu`
  - `zig build -Demit-lib-vt -Dtarget=x86_64-linux-gnu`
  - `zig build`
  - Verified the regression test fails without the release guard
- Manually tested the GTK backend under Wayland/Sway and X11/XWayland,
with the GTK simple input context and ibus 1.5.34:
    - Ergo-L `!` and `'`
    - Spanish `[`, `{`, `]`, and `}`
- Presses, repeats, and both modifier-release orders in `nvim --clean`
    - Dead-key composition and cancellation
    - Unicode hexadecimal input
- Full kitty keyboard mode with `kitty +kitten show_key -m kitty`,
including composed text

## AI disclosure

OpenAI Codex assisted with investigating the reports, reviewing the GTK
and kitty input paths, extending the regression tests, running
validation, and drafting this description. I reviewed the final code,
edited this description, manually performed the tests listed above, and
understand how the change interacts with the input encoder.
2026-08-16 16:32:35 -05:00
Mitchell Hashimoto
f8856a78a2 config: preserve bytes in hex escapes (#13862)
Fixes #13855

Make the config string parser preserve hexadecimal escapes as bytes.
Previously all escaped values were encoded as Unicode codepoints.
2026-08-16 14:23:09 -07:00
Mitchell Hashimoto
29b82dd80c config: preserve bytes in hex escapes
Fixes #13855

Make the config string parser preserve hexadecimal escapes as bytes.
Previously all escaped values were encoded as Unicode codepoints.
2026-08-16 14:14:26 -07:00
Jeffrey C. Ollie
7557944b4f feat: expand tildes in config theme path to HOME (#13840)
When loading a theme from a path that includes a tilde:
```
theme="~/.cache/wal/colors-ghostty"
```
ghostty currently fails with the following error:
```
cannot include path separators unless it is an absolute path
```

This PR tries to expand the ~ of the path. If there is no ~ or expansion
fails, it falls back to the unexpanded value.
2026-08-16 15:19:16 -05:00
Mitchell Hashimoto
3790fb78fe libghostty: simplify Wasm allocation API (#13860)
Replace a bunch of type-specific Wasm allocation functions with a
generic byte allocator and reusable opaque out-parameters for pointers.
This makes it a lot more ergonomic (relatively) to use the Wasm
interface and removes a dozen or so exports.

This also updates the `ghostty_type_json` `abi` field with a maximum
alignment value that host sides can use to keep every allocation aligned
properly, easily, without hardcoding numbers.

This adds a test to verify this all works as intended and runs in CI.
2026-08-16 12:44:01 -07:00
Mitchell Hashimoto
a8e9b413f1 libghostty: simplify Wasm allocation API
Replace a bunch of type-specific Wasm allocation functions with a generic
byte allocator and reusable opaque out-parameters for pointers. This
makes it a lot more ergonomic (relatively) to use the Wasm interface
and removes a dozen or so exports.

This also updates the `ghostty_type_json` `abi` field with a maximum
alignment value that host sides can use to keep every allocation aligned
properly, easily, without hardcoding numbers.

This adds a test to verify this all works as intended and runs in CI.
2026-08-16 12:39:51 -07:00
ghostty-vouch[bot]
7b57c0a029 Update VOUCHED list (#13859)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/13858#discussioncomment-18043290)
from @jcollie.

Vouch: @tsacha

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-16 19:25:55 +00:00
Sacha Trémoureux
bd647035e9 input: don't emit fallback text on key release
Key events without a kitty entry fall back to writing their UTF-8 text
directly. On GTK, keys whose unshifted keysym is a dead key or level 5
latch have no unshifted codepoint and take this path. With event type
reporting enabled, releases therefore emitted the same text as presses
and duplicated characters in applications such as Neovim.

Skip the raw text fallback for release events while retaining it for
presses and repeats. Keep the guard in the shared encoder so release
events for identified keys still retain the UTF-8 data used to derive
alternate keys.

Cover releases with and without report-all mode, and verify that repeat
events continue to emit fallback text.
2026-08-16 20:42:19 +02:00
phl
68a2008b34 fix: format 2026-08-16 20:16:31 +02:00
Mitchell Hashimoto
0ba6250388 libghostty: ghostty_type_json expanded with more metadata, every enum member, packed layouts, etc. (#13856)
This PR makes `ghostty_type_json` contain more metadata necessary for
FFI without access to the C header to produce safe, ABI compliant field
access.

The existing `ghostty_type_json` didn't expose enough information:
embedders still had to hardcode enum values, tagged union values, and
packed bit layouts. For wasm this meant copying offsets and masks from
Zig internals and hoping they didn't drift. This isn't an ABI I want to
promise.

This also includes a formal JSON schema included in Doxygen docs and
used in CI to continuously validate our output structure. I'd like to
expand in the future comparing to actual C headers too.

## Examples

### Named References, Arrays

```json
"GhosttyRenderStateColors": {
  "kind": "struct",
  "size": 792,
  "align": 8,
  "fields": {
    "background": {
      "offset": 8,
      "size": 3,
      "type": "GhosttyColorRgb"
    },
    "palette": {
      "offset": 18,
      "size": 768,
      "type": "array",
      "elem": "GhosttyColorRgb",
      "count": 256
    }
  }
}
```

### Pointers

```json
"GhosttyCellsView": {
  "kind": "struct",
  "size": 16,
  "align": 8,
  "fields": {
    "ptr": {
      "offset": 0,
      "size": 8,
      "type": "pointer",
      "elem": "GhosttyCell",
      "const": true,
      "nullable": true
    },
    "len": {
      "offset": 8,
      "size": 8,
      "type": "u64"
    }
  }
}
```

### Enums

```json
"GhosttyStyleColorTag": {
  "kind": "enum",
  "size": 4,
  "align": 4,
  "underlying": "i32",
  "prefix": "GHOSTTY_STYLE_COLOR_",
  "values": {
    "NONE": 0,
    "PALETTE": 1,
    "RGB": 2,
    "TAG_MAX_VALUE": 2147483647
  }
}
```

### Packed Struct

```json
"GhosttyCell": {
  "kind": "packed",
  "size": 8,
  "align": 8,
  "underlying": "u64",
  "bits": {
    "content_tag": {
      "lsb": 0,
      "width": 2,
      "type": "GhosttyCellContentTag"
    },
    "content": {
      "lsb": 2,
      "width": 24,
      "kind": "union",
      "tag": "content_tag",
      "arms": {
        "BG_COLOR_RGB": {
          "kind": "packed",
          "width": 24,
          "bits": {
            "r": {"lsb": 0, "width": 8, "type": "u8"},
            "g": {"lsb": 8, "width": 8, "type": "u8"},
            "b": {"lsb": 16, "width": 8, "type": "u8"}
          }
        }
      }
    }
  }
}
```
2026-08-16 06:43:14 -07:00