Commit Graph

17555 Commits

Author SHA1 Message Date
Mitchell Hashimoto
fac595c741 macos: normalize action working directory paths (#14051)
Discussion #14048

Directory URLs no longer export a trailing slash through PWD, which
keeps zsh's %1~ prompt expansion from resolving to an empty string.

A shared URL helper removes trailing separators while preserving the
filesystem root and percent-decoding behavior. Tests cover normal,
repeated, encoded, and root paths.
2026-08-27 15:22:38 -07:00
Mitchell Hashimoto
1c3a4a8314 Update macos/Sources/Helpers/Extensions/URL+Extension.swift
Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com>
2026-08-27 14:58:06 -07:00
Mitchell Hashimoto
07abbd1e7e Update macos/Sources/Helpers/Extensions/URL+Extension.swift
Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com>
2026-08-27 14:57:59 -07:00
Mitchell Hashimoto
2de1596115 macos: normalize action working directory paths
Discussion #14048

Directory URLs no longer export a trailing slash through PWD, which
keeps zsh's %1~ prompt expansion from resolving to an empty string.

A shared URL helper removes trailing separators while preserving the
filesystem root and percent-decoding behavior. Tests cover normal,
repeated, encoded, and root paths.
2026-08-27 14:35:01 -07:00
Mitchell Hashimoto
4f4589f31f macOS: use the same default BellFeatures as config (#14049) 2026-08-27 14:27:55 -07:00
Lukas
572fd58377 macOS: use the same default BellFeatures as config 2026-08-27 23:17:17 +02:00
Mitchell Hashimoto
890aa63dbb font: update embedded Noto emoji fonts (#14047)
Fixes #14046

Update Noto Color Emoji from v2.034 to v2.051 and Noto Emoji Regular
from v1.002 to v3.005.

The old assets predate Unicode 15.0 and decompose newer ZWJ sequences
into separate glyphs. This causes sequences such as the Emoji 15.1
head-shaking faces to overlap neighboring terminal cells. The new assets
provide the missing sequence glyphs through Unicode 17.0.

New supported glyphs too:

| Codepoint | Glyph | Name |
|-----------|-------|------|
| U+1F6D8 | 🛘 | LANDSLIDE |
| U+1F6DC | 🛜 | WIRELESS |
| U+1FA75 | 🩵 | LIGHT BLUE HEART |
| U+1FA76 | 🩶 | GREY HEART |
| U+1FA77 | 🩷 | PINK HEART |
| U+1FA87 | 🪇 | MARACAS |
| U+1FA88 | 🪈 | FLUTE |
| U+1FA89 | 🪉 | HARP |
| U+1FA8A | 🪊 | TROMBONE |
| U+1FA8E | 🪎 | TREASURE CHEST |
| U+1FA8F | 🪏 | SHOVEL |
| U+1FAAD | 🪭 | FOLDING HAND FAN |
| U+1FAAE | 🪮 | HAIR PICK |
| U+1FAAF | 🪯 | KHANDA |
| U+1FABB | 🪻 | HYACINTH |
| U+1FABC | 🪼 | JELLYFISH |
| U+1FABD | 🪽 | WING |
| U+1FABE | 🪾 | LEAFLESS TREE |
| U+1FABF | 🪿 | GOOSE |
| U+1FAC6 | 🫆 | FINGERPRINT |
| U+1FAC8 | 🫈 | HAIRY CREATURE |
| U+1FACD | 🫍 | ORCA |
| U+1FACE | 🫎 | MOOSE |
| U+1FACF | 🫏 | DONKEY |
| U+1FADA | 🫚 | GINGER ROOT |
| U+1FADB | 🫛 | PEA POD |
| U+1FADC | 🫜 | ROOT VEGETABLE |
| U+1FADF | 🫟 | SPLATTER |
| U+1FAE8 | 🫨 | SHAKING FACE |
| U+1FAE9 | 🫩 | FACE WITH BAGS UNDER EYES |
| U+1FAEA | 🫪 | DISTORTED FACE |
| U+1FAEF | 🫯 | FIGHT CLOUD |
| U+1FAF7 | 🫷 | LEFTWARDS PUSHING HAND |
| U+1FAF8 | 🫸 | RIGHTWARDS PUSHING HAND |
2026-08-27 12:58:32 -07:00
Mitchell Hashimoto
28b5bf9059 font: update embedded Noto emoji fonts
Fixes #14046

Update Noto Color Emoji from v2.034 to v2.051 and Noto Emoji
Regular from v1.002 to v3.005.

The old assets predate Unicode 15.0 and decompose newer ZWJ sequences
into separate glyphs. This causes sequences such as the Emoji 15.1
head-shaking faces to overlap neighboring terminal cells. The new
assets provide the missing sequence glyphs through Unicode 17.0.

New supported glyphs too:

| Codepoint | Glyph | Name |
|-----------|-------|------|
| U+1F6D8 | 🛘 | LANDSLIDE |
| U+1F6DC | 🛜 | WIRELESS |
| U+1FA75 | 🩵 | LIGHT BLUE HEART |
| U+1FA76 | 🩶 | GREY HEART |
| U+1FA77 | 🩷 | PINK HEART |
| U+1FA87 | 🪇 | MARACAS |
| U+1FA88 | 🪈 | FLUTE |
| U+1FA89 | 🪉 | HARP |
| U+1FA8A | 🪊 | TROMBONE |
| U+1FA8E | 🪎 | TREASURE CHEST |
| U+1FA8F | 🪏 | SHOVEL |
| U+1FAAD | 🪭 | FOLDING HAND FAN |
| U+1FAAE | 🪮 | HAIR PICK |
| U+1FAAF | 🪯 | KHANDA |
| U+1FABB | 🪻 | HYACINTH |
| U+1FABC | 🪼 | JELLYFISH |
| U+1FABD | 🪽 | WING |
| U+1FABE | 🪾 | LEAFLESS TREE |
| U+1FABF | 🪿 | GOOSE |
| U+1FAC6 | 🫆 | FINGERPRINT |
| U+1FAC8 | 🫈 | HAIRY CREATURE |
| U+1FACD | 🫍 | ORCA |
| U+1FACE | 🫎 | MOOSE |
| U+1FACF | 🫏 | DONKEY |
| U+1FADA | 🫚 | GINGER ROOT |
| U+1FADB | 🫛 | PEA POD |
| U+1FADC | 🫜 | ROOT VEGETABLE |
| U+1FADF | 🫟 | SPLATTER |
| U+1FAE8 | 🫨 | SHAKING FACE |
| U+1FAE9 | 🫩 | FACE WITH BAGS UNDER EYES |
| U+1FAEA | 🫪 | DISTORTED FACE |
| U+1FAEF | 🫯 | FIGHT CLOUD |
| U+1FAF7 | 🫷 | LEFTWARDS PUSHING HAND |
| U+1FAF8 | 🫸 | RIGHTWARDS PUSHING HAND |
2026-08-27 12:39:52 -07:00
Mitchell Hashimoto
e9ad4b1d63 macOS: fix non control keys are not working for AppleScript (#13205)
`send key` only works for control keys like `enter` currently; this adds
(fixes) the support for other keys listed as available. Found by
@paaloeye in #13180

The core of this fix is relying on `UCKeyTranslate` to get the
corresponding character and code point from a key code using
`KeyboardLayout.character(for:modifiers:)`.

ScriptKeyEventCommand now respects `macos-option-as-alt`, and attach
`text`, `unshifted_codepoint` and `consumed_mods` under the same
condition as a manual input events like in `performKeyEquivalent` and
`localEventKeyDown`.

## AI Disclosure

Claude did the heavy lifting, I reviewed and rephrased some of the
comments it generated. And ofc reviewed and tested myself.
2026-08-27 09:33:24 -07:00
Mitchell Hashimoto
f2d5758f63 terminal/snapshot: use stack fallback for record scratch (#14018)
Use a bounded 512-byte stack fallback for complete-snapshot record
scratch. Small records avoid heap growth while larger records continue
through the heap allocator.

This usually means 2 fewer allocations per encode, resulting in a small
performance improvement in a local benchmark:

| Workload | `main` median | Branch median | Change |
|---|---:|---:|---:|
| Empty, 50k encodes | 135.06 ms | 130.76 ms | **3.2% faster** |
| 1 MiB ASCII, 500 encodes | 280.75 ms | 281.25 ms | **0.2% slower**,
within noise |
| 1 MiB styled, 200 encodes | 1,023.02 ms | 996.32 ms | **2.6% faster**
|
2026-08-26 19:52:24 -07:00
Jeffrey C. Ollie
f349d10843 build(deps): bump hustcer/milestone-action from 3.1 to 3.2 (#14040)
Bumps
[hustcer/milestone-action](https://github.com/hustcer/milestone-action)
from 3.1 to 3.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/hustcer/milestone-action/releases">hustcer/milestone-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.2</h2>
<h2>[3.2] - 2026-08-25</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Harden action inputs and make GraphQL file lookup path-independent
(<a
href="https://redirect.github.com/hustcer/milestone-action/issues/168">#168</a>)</li>
<li>Look up milestones by title across all states with pagination (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/170">#170</a>)</li>
<li>Guard GITHUB_OUTPUT, surface GraphQL errors and tighten is-int (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/172">#172</a>)</li>
<li>Require title for create action and sync stale docs (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/174">#174</a>)</li>
<li>Send milestone fields as raw strings and harden action inputs (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/176">#176</a>)</li>
</ul>
<h3>Deps</h3>
<ul>
<li>Upgrade hustcer/setup-nu to v3.25 &amp; Nu to 0.113.1</li>
<li>Upgrade hustcer/setup-nu to v3.27 and Nu to 0.115</li>
<li>Upgrade Nu to 0.115.1</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/hustcer/milestone-action/blob/main/CHANGELOG.md">hustcer/milestone-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<h2>[3.2] - 2026-08-25</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Harden action inputs and make GraphQL file lookup path-independent
(<a
href="https://redirect.github.com/hustcer/milestone-action/issues/168">#168</a>)</li>
<li>Look up milestones by title across all states with pagination (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/170">#170</a>)</li>
<li>Guard GITHUB_OUTPUT, surface GraphQL errors and tighten is-int (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/172">#172</a>)</li>
<li>Require title for create action and sync stale docs (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/174">#174</a>)</li>
<li>Send milestone fields as raw strings and harden action inputs (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/176">#176</a>)</li>
</ul>
<h3>Deps</h3>
<ul>
<li>Upgrade hustcer/setup-nu to v3.25 &amp; Nu to 0.113.1</li>
<li>Upgrade hustcer/setup-nu to v3.27 and Nu to 0.115</li>
<li>Upgrade Nu to 0.115.1</li>
</ul>
<h2>[3.1] - 2026-01-23</h2>
<h3>Documentation</h3>
<ul>
<li>Update milestone-action version in README (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/162">#162</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>Break before sleep when milestone found</li>
</ul>
<h3>Miscellaneous Tasks</h3>
<ul>
<li>Update README.md (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/166">#166</a>)</li>
</ul>
<h3>Deps</h3>
<ul>
<li>Update Nu to 0.109.1</li>
<li>Update Nushell to 0.110.0 (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/167">#167</a>)</li>
<li>Upgrade hustcer/setup-nu to v3.22</li>
</ul>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<h2>[3.0] - 2025-10-26</h2>
<p>This release introduces changes that may impact some users. If the
action fails due to insufficient permissions, please add the
<code>issues: write</code> and <code>pull-requests: write</code>
permissions to your workflow. Additionally, the API for binding
milestones has been modified. Due to these changes, the major version
has been incremented to 3.</p>
<h3>Bug Fixes</h3>
<ul>
<li>Try to fix GitHub Projects (classic) deprecation warning by using
REST API instead of GraphQL (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/157">#157</a>)</li>
<li>Fix &quot;Resource not accessible by integration&quot; error for
issue milestone binding by adding <code>issues: write</code>
permission</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2f38355153"><code>2f38355</code></a>
Bump to v3.2</li>
<li><a
href="90d6122217"><code>90d6122</code></a>
deps: Upgrade Nu to 0.115.1</li>
<li><a
href="e587063f37"><code>e587063</code></a>
fix: Send milestone fields as raw strings and harden action inputs (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/176">#176</a>)</li>
<li><a
href="cc2b756fd4"><code>cc2b756</code></a>
fix: Require title for create action and sync stale docs (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/174">#174</a>)</li>
<li><a
href="f8cedae0c1"><code>f8cedae</code></a>
fix: Guard GITHUB_OUTPUT, surface GraphQL errors and tighten is-int (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/172">#172</a>)</li>
<li><a
href="b57a2e26d7"><code>b57a2e2</code></a>
fix: Look up milestones by title across all states with pagination (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/170">#170</a>)</li>
<li><a
href="3ba8f40c95"><code>3ba8f40</code></a>
fix: Harden action inputs and make GraphQL file lookup path-independent
(<a
href="https://redirect.github.com/hustcer/milestone-action/issues/168">#168</a>)</li>
<li><a
href="1e6a3fcc55"><code>1e6a3fc</code></a>
deps: Upgrade hustcer/setup-nu to v3.27 and Nu to 0.115</li>
<li><a
href="9131595492"><code>9131595</code></a>
deps: Upgrade hustcer/setup-nu to v3.25 &amp; Nu to 0.113.1</li>
<li>See full diff in <a
href="ebed8d5daa...2f38355153">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hustcer/milestone-action&package-manager=github_actions&previous-version=3.1&new-version=3.2)](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-26 21:05:27 -05:00
dependabot[bot]
522ebdd0a3 build(deps): bump hustcer/milestone-action from 3.1 to 3.2
Bumps [hustcer/milestone-action](https://github.com/hustcer/milestone-action) from 3.1 to 3.2.
- [Release notes](https://github.com/hustcer/milestone-action/releases)
- [Changelog](https://github.com/hustcer/milestone-action/blob/main/CHANGELOG.md)
- [Commits](ebed8d5daa...2f38355153)

---
updated-dependencies:
- dependency-name: hustcer/milestone-action
  dependency-version: '3.2'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-27 00:13:14 +00:00
Mitchell Hashimoto
b69f612672 macOS: update note about tab accessory view (#14038)
Reverts: #14028
2026-08-26 13:57:52 -07:00
Lukas
0a9f47cae0 macOS: update note about tab accessory view 2026-08-26 22:45:56 +02:00
Lukas
b6ac6e1d47 Revert "macOS: use same ResetZoomAccessoryView (#14028)"
This reverts commit 15ff186f65, reversing
changes made to 1abd53ee53.
2026-08-26 22:44:12 +02:00
Mitchell Hashimoto
d9840f3c8f renderer: park DisplayLink while idle (#14035)
#14033

Pause the CVDisplayLink when there isn't any real work to do.

Start the link after updateFrame rebuilds cells, keep it running while
cell changes or animations remain pending, and resync it from the
no-redraw path to sleep it again.

I also did some benchmark to measure the cost of starting/stopping the
display link since this includes a lot more of that and I found that a
continuously running link used 29 to 35 us of CPU per callback, while
starting and stopping it for every frame used 103 to 121 us. So, in some
pathological case this can be worse, but its still microseconds, and in
the normal case this helps Ghostty sleep a lot more.
2026-08-26 11:35:35 -07:00
Mitchell Hashimoto
6688aa072f renderer: park DisplayLink while idle
#14033

Pause the CVDisplayLink when there isn't any real work to do.

Start the link after updateFrame rebuilds cells, keep it running while
cell changes or animations remain pending, and resync it from the
no-redraw path to sleep it again. 

I also did some benchmark to measure the cost of starting/stopping the
display link since this includes a lot more of that and I found that
a continuously running link used 29 to 35 us of CPU per callback, while
starting and stopping it for every frame used 103 to 121 us. So, in some
pathological case this can be worse, but its still microseconds, and in
the normal case this helps Ghostty sleep a lot more.

Co-authored-by: Jesse Miller <jmiller@jmiller.com>
2026-08-26 11:11:42 -07:00
Mitchell Hashimoto
15ff186f65 macOS: use same ResetZoomAccessoryView (#14028) 2026-08-26 06:52:39 -07:00
Mitchell Hashimoto
1abd53ee53 macOS: clean up deprecated toolbar button (#14027)
This button is a leftover from cf6017e777,
we're now using tab's and titlebar's accessory view to display unzoom
buttons, no need to keep them.
2026-08-26 06:52:27 -07:00
Lukas
7a15898bc8 macOS: use same ResetZoomAccessoryView 2026-08-26 13:28:11 +02:00
trag1c
5f5b988c52 i18n: update fr_FR translations (#13971)
Update missing french translations for Ghostty 1.4
(https://github.com/ghostty-org/ghostty/issues/13766)
2026-08-26 10:58:30 +02:00
Lukas
851751a116 macOS: clean up deprecated toolbar button 2026-08-26 10:21:40 +02:00
Mitchell Hashimoto
88f57ee66e terminal: ignore UTF-8-decoded C1 controls in the ground state (#14023)
Drop UTF-8 decoded C1 controls entirely. This matches xterm's default
behavior which is our standard policy (but note it diverges from libvte
which executes them). There isn't really any standard I could find
around this.

The ground state UTF-8 fast paths (both the scalar decoder and the
batched SIMD path) previously treated decoded codepoints C1 control
codepoints as normal UTF-8 text and routed them to print.
2026-08-25 21:27:42 -07:00
Mitchell Hashimoto
40a40f848d terminal: ignore UTF-8-decoded C1 controls in the ground state
Drop UTF-8 decoded C1 controls entirely. This matches xterm's default
behavior which is our standard policy (but note it diverges from libvte
which executes them). There isn't really any standard I could find
around this.

The ground state UTF-8 fast paths (both the scalar decoder and the
batched SIMD path) previously treated decoded codepoints C1 control
codepoints as normal UTF-8 text and routed them to print.
2026-08-25 21:08:55 -07:00
Mitchell Hashimoto
6dcf68fc0b terminal: execute C0 controls 0x10-0x1F in the ground state (#14022)
Fixes #14021

The ground state UTF-8 fast paths only classified 0x00-0x0F plus 0x1B
(escape) as C0 controls. The remaining C0 bytes (0x10-0x1A, 0x1C-0x1F)
were decoded as ordinary codepoints and routed to print as if they were
text.

This resulted in incorrect grids but also very weird font fallback, e.g.
U+0014 would find CJK fonts.

This commit fixes this by routing every ground state C0 byte except ESC
to execute as it should be.
2026-08-25 20:37:37 -07:00
Mitchell Hashimoto
0f35043c9a terminal: execute C0 controls 0x10-0x1F in the ground state
Fixes #14021

The ground state UTF-8 fast paths only classified 0x00-0x0F plus 0x1B (escape)
as C0 controls. The remaining C0 bytes (0x10-0x1A, 0x1C-0x1F) were decoded 
as ordinary codepoints and routed to print as if they were text.

This resulted in incorrect grids but also very weird font fallback, e.g.
U+0014 would find CJK fonts.

This commit fixes this by routing every ground state C0 byte except ESC to 
execute as it should be.
2026-08-25 20:22:21 -07:00
Lou Ferrand
73e53ceeac i18n: update fr_FR translations 2026-08-26 00:41:51 +02:00
Jon Parise
ee8095d37d terminal/snapshot: use stack fallback for record scratch
Use a bounded 512-byte stack fallback for complete-snapshot record
scratch. Small records avoid heap growth while larger records continue
through the heap allocator.
2026-08-25 14:20:58 -04:00
Mitchell Hashimoto
683d8db643 renderer: release GPU resources for hidden surfaces (macOS) (#14017)
Ref #12034

This commit releases many GPU resources when a surface becomes invisible
and rebuilds it on the next draw. I don't say "all" because there are
still some things we can improve on (Kitty images).

We previously held onto all GPU resources for the lifetime of the
surface regardless of its visibility state. This is 3x (for
triple-buffering): screen render targets, uniform/cell/custom shader
buffers, font textures, and more.

Measured on macOS (Metal):

| Measurement (1 visible + 20 hidden tabs)    | Before    | After   |
|---------------------------------------------|-----------|---------|
| Tracked GPU allocations (steady state)      | 384.6 MiB | 18.3 MiB |
| `MTLDevice.currentAllocatedSize`            | 393.3 MiB | 19.7 MiB |
| `footprint` IOSurface (dirty)               | 309 MB    | 15 MB   |
| Swap chain rebuild on unhide (42 tab switches) | n/a | avg 0.43 ms,
max 0.55 ms |

As you can see, importantly, swap chain rebuild is fast: 0.43ms average.
That means that the rebuild is imperceptible and happens well within a
frame draw time.

This is macOS only, but most of the work was in the generic renderer.
GTK only needs to call `releaseGpuResources` when it becomes invisible
to get the same benefits. I didn't have my VM handy to test this yet so
I didn't include it.
2026-08-25 11:08:01 -07:00
Mitchell Hashimoto
c4e16970a8 renderer: release GPU resources for hidden surfaces (macOS)
Ref #12034

This commit releases many GPU resources when a surface becomes invisible and
rebuilds it on the next draw. I don't say "all" because there are still
some things we can improve on (Kitty images).

We previously held onto all GPU resources for the lifetime of the surface
regardless of its visibility state. This is 3x (for triple-buffering): 
screen render targets, uniform/cell/custom shader buffers, font textures,
and more.

Measured on macOS (Metal):

| Measurement (1 visible + 20 hidden tabs)    | Before    | After   |
|---------------------------------------------|-----------|---------|
| Tracked GPU allocations (steady state)      | 384.6 MiB | 18.3 MiB |
| `MTLDevice.currentAllocatedSize`            | 393.3 MiB | 19.7 MiB |
| `footprint` IOSurface (dirty)               | 309 MB    | 15 MB   |
| Swap chain rebuild on unhide (42 switches)  | n/a       | avg 0.43 ms, max 0.55 ms |

As you can see, importantly, swap chain rebuild is fast: 0.43ms average.
That means that the rebuild is imperceptible and happens well within
a frame draw time.

This is macOS only, but most of the work was in the generic renderer.
GTK only needs to call `releaseGpuResources` when it becomes invisible
to get the same benefits. I didn't have my VM handy to test this yet so
I didn't include it.
2026-08-25 10:46:11 -07:00
Lukas
6229d4eb62 macOS: fix AppleScript send key for non-control keys
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 17:49:02 +02:00
Mitchell Hashimoto
9c3ec931d6 terminal: treat high bytes in DCS strings as payload data (#14016)
Refs #11216

The dcs_passthrough state only forwarded bytes 0x00-0x7E to the DCS
handler. Bytes 0x80-0x9F hit the "anywhere" C1 transitions and exited
the string, while 0xA0-0xFF fell through to the default transition and
were silently dropped. **This breaks any DCS payload carrying UTF-8. **

A continuation byte in the C1 range terminates or corrupts the string:
"Ü" is 0xC3 0x9C, so the 0xC3 is dropped and the 0x9C acts as 8-bit ST,
ending the DCS mid-character.

Also, a payload byte such as 0x9B (second byte of "Û") transitions to
csi_entry, so the remainder of the payload executes as a live control
sequence. This is a prerequisite for tmux control mode (#1935), whose
%output notifications carry raw UTF-8 pane content.

Fix this in the parse table only: override 0x80-0xFF in dcs_passthrough
to put and in dcs_ignore to ignore, exactly how osc_string already
claims 0x20-0xFF (including 0x9C) as data. This deviates from the
vt100.net state machine
(https://vt100.net/emu/dec_ansi_parser) deliberately and includes 0x9C:
a raw 0x9C is indistinguishable from a UTF-8 continuation byte, and we
don't honor 8-bit C1 controls in the ground state either.
2026-08-25 08:42:26 -07:00
Jeffrey C. Ollie
b260da24f8 cli: update list-themes preview sample to valid Zig 0.16 syntax (#14012)
The demo code shown in the `+list-themes` theme preview was stale from
before the Zig 0.16 migration (context: #12228). It referenced
`std.Io.getStdOut().writer()`, which never existed in any Zig release,
and `pub fn main() !void`. This rewrites the rendered sample to valid
Zig 0.16 idioms:

```zig
const std = @import("std");

pub fn main(init: std.process.Init) !void {
    var buf: [1024]u8 = undefined;
    var stdout = std.Io.File.stdout().writer(init.io, &buf);
    const w = &stdout.interface;

    var i: usize = 1;
    while (i <= 16) : (i += 1) {
        if (i % 15 == 0) {
            try w.writeAll("ZiggZagg\n");
        } else if (i % 3 == 0) {
            try w.writeAll("Zigg\n");
        } else if (i % 5 == 0) {
            try w.writeAll("Zagg\n");
        } else {
            try w.print("{d}\n", .{i});
        }
    }
    try w.flush();
}
```

The gutter line numbers, row offsets, and child window height were
renumbered to match, and the zig version shown in the demo prompt line
was updated from v0.13.0 to v0.16.0.
2026-08-25 10:35:12 -05:00
Mitchell Hashimoto
4e817e79a1 terminal: treat high bytes in DCS strings as payload data
Refs #11216

The dcs_passthrough state only forwarded bytes 0x00-0x7E to the DCS
handler. Bytes 0x80-0x9F hit the "anywhere" C1 transitions and exited
the string, while 0xA0-0xFF fell through to the default transition and
were silently dropped. **This breaks any DCS payload carrying UTF-8. **

A continuation byte in the C1 range terminates or corrupts the string: 
"Ü" is 0xC3 0x9C, so the 0xC3 is dropped and the 0x9C acts as 8-bit ST, 
ending the DCS mid-character. 

Also, a payload byte such as 0x9B (second byte of "Û") transitions to 
csi_entry, so the remainder of the payload executes as a live control sequence. 
This is a prerequisite for tmux control mode (#1935), whose %output 
notifications carry raw UTF-8 pane content.

Fix this in the parse table only: override 0x80-0xFF in
dcs_passthrough to put and in dcs_ignore to ignore, exactly how
osc_string already claims 0x20-0xFF (including 0x9C) as data. This
deviates from the vt100.net state machine
(https://vt100.net/emu/dec_ansi_parser) deliberately and includes
0x9C: a raw 0x9C is indistinguishable from a UTF-8 continuation byte,
and we don't honor 8-bit C1 controls in the ground state either.
2026-08-25 08:32:54 -07:00
Mitchell Hashimoto
557253d8f6 terminal: update Kitty clipboard base64 handling to spec (#14015)
The Kitty clipboard protocol now specifies base64 handling: All OSC 5522
payloads and the base64 metadata values (mime, name, pw) use strict RFC
4648 with the standard alphabet. Characters outside the alphabet
(including whitespace) and incorrect padding must be rejected, never
silently skipped.

For wdata payloads for one MIME type, the base64 stream can be split at
arbitrary packet boundaries and only the concatenation must be correctly
padded.

Simdutf has a strict mode for base64 so we got this for free. Benchmarks
to be safe:

| Decoder                       | Time  | Throughput |
|-------------------------------|-------|------------|
| permissive (previous)         | 99ms  | 10.8 GB/s  |
| strict                        | 97ms  | 11.1 GB/s  |
| strict, streaming 4KiB chunks | 102ms | 10.5 GB/s  |
| strict w/ separate scan pass  | 143ms | 7.5 GB/s   |
| std.base64 scalar             | 234ms | 4.6 GB/s   |

Spec changes upstream:

479872838f
https://sw.kovidgoyal.net/kitty/clipboard/#encoding-of-payloads
2026-08-25 08:17:14 -07:00
Mitchell Hashimoto
82ccf12ca2 nix: update nixpkgs-unstable (#13678)
Update nixpkgs-unstable to pick up fontconfig 2.18. Currently we are
linking against 2.17 and you get errors like this on standard error when
using config files meant for fontconfig 2.18:

Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 20:
invalid constant used :
Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 23:
invalid constant used : monospace
Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 42:
invalid attribute 'xsi:nil'
Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 43:
invalid constant used :
Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 46:
invalid constant used : sans-serif
Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 68:
invalid attribute 'xsi:nil'
Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 69:
invalid constant used :
2026-08-25 08:15:15 -07:00
Mitchell Hashimoto
bc2f7d7d2f terminal: update Kitty clipboard base64 handling to spec
The Kitty clipboard protocol now specifies base64 handling:
All OSC 5522 payloads and the base64 metadata values (mime, name, pw)
use strict RFC 4648 with the standard alphabet. Characters outside
the alphabet (including whitespace) and incorrect padding must be
rejected, never silently skipped. 

For wdata payloads for one MIME type, the base64 stream can be split
at arbitrary packet boundaries and only the concatenation must be
correctly padded.

Simdutf has a strict mode for base64 so we got this for free.
Benchmarks to be safe:

| Decoder                       | Time  | Throughput |
|-------------------------------|-------|------------|
| permissive (previous)         | 99ms  | 10.8 GB/s  |
| strict                        | 97ms  | 11.1 GB/s  |
| strict, streaming 4KiB chunks | 102ms | 10.5 GB/s  |
| strict w/ separate scan pass  | 143ms | 7.5 GB/s   |
| std.base64 scalar             | 234ms | 4.6 GB/s   |

Spec changes upstream:
479872838f
https://sw.kovidgoyal.net/kitty/clipboard/#encoding-of-payloads
2026-08-25 08:08:16 -07:00
ghostty-vouch[bot]
bb00a5c988 Update VOUCHED list (#14013)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/14012#issuecomment-5412366760)
from @jcollie.

Vouch: @tacheraSasi

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-25 14:59:54 +00:00
tacheraSasi
d9857eabae cli: update list-themes preview sample to valid Zig 0.16 syntax 2026-08-25 17:47:01 +03:00
Jeffrey C. Ollie
48a9e29f79 nix: update nixpkgs-unstable
Update nixpkgs-unstable to pick up fontconfig 2.18. Currently we are linking against 2.17 and you get errors
like this on standard error when using config files meant for fontconfig 2.18:

  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 20: invalid constant used :
  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 23: invalid constant used : monospace
  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 42: invalid attribute 'xsi:nil'
  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 43: invalid constant used :
  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 46: invalid constant used : sans-serif
  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 68: invalid attribute 'xsi:nil'
  Fontconfig warning: "/etc/fonts/conf.d/48-guessfamily.conf", line 69: invalid constant used :

This also removes an override for libfyaml on Darwin that was merged upstream into nixpkgs.
2026-08-25 09:17:52 -05:00
Mitchell Hashimoto
8144ef4e73 terminal: optimize OSC string reading with SIMD (#14011)
We now have large OSCs (e.g. Kitty clipboard protocol) on the order of
megabytes. OSC was still byte-at-a-time. This adds a vector-optimized
plus bulk storing path to OSC, similar to APC.

Throughput measured with the terminal-stream benchmark:

| Corpus                   | Before | After | Speedup |
|--------------------------|--------|-------|---------|
| OSC 52, 1MiB payloads    | 446ms  | 14ms  | 32x     |
| OSC 5522, 1MiB payloads  | 446ms  | 15ms  | 30x     |
| OSC 5522, 64KiB payloads | 448ms  | 14ms  | 32x     |
| OSC 5522, 4KiB payloads  | 448ms  | 16ms  | 29x     |
| Tiny titles (~24B each)  | 450ms  | 73ms  | 6.2x    |
| Mixed OSCs (16MiB)       | 595ms  | 531ms | 1.13x   |

Used Fable to help validate this with a barrage of differential tests.
The actual implementation was AI-written but was guided to basically
mimic the APC path and then I hand verified everything too.
2026-08-25 07:11:47 -07:00
Mitchell Hashimoto
8c5bc3d29f terminal: optimize OSC string reading with SIMD
We now have large OSCs (e.g. Kitty clipboard protocol) on the order
of megabytes. OSC was still byte-at-a-time. This adds a vector-optimized
plus bulk storing path to OSC, similar to APC.

Throughput measured with the terminal-stream benchmark:

| Corpus                   | Before | After | Speedup |
|--------------------------|--------|-------|---------|
| OSC 52, 1MiB payloads    | 446ms  | 14ms  | 32x     |
| OSC 5522, 1MiB payloads  | 446ms  | 15ms  | 30x     |
| OSC 5522, 64KiB payloads | 448ms  | 14ms  | 32x     |
| OSC 5522, 4KiB payloads  | 448ms  | 16ms  | 29x     |
| Tiny titles (~24B each)  | 450ms  | 73ms  | 6.2x    |
| Mixed OSCs (16MiB)       | 595ms  | 531ms | 1.13x   |

Used Fable to help validate this with a barrage of differential tests.
The actual implementation was AI-written but was guided to basically
mimic the APC path and then I hand verified everything too.
2026-08-25 06:52:37 -07:00
Mitchell Hashimoto
046a45a5fc terminal: fully reset row metadata when recycling row storage (#14010)
Fixes #13940

Various operations like scroll, line insert, erase, etc. operations
would clear cells but remain row metadata such as wrap flags and
semantic prompt state.

When we had fast paths in `grow` and other places like resize we would
adopt that without knowing it because we didn't properly clear.

Fix this by properly clearing row metadata too at the points where we
erase a row that might be reused.

Benchmarked with terminal-stream workloads for each affected path. The
added cost is 2-4 instructions per recycled row next to the existing
full-row cell clear. There was no measurable wall-clock change on any
workload.

AI helped run the benchmarks for me and analyze for missing places (it
found some!) but otherwise this was hand-designed.
2026-08-25 05:59:16 -07:00
Mitchell Hashimoto
b31fbc8464 terminal: fully reset row metadata when recycling row storage
Fixes #13940

Various operations like scroll, line insert, erase, etc. operations
would clear cells but remain row metadata such as wrap flags and
semantic prompt state.

When we had fast paths in `grow` and other places like resize 
we would adopt that without knowing it because we didn't properly clear.

Fix this by properly clearing row metadata too at the points where we
erase a row that might be reused.

Benchmarked with terminal-stream workloads for each affected path.
The added cost is 2-4 instructions per recycled row next to the existing 
full-row cell clear. There was no measurable wall-clock change on any 
workload.

AI helped run the benchmarks for me and analyze for missing places (it found
some!) but otherwise this was hand-designed.
2026-08-25 05:44:31 -07:00
Mitchell Hashimoto
6d2b436529 macos: replace legacy aspectRatio with scaledToFit in clipboard preview (#14006)
Fixes the swiftlint legacy_swiftui_aspect_ratio violation.

### AI Disclosure

By Claude, but it's really simple.
2026-08-25 05:41:28 -07:00
Mitchell Hashimoto
1c739350c3 macOS: add test cases for ScriptKeyEventCommand (#14008)
Partial changes for #13205, known issues are marked as warnings.

### AI Disclosure

Claude generated these tests from linked pr, I cherrypicked and reviewed
myself.
2026-08-25 05:41:14 -07:00
Mitchell Hashimoto
719def70f3 macOS: update default behaviour of KeyboardLayout.character(for:modifiers:) (#14009)
Follow up for #13888, and prepare for #13205.

The comments are copied from the history commit.

## AI Disclosure

The tests are updated by Claude, I cherrypicked them.
2026-08-25 05:41:01 -07:00
Lukas
f1b9efed80 macOS: update default behaviour of KeyboardLayout.character(for:modifiers:) 2026-08-25 13:56:21 +02:00
Lukas
d7f5ba3b4f macOS: add test cases for ScriptKeyEventCommand
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 13:37:58 +02:00
Lukas
a2212a5b12 macos: replace legacy aspectRatio with scaledToFit in clipboard preview
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 10:22:27 +02:00