Compare commits

...

1191 Commits
v1.3.0 ... main

Author SHA1 Message Date
Jeffrey C. Ollie bfe633a948
build(deps): bump actions/checkout from 6.0.2 to 6.0.3 (#12911)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2
to 6.0.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v6.0.3</h2>
<ul>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<h2>v6.0.2</h2>
<ul>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<h2>v6.0.1</h2>
<ul>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
</ul>
<h2>v6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>v5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>v5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>v4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>v4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="df4cb1c069"><code>df4cb1c</code></a>
Update changelog for v6.0.3 (<a
href="https://redirect.github.com/actions/checkout/issues/2446">#2446</a>)</li>
<li><a
href="1cce3390c2"><code>1cce339</code></a>
Fix checkout init for SHA-256 repositories (<a
href="https://redirect.github.com/actions/checkout/issues/2439">#2439</a>)</li>
<li><a
href="900f2210b1"><code>900f221</code></a>
fix: expand merge commit SHA regex and add SHA-256 test cases (<a
href="https://redirect.github.com/actions/checkout/issues/2414">#2414</a>)</li>
<li><a
href="0c366fd6a8"><code>0c366fd</code></a>
Update changelog (<a
href="https://redirect.github.com/actions/checkout/issues/2357">#2357</a>)</li>
<li>See full diff in <a
href="de0fac2e45...df4cb1c069">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=6.0.2&new-version=6.0.3)](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-06-03 14:26:43 -05:00
dependabot[bot] 5f7738a0e9
build(deps): bump actions/checkout from 6.0.2 to 6.0.3
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](de0fac2e45...df4cb1c069)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 18:35:02 +00:00
Lukas 4df593bd24
macos: fix GHOSTTY_QUICK_TERMINAL not set for quick terminal splits (#12896) 2026-06-03 08:49:00 +02:00
ghostty-vouch[bot] 629838b9bd
Update VOUCHED list (#12906)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12905#discussioncomment-17160340)
from @jcollie.

Vouch: @c0x0o

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-03 04:48:36 +00:00
Mitchell Hashimoto 6246c288ae
core: fix use-after-free in Surface.setSelection (#12894)
`setSelection` captured the previous selection, then called
`Screen.select` (which deinits the previous selection's tracked pins),
then compared the new selection against the now-freed previous pin via
`sel.eql(prev)`. That read freed pin memory (use-after-free).

The comparison was a copy-on-select optimization ("only re-copy if the
selection changed"). Remove it rather than repair it because:

- It never fired correctly. It compared against freed memory, so the
shipped behavior was already "always copy".

- It can't be repaired by copying `prev`'s pin before `Screen.select`.
That fixes the use-after-free but not the logic: the call sites (e.g.
mouse drag release) pass a selection equal to the one already set, so a
working `eql` skip would suppress the very copy those sites exist to
perform. A correct optimization would have to compare against the
last-copied selection (before the mouse event mutated the live one),
which would require extra state.

- It isn't worth tracking that additional state. The copy runs once per
selection gesture (mouse up, double-click), which isn't in a hot path,
so skipping a redundant re-copy only saves a single clipboard write.

Removing the skip eliminates the use-after-free and keeps the behavior
consistent with what we've already been doing.

---

_AI Disclosure_: Claude Opus 4.8 found this in a review while I was
working on adjacent code.
2026-06-02 06:07:31 -07:00
YuWiz ef68e96400 macos: fix GHOSTTY_QUICK_TERMINAL not set for quick terminal splits 2026-06-02 16:48:36 +08:00
Jon Parise 76b9bdb199 terminal: test Screen.select frees existing pins 2026-06-01 20:09:25 -04:00
Jon Parise ab82b8ab72 core: fix use-after-free in Surface.setSelection
setSelection captured the previous selection, then called Screen.select
(which deinits the previous selection's tracked pins), then compared the
new selection against the now-freed previous pin via `sel.eql(prev)`.
That read freed pin memory (use-after-free).

The comparison was a copy-on-select optimization ("only re-copy if the
selection changed"). Remove it rather than repair it because:

- It never fired correctly. It compared against freed memory, so the
  shipped behavior was already "always copy".

- It can't be repaired by copying `prev`'s pin before Screen.select.
  That fixes the use-after-free but not the logic: the call sites (e.g.
  mouse drag release) pass a selection equal to the one already set, so
  a working `eql` skip would suppress the very copy those sites exist to
  perform. A correct optimization would have to compare against the
  last-copied selection (before the mouse event mutated the live one),
  which would require extra state.

- It isn't worth tracking that additional state. The copy runs once per
  selection gesture (mouse up, double-click), which isn't in a hot path,
  so skipping a redundant re-copy only saves a single clipboard write.

Removing the skip eliminates the use-after-free and keeps the behavior
consistent with what we've already been doing.
2026-06-01 20:09:14 -04:00
Mitchell Hashimoto 5758e14931
terminal: glyph protocol parser and response encoder (#12352)
**Important: this DOES NOT hook up the glyph protocol to Ghostty or
libghostty. Its just the parser.**

This adds the core parse/encode for the still in-development and
experimental terminal glyph protocol:
https://github.com/raphamorim/rio/pull/1542

The only cross-cutting change necessary was changing the APC
identification logic which previously only looked at a single byte to
support multi-byte identifiers since the glyph protocol uses `25a1`.

For DoS protection, the default limits any glyph-related APC command
size to 1 megabyte.

> [!WARNING]
> 
> Since this protocol is still in development and discussion, there is
no promise the implementation will stay within Ghostty or that any of
the APIs exposed by this will remain stable. We're just getting ahead of
it.
2026-06-01 10:57:52 -07:00
Mitchell Hashimoto d3775d1ed0
terminal: glyph protocol parser and response encoder
This adds the core parse/encode for the still in-development and experimental
terminal glyph protocol: https://github.com/raphamorim/rio/pull/1542
Up to version 1.9.

The only cross-cutting change necessary was changing the APC
identification logic which previously only looked at a single byte to
support multi-byte identifiers since the glyph protocol uses `25a1`.
2026-06-01 10:50:05 -07:00
Mitchell Hashimoto 43e0340175
Update iTerm2 colorschemes (#12867)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20260525-155808-7335c0a
2026-06-01 10:03:09 -07:00
Mitchell Hashimoto b81670f3f4
macOS: mark Swift os.Logger interpolations as public (#12877)
### AI Disclosure

Claude implemented it. I'm fully aware of and confident about the
change; it's just chore work actually.
2026-06-01 10:02:53 -07:00
ghostty-vouch[bot] 0f7cd84b88
Update VOUCHED list (#12889)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12840#discussioncomment-17132417)
from @bo2themax.

Vouch: @52dyd

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-01 08:07:04 +00:00
Jeffrey C. Ollie 16f2fdc90c
config: fix missing space in docs (#12879)
fixes #12873

comment/docs only change:
switched space and tab in default value of `selection-word-chars` so
there is no space at the value boundary
needed because markdown trims spaces at the beginning & end of a code
snippet
2026-05-31 12:00:12 -05:00
ghostty-vouch[bot] c4c9e945ae
Update VOUCHED list (#12880)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12879#issuecomment-4587359428)
from @00-kat.

Vouch: @masterflitzer

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-31 16:39:28 +00:00
masterflitzer a181c386ca
config: fix missing space in docs
fixes #12873

comment/docs only change:
switched space and tab in default value of `selection-word-chars`
so there is no space at the value boundary
needed because markdown trims spaces at the beginning & end
of a code snippet
2026-05-31 18:23:29 +02:00
Claude Opus 4.7 eb5c1c7220
fix(macos): mark Swift os.Logger interpolations as public 2026-05-31 16:35:11 +02:00
Lukas 3e83a54d08
macos: remove unneeded initializers (#12875)
These will be automatically synthesized (they only do memberwise
initialization) and do not need to be manually defined.
2026-05-31 16:33:54 +02:00
Jon Parise e32d7abe6e macos: fix swiftlint opening_brace issue 2026-05-31 10:00:24 -04:00
Jon Parise 33adb58bee macos: remove unneeded initializers
These will be automatically synthesized (they only do memberwise
initialization) and do not need to be manually defined.
2026-05-31 09:54:41 -04:00
mitchellh 024880b9ca deps: Update iTerm2 color schemes 2026-05-31 00:38:07 +00:00
Jeffrey C. Ollie 2c62d182ce
gtk: fix context menu hiding quick-terminal (#12843)
Fixes #12783 where opening the context menu (with right click) inside
the quick-terminal will hide the quick-terminal if autohide is enabled.

The cause of this issue is the quick-terminal window becoming inactive
and immediately active again when you open the context-menu. When the
window becomes inactive, the autohide feature hides the quick-terminal.
The temporary focus loss in GTK is triggered by GDK focus change events,
which probably originate from the windowing backend treating the context
menu as its own window. Whereas in GTK the context menu is not a
separate window but instead part of the widget tree of the window it was
opened from, so even when the context menu has focus that window is
still the active one in GTK.

As a fix `Window.propIsActive`, which implements the autohide logic,
will now do its work from a timeout callback, since there is probably no
reliable way to distinguish a temporary focus loss from a real one from
inside GTK and I'm not sure we can make any assumptions about the timing
of things happening in the windowing backend. A 100ms delay should be
long enough for the focus state to settle while still hiding the
quick-terminal quickly.

I reproduced the bug and verified the fix on Wayland with both Hyprland
and KDE. Temporary focus loss happens on X11+KDE as well, although it
doesn't matter there because there is no quick-terminal.

### AI Disclosure

No AI was used, code and comments were written by myself.
2026-05-29 22:44:30 -05:00
Jeffrey C. Ollie c4eba3da38
agents: symlink CLAUDE.md to AGENTS.md (#12861)
Claude code [doesn't support AGENTS.md
files](https://github.com/anthropics/claude-code/issues/6235) so I've
seen lots of repos symlinking
2026-05-29 14:56:50 -05:00
Uzair Aftab c09ade225a
agents: symlink CLAUDE.md to AGENTS.md 2026-05-29 21:11:09 +02:00
Daniel Kinzler ff963f3119 Renamed timeout source and callback function. Added comment explaining timeout delay. 2026-05-29 17:40:25 +02:00
Mitchell Hashimoto 90175950d5
libghostty-vt: preserve shell prompts on resize by default (#12653)
This PR makes libghostty-vt preserve shell prompts across resize unless
the shell explicitly opts into prompt clearing/redraw with `redraw=1`.
2026-05-29 06:41:23 -07:00
Mitchell Hashimoto cb36966a75
libghostty: add utf-8 grapheme cell getter to C API (#12847)
Add a render-state row-cells getter that encodes the current cell's full
grapheme cluster directly as UTF-8 into a caller-provided GhosttyBuffer.
The getter writes the base codepoint first, followed by any extra
grapheme codepoints, and follows the existing buffer-writer convention
where len is bytes written on success or required capacity on
GHOSTTY_OUT_OF_SPACE.

Previously C consumers could query grapheme codepoints, but bindings
that needed UTF-8 text had to reconstruct and encode the cluster
themselves. That duplicated terminal internals in downstream bindings
and made users pay for awkward cross-language struct handling. By owning
the UTF-8/grapheme behavior in libghostty, bindings can use one stable C
API and optionally wrap it with small binding-local helpers.
2026-05-28 13:02:11 -07:00
Mitchell Hashimoto 519a612beb
libghostty: fix wasm build for selection gesture 2026-05-28 13:00:49 -07:00
Mitchell Hashimoto 3cf01e8445
libghostty: add utf-8 grapheme cell getter to C API
Add a render-state row-cells getter that encodes the current cell's
full grapheme cluster directly as UTF-8 into a caller-provided
GhosttyBuffer. The getter writes the base codepoint first, followed by
any extra grapheme codepoints, and follows the existing buffer-writer
convention where len is bytes written on success or required capacity
on GHOSTTY_OUT_OF_SPACE.

Previously C consumers could query grapheme codepoints, but bindings
that needed UTF-8 text had to reconstruct and encode the cluster
themselves. That duplicated terminal internals in downstream bindings
and made users pay for awkward cross-language struct handling. By
owning the UTF-8/grapheme behavior in libghostty, bindings can use one
stable C API and optionally wrap it with small binding-local helpers.
2026-05-28 12:33:36 -07:00
Daniel Kinzler 1753d57bfd remove timeout source when window is disposed 2026-05-28 15:08:12 +02:00
Mitchell Hashimoto 54ac5fd21e
libghostty: expose row cell styling bit (#12837)
Add a render row-cells data key for querying whether the current cell
has explicit styling. This lets consumers avoid fetching a raw cell or
full style snapshot when all they need is the cell's HasStyling bit.

The new key is appended to the existing enum for ABI safety and is
served by the existing row-cells getter path. Existing data keys and
function exports are unchanged.

This was identified as an allocation hot-spot in Go renderers.
2026-05-27 21:11:56 -07:00
Mitchell Hashimoto 8beea5f92d
libghostty: expose row cell styling bit
Add a render row-cells data key for querying whether the current cell has
explicit styling. This lets consumers avoid fetching a raw cell or full style
snapshot when all they need is the cell's HasStyling bit.

The new key is appended to the existing enum for ABI safety and is served by
the existing row-cells getter path. Existing data keys and function exports are
unchanged.
2026-05-27 21:10:26 -07:00
Mitchell Hashimoto 15264856f6
libghostty: expose viewport active state (#12836)
Expose whether the terminal viewport is currently pinned to the active
area through the libghostty-vt terminal data API. Previously embedders
could only infer this from scrollbar geometry, which was indirect and
could require the more expensive scrollbar calculation.

The new GHOSTTY_TERMINAL_DATA_VIEWPORT_ACTIVE value returns the exact
PageList viewport state as a bool. The scroll viewport test now verifies
the value while moving between the active area and scrollback.
2026-05-27 15:28:49 -07:00
Mitchell Hashimoto f730ee0557
libghostty: expose viewport active state
Expose whether the terminal viewport is currently pinned to the active
area through the libghostty-vt terminal data API. Previously embedders
could only infer this from scrollbar geometry, which was indirect and
could require the more expensive scrollbar calculation.

The new GHOSTTY_TERMINAL_DATA_VIEWPORT_ACTIVE value returns the exact
PageList viewport state as a bool. The scroll viewport test now verifies
the value while moving between the active area and scrollback.
2026-05-27 15:24:49 -07:00
Mitchell Hashimoto 6d089a544d
libghostty: C API for SelectionGesture (#12833)
C API side of https://github.com/ghostty-org/ghostty/pull/12830
2026-05-27 11:11:14 -07:00
Mitchell Hashimoto 4e2d7c314b
libghostty: optimize bits for selection gesture validation fields 2026-05-27 11:05:33 -07:00
Mitchell Hashimoto 3e0477a14a
example/c-vt-selection-gesture 2026-05-27 11:01:25 -07:00
Mitchell Hashimoto f0fcb10406
libghostty: selection gesture deep press 2026-05-27 10:57:50 -07:00
Mitchell Hashimoto 603684ba11
libghostty: selection gesture autotick 2026-05-27 10:55:15 -07:00
Mitchell Hashimoto 90fd1ec2e7
libghostty: selection gesture drag events 2026-05-27 10:53:10 -07:00
Mitchell Hashimoto 3fd2c66a04
libghostty: selection gesture release event 2026-05-27 10:49:18 -07:00
Mitchell Hashimoto 5ac8e6569a
libghostty: add ghostty_selection_gesture_event 2026-05-27 10:47:26 -07:00
Mitchell Hashimoto bbfa984aec
libghostty: GhosttySelectionGestureEvent 2026-05-27 10:42:29 -07:00
Mitchell Hashimoto 2f61ba036e
libghostty: starting the SelectionGesture API, just init/get 2026-05-27 09:02:25 -07:00
Mitchell Hashimoto 3103ae8838
macos: avoid duplicate appearance sync on tab focus (#12828)
Close #12825

Skip the initial emissions from the focused surface appearance
publishers after a tab focus change. The focused surface is already
synced immediately, so the initial Combine values only repeat the same
titlebar and background updates. Subsequent derived config and OSC
background changes still resync the window appearance.



https://github.com/user-attachments/assets/f229fb95-4b4c-4040-85ac-0acfcc54ca82



Assigned to Codex GPT 5.5(medium)
PS: Sry for I don't write zig and let AI write this.
2026-05-27 07:52:42 -07:00
Mitchell Hashimoto 756fda776b
cli: rework +ssh-cache internals and user interface (#12814)
This change primarily focused on a revised +ssh-cache user interface,
but it also reworks a bunch of the internals.

The primary CLI improvement is support for positional arguments and a
consistent list output format that includes both the ISO-formatted
timestamp and relative age.

ghostty +ssh-cache # List all cached destinations
    ghostty +ssh-cache user@example.com          # Show that destination
ghostty +ssh-cache example.com # Show all users on that host
ghostty +ssh-cache --add=user@example.com # Manually add a destination
    ghostty +ssh-cache --remove=user@example.com # Remove a destination
ghostty +ssh-cache --prune=30d # Remove entries older than 30 days
    ghostty +ssh-cache --clear                   # Clear entire cache

Notable, we now support a --prune operation that replaces the previous
--expire-days flag that was never actually hooked up to anything (!!).
--prune also supports a wider range of Duration-based values.

We're also much more consistent with error codes: 0=success, 1=failure,
2=usage.

While working on those changes, I also reworked the cache internals,
particularly the code around timestamp handling and errors. For example,
I dropped the explicit error sets because they were growing unwieldy,
and in practice we only matched on a subset of those errors.

Lastly, overall test coverage should be much improved, especially around
the time- and allocation-related operations.

---

*AI Disclosure:* I made a lot of iterative, AI-assisted (Claude Opus
4.7) correctness passes over this work. It was particularly helpful in
tracing through the various failure modes, and it wrote those unit tests
in the process.
2026-05-27 07:52:00 -07:00
Mitchell Hashimoto 8518986b1e
macOS: clear stale OSC 11 background cache on config change (#12822)
## Summary

`SurfaceView` caches the background color set by OSC 11 in
`backgroundColor`. `TerminalWindow.preferredBackgroundColor` consults
that cache before falling back to `derivedConfig.backgroundColor`, so
once OSC 11 has fired the cached value masks any later config change.

After a light/dark theme auto-switch (e.g. `theme =
light:my-light,dark:my-dark`) this leaves the window chrome on the
previous theme's color until the application next emits OSC 11.

In `ghosttyConfigDidChange`, after updating `derivedConfig`, drop the
cache when it no longer matches the new config-derived background. A
subsequent `ghosttyColorDidChange` repopulates it as before, so
within-config OSC 11 behavior is unchanged.

## Reproduction

1. Configure `theme = light:SomeLight,dark:SomeDark` where the two
themes have visibly different background colors.
2. Open a terminal session where any application (e.g. a shell startup
script) has sent OSC 11 to set a custom background color.
3. Switch macOS appearance (System Settings → Appearance).
4. **Before**: window chrome stays the previous theme's color until the
terminal next emits OSC 11.
5. **After**: window chrome immediately updates to the new theme's
background color.

## Changes

- `SurfaceView_AppKit.swift` — one guard: if the cached
`backgroundColor` disagrees with the new
`derivedConfig.backgroundColor`, set it to `nil`.
2026-05-27 07:51:12 -07:00
Mitchell Hashimoto c343c5a67a
Extract click/drag selection handling into SelectionGesture (#12830)
Refactor terminal text selection into a reusable `SelectionGesture`
state machine. Most importantly, this means our click+drag logic around
selection is now fully unit tested! And we found bugs! And fixed them!

The large line increase in this diff is mainly comments + tests.

I've wanted to do this forever so we can unit test this, but I was
kicked in the butt to do it recently because reimplementing selection
logic in libghostty consumers turns out to be complex and error prone
and we have a perfectly battle tested logic machine here so why not
extract it?

Behavioral changes from main surfaced via unit testing:

- Dragging now drags by output across semantic output blocks when the
initial press was an output selection. This matches the behavior of
dragging continuing whatever the initial selection logic was.
- Selection autoscroll now stops when the click anchor is invalidated by
a screen change (e.g. primary to alt)
- Deep press (macOS force touch) now selects the word at the original
press location and consumes the active drag gesture, preventing later
movement from dragging or autoscrolling that selection. This matches
built-in macOS apps.
- Mouse release records whether the gesture moved away from the pressed
cell, so link and prompt clicks are skipped after a drag while normal
clicks still activate them.

Example usage:

```zig
var gesture: terminal.SelectionGesture = .init;
defer gesture.deinit(t);

const press_selection = try gesture.press(t, .{
    .time = try std.time.Instant.now(),
    .pin = press_pin,
    .xpos = mouse_x,
    .ypos = mouse_y,
    .max_distance = cell_width,
    .repeat_interval = mouse_interval,
    .word_boundary_codepoints = selection_word_chars,
    .behaviors = &.{ .cell, .word, .output },
});
try t.screens.active.select(press_selection);

if (gesture.drag(t, drag_event)) |drag_selection| {
    try t.screens.active.select(drag_selection);
}

gesture.release(t, .{ .pin = release_pin });
```
2026-05-27 07:48:23 -07:00
Mitchell Hashimoto 68959c5c63
terminal: fix selection gesture edge cases
Selection gestures now treat releases with invalidated anchors as dragged,
so a press that crosses screen boundaries cannot also activate links or
prompt clicks on release. Cell drags that create a same-cell selection also
mark the gesture as dragged, which keeps click-only actions from firing
after a threshold-crossing drag.

Autoscroll now resolves the drag pin after moving the viewport instead of
reusing the pin from before the scroll. This keeps the selection aligned
with the row currently under the pointer. The inspector also validates the
tracked click pin before displaying it so stale pins from inactive screens
are ignored.
2026-05-27 06:58:44 -07:00
Mitchell Hashimoto 7d4d1e5819
terminal: add configurable behaviors based on click count 2026-05-27 06:32:51 -07:00
Mitchell Hashimoto 82a73f2bf1
terminal: SelectionGesture press returns standard behaviors 2026-05-27 06:26:07 -07:00
Mitchell Hashimoto 9b00bb436a
terminal: better SelectionGesture docs 2026-05-27 06:20:22 -07:00
ghostty-vouch[bot] ce4128afc4
Update VOUCHED list (#12829)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12827#discussioncomment-17075382)
from @trag1c.

Denounce: @Cznorth

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-27 12:33:56 +00:00
Tunglies 5368adcd29
macos: avoid duplicate appearance sync on tab focus
Close #12825

Skip the initial emissions from the focused surface appearance publishers after a tab focus change. The focused surface is already synced immediately, so the initial Combine values only repeat the same titlebar and background updates. Subsequent derived config and OSC background changes still resync the window appearance.
2026-05-27 19:43:41 +08:00
Mitchell Hashimoto f5f9d32d0a
terminal: SelectionGesture deep press 2026-05-26 21:36:22 -07:00
Mitchell Hashimoto df98b6d983
terminal: SelectionGesture autoscrollTick 2026-05-26 21:26:49 -07:00
Mitchell Hashimoto 141c7d44d2
SelectionGesture: release event 2026-05-26 21:17:03 -07:00
Mitchell Hashimoto 229f4c1f4f
terminal: SelectionGesture handles word/line drag 2026-05-26 21:04:22 -07:00
Mitchell Hashimoto c00cdd886b
SelectionGesture: drag events 2026-05-26 20:56:49 -07:00
Mitchell Hashimoto 33f1558801
core: mouse left release renderer lock made more coarse
This will make our selection gesture extraction a bit easier.
2026-05-26 17:02:20 -07:00
Adam Bouker 57d202066d macOS: clear stale OSC 11 background cache on config change
SurfaceView caches the background color set by OSC 11 in
backgroundColor. TerminalWindow.preferredBackgroundColor consults
that cache before falling back to derivedConfig.backgroundColor,
so once OSC 11 has fired the cached value masks any later config
change. After a light/dark theme auto-switch this leaves the
window chrome on the previous theme's color until the application
next emits OSC 11.

In ghosttyConfigDidChange, after updating derivedConfig, drop the
cache when it no longer matches the new config-derived background.
A subsequent ghosttyColorDidChange repopulates it as before, so
within-config OSC 11 behavior is unchanged.
2026-05-26 14:11:45 -05:00
Daniel Kinzler 37997f8dbe Use a timeout callback to wait for changes in window active state to settle. Depending on the backend a window might temporarily become inactive.
Fixes an issue where quick-terminal would disappear when opening the surface context menu.
2026-05-26 18:26:17 +02:00
Jeffrey C. Ollie 2e5ad917eb
apprt/gtk: fix audio-bell GStreamer thread leak (reuse one MediaFile per surface) (#12815)
## Problem

Every audio bell calls `gtk.MediaFile.newForFilename`, which spins up a
full GStreamer pipeline. The GTK4 GStreamer backend's GL sink starts
`gstglcontext`/`gldisplay-event` threads that are **never joined on
teardown**, so allocating a fresh `MediaFile` per ring leaks a pipeline
and ~4 threads on every bell. The old `notify::ended -> unref` handler
discarded the pipeline but did not (and could not) join those threads.

A long-running instance accumulated **705 threads over ~4h** of normal
use.

## Fix

Cache one `MediaFile` per surface (`priv.bell_media`), rebuilt only when
`bell-audio-path` changes and unref'd on `dispose`. Each bell now
replays the same pipeline via `seek(0)` + `play()` instead of creating a
new one. `seek(0)` is required so an ended stream plays again (cf.
#8957).

## Verification

Confirmed on a real running instance with the fix: GStreamer's global
element counter only ever reached `oggdemux4` over an hour of use (one
pipeline per bell-ringing surface, reused for every subsequent bell) and
the process thread count stayed flat — versus the per-bell growth
before.

## Commits

1. **The fix** — reuse one MediaFile per surface.
2. **Unit regression test** — guards the `bellMediaFile` reuse contract
(same path → same object, changed path → rebuild). Runs in the existing
`test-gtk` CI job; needs no display.
3. **End-to-end CI job** *(kept separate so it can be dropped
independently)* — `test/bell-leak.sh` + a `test-gtk-bell-leak` workflow
job that runs ghostty headless (Xvfb + software GL), rings 120 bells,
and fails if the thread count grows per-bell. It's heavier and more
environment-sensitive (needs Xvfb/Mesa/GStreamer on the runner), so it's
isolated for easy review/removal.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-26 11:20:02 -05:00
Mitchell Hashimoto 14df684a70
core: adapt Surface to use SelectionGesture with press only 2026-05-25 15:48:20 -07:00
Mitchell Hashimoto d86ff37a58
terminal: SelectionGesture, but only with mouse press 2026-05-25 15:48:16 -07:00
Nikolay Bryskin 9910a1a475
test: add audio-bell thread-leak NixOS check (GNOME/Wayland)
Adds a bell-leak-check-gnome NixOS test (nix/tests.nix) that launches
Ghostty under GNOME on Wayland, rings 100 bells in the window, and fails
if the GUI process thread count grows per-bell — the end-to-end
signature of the GStreamer pipeline leak fixed in this branch. Verified
locally: growth of ~1 thread over 100 bells, vs ~+400 pre-fix.

Replaces the earlier Xvfb shell script + workflow job: per review, X11
support in GNOME is going away, and this belongs as a Nix check
alongside the other *-gnome tests rather than a standalone script.

The VM has no GPU, so it renders via llvmpipe; the test gives the guest
enough cores/RAM for software GL and tolerates the +new-window D-Bus
activation exceeding its client-side timeout (the window still comes up)
by waiting for the window rather than hard-failing on the call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 01:06:21 +03:00
Nikolay Bryskin 0708f932a5
apprt/gtk: add regression test for audio-bell MediaFile reuse
Guards the contract that prevents the bell thread leak: bellMediaFile
must return the same cached MediaFile for an unchanged path and only
rebuild when the path changes. A revert to per-bell allocation (the
leak) would fail this. Runs in the existing test-gtk CI job; needs no
display or playback since the path bookkeeping is all that's asserted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 23:43:04 +03:00
Nikolay Bryskin 0b6d91e531
apprt/gtk: reuse one audio-bell MediaFile per surface to fix thread leak
Each audio bell called gtk.MediaFile.newForFilename, which spins up a
full GStreamer pipeline. The GTK4 GStreamer backend's GL sink starts
gstglcontext/gldisplay-event threads that are never joined on teardown,
so allocating a MediaFile per ring leaked a pipeline and ~4 threads on
every bell. A long-running instance accumulated 705 threads over ~4h of
normal use.

Cache one MediaFile per surface (priv.bell_media), rebuilt only when
bell-audio-path changes and unref'd on dispose. Each bell now replays
the same pipeline via seek(0)+play() instead of creating a new one. The
notify::ended -> unref handler is removed: it was what discarded (and
leaked) a pipeline per ring. seek(0) is required so an ended stream
plays again (#8957).

Verified on a real instance: GStreamer's global element counter reached
only oggdemux4 over an hour of use (one pipeline per bell-ringing
surface, reused) and thread count stayed flat, versus per-bell growth
before.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 23:43:01 +03:00
ghostty-vouch[bot] a746d0f728
Update VOUCHED list (#12816)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12815#issuecomment-4537093020)
from @jcollie.

Vouch: @nikicat

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-25 20:38:13 +00:00
Jon Parise ac69942cdc cli: rework +ssh-cache internals and user interface
This change primarily focused on a revised +ssh-cache user interface,
but it also reworks a bunch of the internals.

The primary CLI improvement is support for positional arguments and a
consistent list output format that includes both the ISO-formatted
timestamp and relative age.

    ghostty +ssh-cache                           # List all cached destinations
    ghostty +ssh-cache user@example.com          # Show that destination
    ghostty +ssh-cache example.com               # Show all users on that host
    ghostty +ssh-cache --add=user@example.com    # Manually add a destination
    ghostty +ssh-cache --remove=user@example.com # Remove a destination
    ghostty +ssh-cache --prune=30d               # Remove entries older than 30 days
    ghostty +ssh-cache --clear                   # Clear entire cache

Notable, we now support a --prune operation that replaces the previous
--expire-days flag that was never actually hooked up to anything (!!).
--prune also supports a wider range of Duration-based values.

We're also much more consistent with error codes: 0=success, 1=failure,
2=usage.

While working on those changes, I also reworked the cache internals,
particularly the code around timestamp handling and errors. For example,
I dropped the explicit error sets because they were growing unwieldy,
and in practice we only matched on a subset of those errors.

Lastly, overall test coverage should be much improved, especially around
the time- and allocation-related operations.
2026-05-25 16:00:21 -04:00
ghostty-vouch[bot] 2d0fb81751
Update VOUCHED list (#12813)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12793#discussioncomment-17052752)
from @bo2themax.

Vouch: @LePips

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-25 17:54:35 +00:00
Mitchell Hashimoto cb28160b5a
elvish: remove community maintenance note (#12812)
The Elvish integration is currently actively maintained by the Ghostty
maintainers. Contributions are of course still welcome.
2026-05-25 09:07:19 -07:00
Mitchell Hashimoto 53e400ad85
cli: fix readEntries leak and double-free (#12811)
readEntries had two memory bugs on the allocation failure path, both
only reachable under OOM:

- The map itself was never freed if we ran into an allocation failure
- The unconditional `errdefer`s for the dupe'd hostname and terminfo
values could double-free if there was a later allocation failure.

This change restructures this function so that these values are dupe'd
up-front, and then their ownership is tracked using optionals that can
be null'ed out once their ownership is transferred into the map.

Both of these cases are now covered by unit tests.
2026-05-25 09:07:09 -07:00
Jon Parise 16d7c8f2b4 elvish: remove community maintenance note
The Elvish integration is currently actively maintained by the Ghostty
maintainers. Contributions are of course still welcome.
2026-05-25 11:56:37 -04:00
Jon Parise a5550a2dcb cli: fix readEntries leak and double-free
readEntries had two memory bugs on the allocation failure path, both
only reachable under OOM:

- The map itself was never freed if we ran into an allocation failure
- The unconditional `errdefer`s for the dupe'd hostname and terminfo
  values could double-free if there was a later allocation failure.

This change restructures this function so that these values are dupe'd
up-front, and then their ownership is tracked using optionals that can
be null'ed out once their ownership is transferred into the map.

Both of these cases are now covered by unit tests.
2026-05-25 11:49:01 -04:00
ghostty-vouch[bot] ae52f97dca
Update VOUCHED list (#12809)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12807#issuecomment-4534655288)
from @pluiedev.

Denounce: @eric-assetpass

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-25 13:31:49 +00:00
Mitchell Hashimoto b869a6e5ab
libghostty: expose per-cell selection state (#12798)
Render-state rows already expose their selected range, but cell-oriented
C API consumers had to fetch that row range separately and duplicate the
containment check while rendering.

Add a SELECTED row-cells data kind that carries the row selection into
the row-cells wrapper and returns whether the current cell column is in
that inclusive range. The field remains separate from cell colors and
style so selection stays an explicit render overlay policy.

For performance reasons, the span-based row getter is recommended still
but this is a convenient thing to do for cell-oriented folks.
2026-05-24 20:28:58 -07:00
Mitchell Hashimoto edf2da0157
libghostty: expose per-cell selection state
Render-state rows already expose their selected range, but
cell-oriented C API consumers had to fetch that row range separately
and duplicate the containment check while rendering.

Add a SELECTED row-cells data kind that carries the row selection into
the row-cells wrapper and returns whether the current cell column is in
that inclusive range. The field remains separate from cell colors and
style so selection stays an explicit render overlay policy.

For performance reasons, the span-based row getter is recommended still
but this is a convenient thing to do for cell-oriented folks.
2026-05-24 20:24:16 -07:00
Mitchell Hashimoto cf9e85ecd7
deal with large outputs from xdg-open/rundll32/open (#12797)
Depending on your system config, `xdg-open` may stay open for extended
periods, and potentially log more than the 50kb of output that we were
previously able to deal with. This changes `open()` so that output on
`stdout` is just directly ignored. Any output from `stderr` is immedialy
logged rather than collected for later logging.

Note that this will generally occur if your system is not configured
with the DBus portals that `xdg-open` uses to open URLs rather than
launching programs like your web browser directly. This could be seen as
user misconfiguration but we should deal with it robustly anyway.
2026-05-24 19:49:04 -07:00
Jeffrey C. Ollie bb375a2f75
deal with large outputs from xdg-open/rundll32/open
Depending on your system config, `xdg-open` may stay open for extended
periods, and potentially log more than the 50kb of output that we were
previously able to deal with. This changes `open()` so that output on
`stdout` is just directly ignored. Any output from `stderr` is immedialy
logged rather than collected for later logging.

Note that this will generally occur if your system is not configured
with the DBus portals that `xdg-open` uses to open URLs rather than
launching programs like your web browser directly. This could be seen as
user misconfiguration but we should deal with it robustly anyway.
2026-05-24 20:35:39 -05:00
Mitchell Hashimoto c5946f4fef
libghostty: detach tracked grid refs on free (#12795)
Tracked grid references previously held a raw terminal wrapper pointer
and were required to be freed before the terminal. If callers kept one
past terminal destruction, later tracked-ref calls could dereference
freed terminal or page-list memory before detecting that the reference
was no longer meaningful.

Track live C tracked-grid-ref handles from the terminal wrapper and
detach them before tearing down terminal storage. Detached refs now
report no value through the tracked-ref APIs and can still be freed by
the caller. Update the C API docs to describe this lifetime behavior and
add a regression test for using a tracked ref after terminal free.

This introduces some overhead but tracked pins shouldn't be numerous and
this dramatically improves safety.

No API changes due to this (just more safety).
2026-05-24 14:21:58 -07:00
Mitchell Hashimoto 5f08694759
libghostty: selection APIs for C (#12794)
Adds libghostty-vt selection APIs read/write, formatting, inspecting,
and rendering selection state from C.

| Introduced type/function | Purpose |
| --- | --- |
| `GhosttyRenderStateRowSelection` | Row-local inclusive selection range
returned by render row queries. |
| `GhosttyTerminalSelectWordOptions` | Options for deriving a word
selection from a grid ref. |
| `GhosttyTerminalSelectWordBetweenOptions` | Options for finding the
nearest selectable word between two refs. |
| `GhosttyTerminalSelectLineOptions` | Options for deriving line
selections, including semantic prompt boundaries. |
| `GhosttyTerminalSelectionFormatOptions` | Options for formatting the
active or caller-provided selection. |
| `GhosttySelectionOrder` | Describes endpoint ordering, including
rectangular mirrored orders. |
| `GhosttySelectionAdjust` | Operations for moving a selection endpoint.
|
| `ghostty_terminal_select_word` | Derive a word selection snapshot. |
| `ghostty_terminal_select_word_between` | Derive the nearest word
selection between two refs. |
| `ghostty_terminal_select_line` | Derive a line selection snapshot. |
| `ghostty_terminal_select_all` | Derive a selection covering all
selectable content. |
| `ghostty_terminal_select_output` | Derive a semantic command-output
selection. |
| `ghostty_terminal_selection_format_buf` | Format a selection into a
caller-provided buffer. |
| `ghostty_terminal_selection_format_alloc` | Format a selection into an
allocated buffer. |
| `ghostty_terminal_selection_adjust` | Mutate a selection snapshot
endpoint. |
| `ghostty_terminal_selection_order` | Query selection endpoint order. |
| `ghostty_terminal_selection_ordered` | Return a selection with
normalized endpoint order. |
| `ghostty_terminal_selection_contains` | Test whether a point is inside
a selection. |
| `ghostty_terminal_selection_equal` | Compare two selection snapshots
using terminal semantics. |
2026-05-24 14:14:54 -07:00
Mitchell Hashimoto 03df613e39
libghostty: detach tracked grid refs on free
Tracked grid references previously held a raw terminal wrapper pointer and
were required to be freed before the terminal. If callers kept one past
terminal destruction, later tracked-ref calls could dereference freed
terminal or page-list memory before detecting that the reference was no
longer meaningful.

Track live C tracked-grid-ref handles from the terminal wrapper and detach
them before tearing down terminal storage. Detached refs now report no
value through the tracked-ref APIs and can still be freed by the caller.
Update the C API docs to describe this lifetime behavior and add a
regression test for using a tracked ref after terminal free.

This introduces some overhead but tracked pins shouldn't be numerous
and this dramatically improves safety.
2026-05-24 14:13:26 -07:00
Mitchell Hashimoto 2ce5db29ca
libghostty: selection formatting 2026-05-24 14:01:35 -07:00
Mitchell Hashimoto eb777b8036
libghostty: selectWordBetween in C 2026-05-24 13:53:31 -07:00
Mitchell Hashimoto e8f5353912
example/c-vt-selection 2026-05-24 13:48:10 -07:00
Mitchell Hashimoto cc48312c08
libghostty: selection word/line/output/all helpers 2026-05-24 13:42:20 -07:00
Mitchell Hashimoto 847b8afc87
libghostty: remove selection validation, way too expensive 2026-05-23 18:31:20 -07:00
Mitchell Hashimoto 7b49d1f129
terminal: PageList.reset needs to reset page serial mins 2026-05-23 15:32:15 -07:00
Mitchell Hashimoto ae839393d9
libghostty: add Selection equal and validate 2026-05-23 15:23:39 -07:00
Mitchell Hashimoto 2512fad940
libghostty: move selection functions to selection doxygen group 2026-05-23 15:20:45 -07:00
Mitchell Hashimoto 671c12fad9
libghostty: add selection contains API
Expose a C API for checking whether a GhosttyPoint is inside a
GhosttySelection. The new terminal helper validates the selection snapshot
against the active screen, resolves the point to a grid pin, and delegates
to the internal Selection.contains implementation so C consumers get the
same linear and rectangular selection semantics as Ghostty.

Wire the symbol through the C API exports and public headers, and add a
focused test covering linear containment and rectangular selection behavior.
2026-05-23 15:17:59 -07:00
Mitchell Hashimoto 4a77e81967
libghostty: add selection ordering APIs
Expose selection endpoint ordering through the libghostty-vt C API so
embedders can safely normalize selections whose start and end refs may be
reversed. The new APIs report the current order and return a fresh
untracked selection with forward or reverse bounds.

Selection.Order now uses lib.Enum, matching the existing adjustment enum
pattern and keeping the C ABI enum generated from the same Zig source of
truth. The new functions are wired through the C API re-export and lib-vt
export paths, with coverage for mirrored rectangular selection ordering.
2026-05-23 15:16:04 -07:00
Mitchell Hashimoto 15d8963681
libghostty: add selection adjustment api 2026-05-23 15:12:32 -07:00
Mitchell Hashimoto 545a5aef66
libghostty: document selection snapshot lifetime
Clarify that GhosttySelection is a snapshot type whose endpoints are
untracked GhosttyGridRef values. The previous documentation described the
range shape but did not repeat the grid reference lifetime caveat, which
made it easy to keep selections across terminal mutations incorrectly.
2026-05-23 15:05:23 -07:00
Mitchell Hashimoto 24048ffd47
libghostty: expose row-local render selections
Render state already tracks the selected cell range for each viewport row,
but C renderers could only get the full terminal selection. That required
consumers to map global selection pins back into row-local spans themselves.

Add row selection data to the render-state row API. Querying the new row
data returns GHOSTTY_NO_VALUE for unselected rows and writes the inclusive
start and end columns for selected rows. The render example now demonstrates
setting a selection and reading the row-local range while iterating rows.
2026-05-23 15:03:51 -07:00
Mitchell Hashimoto ae03d3cae4
libghostty: expose get/set active selection state
Add terminal set/get support for the active screen selection through the
existing option and data APIs. Setting a selection copies the C snapshot
into terminal-owned tracked state, while passing NULL clears the current
selection.

Getting the selection now returns an untracked GhosttySelection snapshot
or GHOSTTY_NO_VALUE when there is no selection. The C header documents
the different lifetimes for set and get so embedders know when input and
returned grid references remain valid.
2026-05-23 14:56:39 -07:00
Mitchell Hashimoto d5d8cef4d3
macOS: fix search bar Enter key blocking IME composition (#12781)
Closes https://github.com/ghostty-org/ghostty/discussions/12774

`.onKeyPress(.return)` unconditionally returns `.handled`, so when IME
is composing the return key never reaches the IME to confirm the
candidate. The search bar gets stuck.

The fix: use `.onSubmit` for the next-match navigation — it only fires
when there is no composing text. In `.onKeyPress` only intercept
shift+return (previous match), return `.ignored` otherwise.

Tested on macOS 26.5, Ghostty 1.3.1, built from source. Chinese Pinyin
input in the search bar works correctly after the fix.
2026-05-23 14:51:12 -07:00
Mitchell Hashimoto 7c3d9502dc
Update VOUCHED list (#12779)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12775#discussioncomment-17030265)
from @bo2themax.

Vouch: @minorcell
2026-05-23 14:50:45 -07:00
Mitchell Hashimoto af94eac1e1
libghostty: add tracked grid ref API (#12785)
Add a C API for tracked pins, known as a tracked grid ref in C.

The new API can create tracked refs from terminal points, snapshot them
back to regular grid refs for cell access, convert them to coordinates,
move them to a new point, report when their semantic location was lost,
and free the tracked pin bookkeeping. This is backed by PageList tracked
pins and exposed through the libghostty-vt export layer and headers.
2026-05-23 14:50:19 -07:00
Mitchell Hashimoto 60f767dd84
core: guard surface left-click pins with screen generations
Left-click mouse state stored a tracked pin with only the screen key that
owned it. If the alternate screen was removed and later recreated, the key
could match again even though the stored pin belonged to destroyed PageList
storage.

Store the screen generation alongside the left-click pin and resolve the
pin through helpers that require both the key and generation to match. This
keeps selection scrolling, link hover checks, pressure selection, and drag
selection from dereferencing stale tracked pins after screen teardown.
2026-05-23 14:45:13 -07:00
Mitchell Hashimoto 2355550a94
libghostty: add tracked grid ref API
Add a C API for tracked pins, known as a tracked grid ref in C.

The new API can create tracked refs from terminal points, snapshot them
back to regular grid refs for cell access, convert them to coordinates,
move them to a new point, report when their semantic location was lost,
and free the tracked pin bookkeeping. This is backed by PageList tracked
pins and exposed through the libghostty-vt export layer and headers.
2026-05-23 14:37:59 -07:00
minorcell da541bea63 fix stray brace from conflict resolution 2026-05-23 16:33:33 +08:00
minorcell 7a346dd8d4 macOS: fix search bar Enter key blocking IME composition
Use onSubmit for the plain Enter → next-match behavior, which respects
IME composition state. Keep onKeyPress only for Shift+Enter (previous
match), returning .ignored for plain Enter so the IME can process it.
2026-05-23 16:09:48 +08:00
ghostty-vouch[bot] a968e120dd
Update VOUCHED list (#12780)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12775#discussioncomment-17030265)
from @bo2themax.

Vouch: @minorcell

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-23 07:58:07 +00:00
github-actions[bot] 1b3c5b57ff Update VOUCHED list
https://github.com/ghostty-org/ghostty/discussions/12775#discussioncomment-DC_kwDOHFhdAs4BA9x5
2026-05-23 07:25:16 +00:00
Mitchell Hashimoto 3e3705b932
macOS: fix surface focus/render state after dragging in to to another window/tab (#12338)
Fixes 2 bugs

1. After dragging a non-focused surface from window A to window B
**quickly without making B the key window**, the focused surface in
window A is not receiving `keyDown` events.


https://github.com/user-attachments/assets/a8861c0a-9300-470d-bf7e-0f32a9ab2cd1

2. #12343 After dragging a surface from tab A to tab B within the same
window, the dragged surface is not rendering input correctly.
> The reason the thread is stuck is because the surface's occlusion
state is set to invisible after target tab's activate while dragging,
since the dragged surface is still in previous tree before dropping, and
after dropping the occlusion state of this surface is not updated to
visible, which causing the surface is accepting input but not rendering.



https://github.com/user-attachments/assets/d67f5dba-8609-4f67-a956-921982faf796
2026-05-22 09:05:11 -07:00
Mitchell Hashimoto f5aa271d07
cli: add an ssh-wrapping +ssh action (#12582)
Add a drop-in `ssh` wrapper that sets up the remote environment for
Ghostty. Anything not consumed as one of our own flags is forwarded to
the real, wrapped `ssh` binary. It can be used directly (`ghostty +ssh
user@host`), aliased (`alias ssh='ghostty +ssh --'`), or invoked through
Ghostty's shell integration.

Before exec'ing ssh, `+ssh`:

- Forwards Ghostty environment to the remote (`--forward-env`): sets
TERM=xterm-256color and requests SendEnv forwarding of COLORTERM,
TERM_PROGRAM, and TERM_PROGRAM_VERSION.
- Installs Ghostty's terminfo on the remote (`--terminfo`), informed by
our existing `ssh-cache` system and using our internal xterm-ghostty
terminfo representation.

A third flag, `--cache`, controls cache use; `--cache=false` bypasses
both read and write, which is useful for scripting and for debugging
install failures without polluting the cache.

For shell integration, this replaces the per-shell logic (which made up
roughly a third of our shell integration scripts) with a simple wrapper
function that translates GHOSTTY_SHELL_FEATURES into a `ghostty +ssh`
command line.
2026-05-22 09:04:36 -07:00
Mitchell Hashimoto a03b52e18b
fix: preserve active cursor position during reflow (#12598)
This PR fixes an issue where reflowing could leave the active cursor
attached to a clipped trailing blank cell instead of following the
current write position.
2026-05-22 09:03:52 -07:00
Mitchell Hashimoto 24d664f0ba
fix: apply variation selectors to preceding codepoint (#12596)
This fixes a bug where the variation selectors (VS15 & VS16) were
checked against the first codepoint in a cell instead of the previous
codepoint in the cell's grapheme cluster, causing them to be dropped if
that first codepoint was not a valid base.
2026-05-22 09:02:48 -07:00
Mitchell Hashimoto b78174a68f
macOS: update window appearance for About and ConfigurationErrors (#12601)
<img width="1224" height="696" alt="Xnip2026-05-06_19-13-31"
src="https://github.com/user-attachments/assets/ab090dc0-7c06-4a01-8e7c-5d48ca6ccca3"
/>
2026-05-22 08:58:26 -07:00
Mitchell Hashimoto 7e24f0e0bc
macOS: use find pasteboard for search needle (#12712)
Fixes the issue described in #12516.

### What
- Inject an `OSPasteboard` into `SearchState`
- Add `OSPasteboard` extension to normalize working with strings between
UIPasteboard/NSPasteboard
- Add `BackportSelectionTextField` which supports text selection for
MacOS 15/iOS 18 and up.
- Read from the pasteboard when the overlay opens and when the app
becomes active
- Write to the pasteboard when the search needle changes
- Annotate `SearchState` as MainActor. `NSPasteboard` isn't thread safe,
and since `SearchState` is already accessed from the main thread,
MainActor enforces our writes be thread safe
- Add SearchState unit tests

### Why
Consistent with other macOS apps, the Find bar's search needle should
persist when re-opened and should sync to the Find bar in other apps.
For example, see Xcode, Notes, Terminal, and Safari.


https://github.com/user-attachments/assets/b6a55a4a-a52c-45bc-ac38-c9df452c11cb
2026-05-22 08:57:45 -07:00
Mitchell Hashimoto afe4819920
macOS: Re-enable global keybinds after event tap disable events (#12714)
While testing https://github.com/ghostty-org/ghostty/pull/9857, I
encountered the behavior mentioned below. It's pretty frustrating to
encounter, so I've been actually compiling this fix into my test builds
for last month or so, and the issue has not come back. I exclusively use
the QuickTerminal, so my workflow depends on global keybinds working
reliably.

Issue: https://github.com/ghostty-org/ghostty/issues/12294

The solution includes listening to two events that are fired when a tap
is disabled:
- tapDisabledByTimeout
- tapDisabledByUserInput

When these are fired, we re-enable the tap.

Apple's Docs:
https://developer.apple.com/documentation/coregraphics/cgeventtype?language=swift

Related Discussions:
- https://github.com/ghostty-org/ghostty/discussions/11819
- https://github.com/ghostty-org/ghostty/discussions/12091
2026-05-22 08:56:16 -07:00
Mitchell Hashimoto 52f23fb419
macOS: review windows when quitting (#12742)
Inspired by `Terminal.app` which I think is a nice feature.

First two commits contains some changes in `BaseTerminalController` so
that I can use swift concurrency to review those windows in chain more
easily.



https://github.com/user-attachments/assets/41d92432-4ae0-499e-961a-fc247602f3d7


Works with tabs as well, i forgot to record that.
2026-05-22 08:55:14 -07:00
Mitchell Hashimoto ec15d0e7db
gtk: wire up occlusionCallback for non-focused tabs (#12760)
As discussed in #12745, there has been an outstanding plan to make
rendering behavior for non-focused surfaces consistent across platforms.
This PR does that for Linux/GTK using the same patterns as OSX.

The change in `src/apprt/gtk/class/surface.zig` piggybacks on the
existing `glareaMap` / `glareaUnmap` callbacks (added by `e59e27f8b`) by
also calling a new `updateOcclusion(bool)` helper. If you don't like the
helper, or want the helper lifted up further and used on other paths,
let me know and I can revise.

The changes in `src/renderer/Thread.zig` bail on `renderCallback` when
not visible and then block on `drainMailbox` to complete the "catch up"
before trying to draw again.

I want to note that this is more granular than the original #1512, which
was just focused on the top level window state. I can look at that as
well if you want, but given the complexity around how
`XDG_TOPLEVEL_STATE_SUSPENDED` event is fired, I would want to make sure
we discussed things like transparency and single-instance properly first
(e.g., do we render when behind another transparent window).

## Testing

Here's a summary of what I tested:

Tested on Linux/GTK (Ubuntu 26.04, GTK 4.22.2, libadwaita 1.9.0,
Wayland), built `ReleaseFast`. The patched binary has been daily-driven
for ~24 hours as my primary terminal.

| Test | Workload | Result |
|---|---|---|
| Daily drive | byobu × multiple SSH sessions, Claude Code and Codex
producing sustained streaming output, `top` / `btop` redrawing on 1 s
intervals, frequent tab switching | No observed issues over ~24 hours of
mixed use |
| Bell on hidden tab | `sleep 5 && printf '\a'` in background tab | Bell
+ needs-attention indicator both fire; confirms IO-thread → GTK-signal
path is untouched |
| Search highlight survives hide/show | Open search w/ matches
highlighted in tab B → switch to tab A for ~10 s → switch back |
Highlights restored instantly with no stale state; confirms
deferred-replay path (`updateFrame` on `.visible → true`) works
correctly |
| Selection persistence | Select text in tab B → switch tabs → switch
back | Selection preserved exactly |
| Lifecycle (close-all) | Opened 8 surfaces, closed them one at a time,
then process exit + systemd restart | Zero `glib-CRITICAL`, zero `error
in occlusion callback ...` warnings, clean teardown per `journalctl
--user -u app-com.mitchellh.ghostty` |
| Per-thread CPU during workload | `pidstat -t -p <pid>` 30 s with 1
byobu surface focused, 1 background | Hidden surface's renderer thread
sits at 0.00 % every sample; focused surface's renderer shows ~1 % blips
on byobu status ticks |



## AI usage 

Claude Code (Opus 4.7) helped review my patch and monitor / summarize
the jorunald log and pidstat entries.
2026-05-22 08:54:02 -07:00
Jeffrey C. Ollie 10c6121458
build(deps): bump docker/build-push-action from 7.1.0 to 7.2.0 (#12765)
Bumps
[docker/build-push-action](https://github.com/docker/build-push-action)
from 7.1.0 to 7.2.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.2.0</h2>
<ul>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1525">docker/build-push-action#1525</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.87.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1517">docker/build-push-action#1517</a></li>
<li>Bump brace-expansion from 2.0.2 to 5.0.6 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1534">docker/build-push-action#1534</a></li>
<li>Bump fast-xml-builder from 1.1.4 to 1.2.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1529">docker/build-push-action#1529</a></li>
<li>Bump fast-xml-parser from 5.5.7 to 5.8.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1521">docker/build-push-action#1521</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1526">docker/build-push-action#1526</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1533">docker/build-push-action#1533</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0">https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f9f3042f7e"><code>f9f3042</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1517">#1517</a>
from docker/dependabot/npm_and_yarn/docker/actions-t...</li>
<li><a
href="812d5fd921"><code>812d5fd</code></a>
chore: update generated content</li>
<li><a
href="b6f6693076"><code>b6f6693</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.87.0 to
0.90.0</li>
<li><a
href="c1c626eced"><code>c1c626e</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1525">#1525</a>
from docker/dependabot/npm_and_yarn/actions/core-3.0.1</li>
<li><a
href="51bb284cd4"><code>51bb284</code></a>
chore: update generated content</li>
<li><a
href="5f7884def8"><code>5f7884d</code></a>
chore(deps): Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1</li>
<li><a
href="e01deff7d9"><code>e01deff</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1521">#1521</a>
from docker/dependabot/npm_and_yarn/fast-xml-parser-...</li>
<li><a
href="3804d49793"><code>3804d49</code></a>
chore: update generated content</li>
<li><a
href="71e8947aac"><code>71e8947</code></a>
chore(deps): Bump fast-xml-parser from 5.5.7 to 5.8.0</li>
<li><a
href="4925ad24cd"><code>4925ad2</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1526">#1526</a>
from docker/dependabot/npm_and_yarn/postcss-8.5.10</li>
<li>Additional commits viewable in <a
href="bcafcacb16...f9f3042f7e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=7.1.0&new-version=7.2.0)](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-05-21 20:02:51 -05:00
dependabot[bot] cb79efa779
build(deps): bump docker/build-push-action from 7.1.0 to 7.2.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.1.0 to 7.2.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](bcafcacb16...f9f3042f7e)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 00:23:23 +00:00
Mike Bommarito 14d9e600ac renderer: skip updateFrame when surface is not visible
renderCallback early-returns while !flags.visible to avoid the
cell rebuild for hidden surfaces (tab switch, minimize, etc.).
The .visible → true mailbox handler now runs updateFrame before
drawFrame so the first frame after re-show isn't stale.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 22:50:03 -04:00
Mike Bommarito 88d30bb30a gtk: wire occlusionCallback to GLArea map/unmap
Calls core_surface.occlusionCallback(visible) from the existing
glareaMap/glareaUnmap handlers (added in #12698) so the renderer
thread learns when a surface is off-screen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 22:50:03 -04:00
Mitchell Hashimoto 46d54ed673
vouch: enable auto-locking closed issues (#12752) 2026-05-20 09:38:17 -07:00
trag1c 4f94afdb4b
vouch: enable auto-locking closed issues 2026-05-20 18:13:49 +02:00
Ken VanDine 25596541ec
snap: export TERMINFO_DIRS so child shells find xterm-ghostty (#12662)
## Summary

When Ghostty is installed via snap on Ubuntu, programs running inside
Ghostty (e.g. `clear`) fail with:

```
terminals database is inaccessible
```

The snap ships terminfo at `${SNAP}/share/terminfo` but the launcher
never exports `TERMINFO_DIRS`, so ncurses in child shells falls back to
the host's system database. On Ubuntu 24.04 (ncurses 6.4) the system
database predates the `xterm-ghostty` entry, so the lookup fails.

This is the same fix as the auto-closed #12303 and resolves #12304.

## Fix

Export `TERMINFO_DIRS` in `snap/local/launcher` so all child processes
can resolve the bundled entry without manual setup.

## Local build (how this PR was verified)

Remix the installed store snap by swapping `app/launcher` with the
patched one:

```sh
sudo unsquashfs -d /tmp/g \
  /var/lib/snapd/snaps/ghostty_$(readlink /snap/ghostty/current).snap
sudo cp snap/local/launcher /tmp/g/app/launcher
sudo mksquashfs /tmp/g /tmp/ghostty-test.snap -comp xz -noappend
sudo snap install --dangerous --classic /tmp/ghostty-test.snap
```

Then launch `/snap/bin/ghostty` and run `clear`.

## Test plan

Verified locally on Ubuntu 24.04 / arm64.

- [x] In default `zsh` / `bash` inside Ghostty, `clear` succeeds.
- [x] `infocmp xterm-ghostty` resolves to
`/snap/ghostty/current/share/terminfo/x/xterm-ghostty`.
- [x] No manual copying of terminfo entries into `~/.terminfo/`
required.

## AI Disclosure

Claude Code was used to investigate the root cause and to draft this
single-line launcher change. The fix is identical to the proposal in the
linked discussion (#12304). I manually verified by remixing the
installed snap with the patched launcher and confirming `clear` and
`infocmp xterm-ghostty` work without manually copying terminfo entries
into `~/.terminfo/` (original workaround shared in the discussion).
2026-05-20 16:57:21 +02:00
Mitchell Hashimoto 86444156b4
build(highway): require `apple_sdk` for darwin builds (#12725)
Noticed this was removed in another PR, but `apple_sdk` is required to
build libghsotty for the iOS simulator, specifically for the x86 version
(see the error log
[here](https://github.com/elias8/libghostty/actions/runs/26075576793/job/76666498246)).
Figured it'd be better to include the SDK in all darwin builds for
consistency.
2026-05-20 06:07:07 -07:00
ghostty-vouch[bot] 19e20f7664
Update VOUCHED list (#12746)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12745#discussioncomment-16984203)
from @jcollie.

Vouch: @mjbommar

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-20 03:31:15 +00:00
ghostty-vouch[bot] 9bcb30aa11
Update VOUCHED list (#12744)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12743#discussioncomment-16981434)
from @bo2themax.

Vouch: @b0uks

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-19 20:36:54 +00:00
Lukas 00a989774e
macOS: add review windows when quitting
Inspired by Terminal.app
2026-05-19 20:01:32 +02:00
Lukas 8f9b86afa8
macOS: add confirmCloseAsync to return the actual response 2026-05-19 20:00:10 +02:00
Lukas 7f5c233492
macOS: add `windowCanBeClosedWithoutConfirmation` without any side effects 2026-05-19 19:56:09 +02:00
Mitchell Hashimoto 8150b5b772
Update iTerm2 colorschemes (#12711)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20260511-160054-2671288
2026-05-19 09:11:09 -07:00
Mitchell Hashimoto 5f2f08ebda
macOS: check the resource the URL refers to (#12731)
- Fixes https://github.com/ghostty-org/ghostty/issues/12727.
[`NSURL.hasDirectoryPath` doesn't do
this](https://developer.apple.com/documentation/foundation/nsurl/hasdirectorypath).

<img width="977" height="177" alt="image"
src="https://github.com/user-attachments/assets/94f77277-8ef0-4573-8ae1-0e54f810463f"
/>

> We don't need to check this in NewTerminalIntent since AppIntent
already appends `/` to the directory.

- Set error when there is no directory to open with
2026-05-19 09:10:05 -07:00
Lukas 3ac7562791
macOS: set error when there is no directory to open with 2026-05-19 09:58:44 +02:00
Lukas fdf84ef7ce
macOS: check the resource the URL refers to.
Fixes #12727. [`NSURL.hasDirectoryPath` doesn't do this](https://developer.apple.com/documentation/foundation/nsurl/hasdirectorypath).

We don't need to check this in NewTerminalIntent since AppIntent already appends `/` to the directory.
2026-05-19 09:58:44 +02:00
ghostty-vouch[bot] 3706abab0c
Update VOUCHED list (#12733)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12732#discussioncomment-16966426)
from @jcollie.

Vouch: @rewdy

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-18 19:17:07 +00:00
Nolin McFarland bf716a0c39 feat: add extension to normalize OSPasteboard string interface 2026-05-18 10:12:26 -04:00
Elias Andualem 7c2b29a9f3 build(highway): require `apple_sdk` for darwin builds 2026-05-18 13:44:34 +08:00
Jeffrey C. Ollie 4b7bf0b20e
IPC: add +toggle-quick-terminal command (#12661)
Add `+toggle-quick-terminal` as a first-class IPC action, following the
same pattern as `+new-window`. This provides a proper CLI command
(`ghostty +toggle-quick-terminal`) to toggle the quick terminal on a
running Ghostty instance.

Closes discussion #12618
2026-05-17 21:03:09 -05:00
Jeffrey C. Ollie cfac861794
split_tree: rescale split ratio when resizing (#12699)
Fixes `SplitTree.resize` not rescaling the split ratio to be relative to
the size of the split. Added a unit test for resizing a nested split.

Previously the new ratio was incorrectly calculated relative to the
entire grid. As a consequence resizing a nested split in the GTK app
would cause unexpected size changes like large jumps. E.g. in the
following recording the window has height ~1000px and the resize was
done using a keybind for `resize_split:up,10`. The change is much larger
than 10 pixels.



https://github.com/user-attachments/assets/ba375ddf-5b2f-45e4-8b12-69021ef2f8a8



Note that even with this fix, resizing by a small amount like 10 pixels
might not work at all (depending on window size and layout), because of
the same bug causing #11193 (see my PR #12698). Initially an inaccurate
split ratio will be set and eventually written back to the split tree
datastructure. That incorrect split ratio will be the same before and
after the small resize, so nothing actually changes in the UI.

The split tree implementation for the macOS app already calculates the
ratios correctly.

AI Disclosure
No AI was used, the bug was discovered and all code written by myself.
2026-05-17 20:20:19 -05:00
Jeffrey C. Ollie 4814aee44e
gtk: fix invisible splits and focus being lost (#12698)
Fixes #11193 where terminal surfaces might not appear and focus might be
lost when creating multiple nested splits.

These bugs are caused by GTK initially allocating a tiny width/height to
deeply nested splits. For a split with a tiny size, the split ratio will
be set inaccurately e.g. to 1 which means that the right/bottom child of
the split is invisible. If that child is the terminal surface that
should have the focus, it will lose it. In the current implementation
the split ratio can be set at most once, which means the inaccurate
ratio never gets corrected and a surface (or an entire sub-tree of the
layout) will stay invisible.

The following explains the current implementation and bug in more
detail, it is a bit long, but I hope it will make it easier to review
this PR.

### Current Implementation

A split layout is a tree, in code represented by `datastruct/SplitTree`,
where inner nodes are splits and leafs are terminal surface. A split can
be either horizontal or vertical, and has a ratio that defines how its
space should be divided among the 2 children.
The counterpart in the GTK UI is the `apprt/gtk/class/SplitTree` widget
whose `onRebuild/buildTree` functions build a widget tree that has the
same structure as the `datastruct/SplitTree`. The widget tree consists
of a `SplitTreeSplit` widget for every split and a `Surface` widget for
every terminal surface.

A `SplitTreeSplit` widget wraps a `gtk.Paned` widget, which displays its
two children with a divider in between, either horizontally or
vertically. How much space each child gets is determined by 3
properties. `min_position` is always 0 in our case, `max_position`
corresponds to the width/height (for horizontal/vertical splits) of the
widget and `position` is where the divider should be. So `position` is
equivalent to the width/height of the left/top child and thereby also
determines the width/height of the right/bottom child. `SplitTreeSplit`
listens for changes in the 3 properties. If there is one, the
`propPosition`, `propMinPosition` or `propMaxPosition` function gets
triggered and an idle callback for the `onIdle` function is added.

We need to make sure that the widget tree and the `datastruct/SplitTree`
stay in sync.

If we e.g. create a new split or close a surface, the structure of the
split tree changes. In that case `gtk/class/SplitTree.onRebuild` will
completely rebuild the widget tree (the `Surface` widgets are actually
reused) to match the new tree structure. If we resize a split (i.e.
change the split ratio) via action/keybind, we also completely rebuild
the widget tree.

Additionally we need to make sure that for every
`SplitTreeSplit/gtk.Paned` the `position` divided by `max_position`
matches the ratio of the corresponding split node in our
`datastruct/SplitTree`. There are two ways the current implementation
keeps these ratios in sync, both are handled by the
`SplitTreeSplit.onIdle` function.
1. Initially when the widget tree is built, GTK allocates each widget a
size. Specifically it also sets the `position` and `max_position`
properties of each `gtk.Paned` widget, which will trigger the
`SplitTreeSplit.onIdle` function to run. GTK will not necessarily set
position correctly, it is the task of `onIdle` to make sure that the UI
matches the layout defined by the `datastruct/SplitTree`. `onIdle`
checks if `position/max_position` matches the ratio that the split
should have and if not calls `gtk.Paned.setPosition` to update it. This
can only happen once for each split since `onIdle` checks if the
position was set previously. The idea is that we should only ever need
to set the position once, because `gtk.Paned` will automatically keep
its current ratio whenever its size/`max-position` changes (if the
`setPosition` function has been called before). A size change can happen
e.g. because the entire window was resized or because an ancestor split
changed its split ratio.
2. The user can manually change the ratio between the two children of a
split by dragging the divider between them in the UI. When that happens
the `position` property in `gtk.Paned` changes and eventually the
`SplitTreeSplit.onIdle` function gets called. Since `setPosition` should
have already been called when the widget was initially sized, we should
fall through to the second case and write the current ratio back to the
`datastructure/SplitTree`.

The problem with `SplitTreeSplit.onIdle` is that sometimes the split
ratio cannot be set accurately given the current size of the `gtk.Paned`
widget. Because `onIdle` can only set the position/ratio once, any
previous inaccuracy can never get corrected.

For example with many nested vertical splits, GTK might initially
allocate a `gtk.Paned` widget a height of 1. It will have
`max_position=1` and `position=1`. When `onIdle` runs the current ratio
of `position/max_position = 1` is different from the desired ratio of
e.g. 0.5. But a ratio of 0.5 cannot be set, the position can only be 0
or 1 corresponding to a ratio of 0 or 1. The position will then get set
as 1 and can't be changed later. Even when the split later gets a larger
height, it will keep the ratio of 1 and the bottom child will stay
invisible. When the surface that should be focused initially becomes
invisible it loses focus and the focus will never be restored. That is
exactly what happens in the first screencast in the issue description
(#11193).

Another problem with `onIdle` is that the `setPosition` call in `onIdle`
will trigger another idle callback where the position change is
sometimes wrongly interpreted as a manual update and written back to the
tree. Also sometimes the initial ratio in a `gtk.Paned` can already be
correct, in which case position will not get set. The next manual
position update is then not detected as a manual update.

### Changes

`SplitTreeSplit.onIdle` is now able to set the split position every time
the widget is resized, an inaccurate initial ratio will be corrected. To
be able to distinguish a widget resize from a manual position update by
the user, we keep track of whether `max-position`, `position` or both
properties changed. If only `max-position` or both properties changed,
then the widget was resized. If just `position` changed it is a manual
update. This is kind of hacky but works. To verify I checked the source
code for `gtk.Paned`, see the comment in the code on `onIdle`.

`SplitTreeSplit` no longer listens to changes in `min-position`, that
should always be 0 (because we use the default resize/shrink properties
for `gtk.Paned`) and there is already an assert in `onIdle` that checks
that.

It can still happen that a surface initially gets allocated width/height
0 and loses focus. The only reliable way to detect when we can restore
focus, is to listen to the `map/unmap` signals exposed by `gtk.Widget`.
The `Surface` widget now listens to these signals on its `GlArea` child
(because that is where we want to put focus) and stores the current
state in the new `mapped` property. The `SplitTree` widget listens to
changes in that property: when surfaces become mapped, an idle callback
for the new `onRestoreFocus` function is added, which will check whether
the last focused surface is mapped and if so restore focus to it.

### Other possible solutions

Alternatively we could try to only set the split ratio once the split
has its correct final size, but I think it's hard to detect that
reliably. Or we could try to prevent the splits/surfaces from becoming
invisible in the first place by e.g. setting a minimal widget size. But
then you won't get the exactly correct layout and sometimes you do want
a surface to be tiny or invisible e.g. you can drag the divider in a
split all the way to one side.

The ideal solution would probably be to write a custom version of
`gtk.Paned` where you can provide the desired ratio on widget creation.
Then everything will be sized correctly from the start, focus will not
be lost. In terms of performance it would probably be better as well,
because right now there can be multiple rounds of resizes until every
split/surface has its correct size. I have played around with this a
bit, it is definitely possible. But you would have to implement the
divider widget, logic for layouting, handling gestures and co. That is a
bigger undertaking.

### Testing

Tested by creating/modifying deeply nested layouts, dragging split
dividers and resizing splits via keybind. Checked that ratios are
maintained when the window is resized and tested that it works with
zoom. Tested locally with hyprland and in a VM with KDE.

All the bugs described in the issue should be fixed.

### AI Disclosure

Discovered the bug and wrote all code/comments by myself. Used AI in
researching various internals of GTK.
2026-05-17 20:20:01 -05:00
Jeffrey C. Ollie 22b9df25e6
Fix "Available since"
Co-authored-by: Leah Amelia Chen <github@acc.pluie.me>
2026-05-17 14:42:27 -05:00
Nolin McFarland ed52160612 feat: support BackportSelectionTextField on iOS 18 2026-05-17 12:33:56 -04:00
Nolin McFarland 69cab3d808 feat: select needle when reading from pasteboard 2026-05-17 11:26:32 -04:00
Jeffrey C. Ollie e90b7c9fad
build(deps): bump actions/create-github-app-token from 3.1.1 to 3.2.0 (#12670)
Bumps
[actions/create-github-app-token](https://github.com/actions/create-github-app-token)
from 3.1.1 to 3.2.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's
releases</a>.</em></p>
<blockquote>
<h2>v3.2.0</h2>
<h2><a
href="https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0">3.2.0</a>
(2026-05-12)</h2>
<h3>Features</h3>
<ul>
<li>add support for enterprise-level GitHub Apps (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)
(<a
href="952a2a7073">952a2a7</a>)</li>
<li>support full repository names in <code>repositories</code> input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)
(<a
href="85eb8dd414">85eb8dd</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@​actions/core</code> from 3.0.0
to 3.0.1 in the production-dependencies group (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/364">#364</a>)
(<a
href="43e5c345bf">43e5c34</a>)</li>
<li>validate private-key input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)
(<a
href="f24bbd8964">f24bbd8</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/blob/main/CHANGELOG.md">actions/create-github-app-token's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2><a
href="https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0">3.2.0</a>
(2026-05-12)</h2>
<h3>Features</h3>
<ul>
<li>add support for enterprise-level GitHub Apps (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)
(<a
href="952a2a7073">952a2a7</a>)</li>
<li>support full repository names in <code>repositories</code> input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)
(<a
href="85eb8dd414">85eb8dd</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@​actions/core</code> from 3.0.0
to 3.0.1 in the production-dependencies group (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/364">#364</a>)
(<a
href="43e5c345bf">43e5c34</a>)</li>
<li>validate private-key input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)
(<a
href="f24bbd8964">f24bbd8</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bcd2ba4921"><code>bcd2ba4</code></a>
chore(main): release 3.2.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/370">#370</a>)</li>
<li><a
href="f24bbd8964"><code>f24bbd8</code></a>
fix: validate private-key input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)</li>
<li><a
href="363531b6d9"><code>363531b</code></a>
docs: capitalize Git as a proper noun in README (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/374">#374</a>)</li>
<li><a
href="fd2801133e"><code>fd28011</code></a>
docs: update procedure to configure Git (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/287">#287</a>)</li>
<li><a
href="85eb8dd414"><code>85eb8dd</code></a>
feat: support full repository names in <code>repositories</code> input
(<a
href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)</li>
<li><a
href="c9aabb8372"><code>c9aabb8</code></a>
build(deps-dev): bump yaml from 2.8.3 to 2.8.4 in the
development-dependencie...</li>
<li><a
href="e02e816e55"><code>e02e816</code></a>
build(deps-dev): bump undici from 7.24.6 to 8.2.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/366">#366</a>)</li>
<li><a
href="8d835bfd37"><code>8d835bf</code></a>
build(deps-dev): bump esbuild from 0.27.4 to 0.28.0 in the
development-depend...</li>
<li><a
href="952a2a7073"><code>952a2a7</code></a>
feat: add support for enterprise-level GitHub Apps (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)</li>
<li><a
href="43e5c345bf"><code>43e5c34</code></a>
fix(deps): bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in the
production-dependenc...</li>
<li>Additional commits viewable in <a
href="1b10c78c78...bcd2ba4921">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=3.1.1&new-version=3.2.0)](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-05-16 19:42:18 -05:00
mitchellh aed646139d deps: Update iTerm2 color schemes 2026-05-17 00:33:21 +00:00
Nolin McFarland 8fa42c6ec0 feat: add search state unit tests 2026-05-16 20:05:11 -04:00
Nolin McFarland 59eece9a8e feat: use find pasteboard to store search needle 2026-05-16 19:59:20 -04:00
Lukas b6c6f7630a
macos: opacity-toggle setting persists between tabs in a window and to a newly created window (#11583) 2026-05-17 00:45:24 +02:00
ghostty-vouch[bot] cf24a4856b
Update VOUCHED list (#12707)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12625#discussioncomment-16940042)
from @bo2themax.

Unvouch: @backnotprop

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-16 12:57:27 +00:00
ghostty-vouch[bot] 42ed74bf8c
Update VOUCHED list (#12706)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12686#discussioncomment-16940039)
from @bo2themax.

Vouch: @nolinmcfarland

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-16 12:56:56 +00:00
ghostty-vouch[bot] 0a3598d7a1
Update VOUCHED list (#12705)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12625#discussioncomment-16940011)
from @bo2themax.

Vouch: @backnotprop

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-16 12:53:21 +00:00
Daniel Kinzler 9f72eb9d7c added back accidentally deleted empty line 2026-05-15 17:52:48 +02:00
Daniel Kinzler 93d1142ada small formatting changes 2026-05-15 17:20:57 +02:00
Jeffrey C. Ollie 0071971b57
Delete test_align (#12688)
Checked in to make sure that this wasn't added intentionally
🙂

Looks like it snuck in in #11868.
2026-05-14 22:50:26 -05:00
ghostty-vouch[bot] 84ad649128
Update VOUCHED list (#12689)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12688#issuecomment-4456633108)
from @rhodes-b.

Vouch: @vancluever

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-15 03:28:40 +00:00
Chris Marchesi e9213bb1e7
Delete test_align
Checked in to make sure that this wasn't added intentionally 🙂

Looks like it snuck in in #11868.
2026-05-14 20:27:04 -07:00
Leah Amelia Chen 96848d792e
config: clear `command-palette-entry` like `keybind` (#12682)
After #1368, `command-palette-entry=` will no longer clear the entries
like the documentation says. Since i couldn't find an existing issue or
discussion about this, I assume no one is actually using it. So I put
1.4.0 here, lemme know if you want to change it to 1.3.2.

> I basically copied the `keybind` parsing code and doc.
2026-05-15 03:27:07 +09:00
Lukas 13ca032b1d
config: clear `command-palette-entry` like `keybind`
After #1368, `command-palette-entry=` will no longer clear the entries like the documentation says. Since i couldn't find an existing issue or discussion about this, I assume no one is actually using it. So I put 1.4.0 here, lemme know if you want to change it to 1.3.2.

> I basically copied the `keybind` parsing code and doc.
2026-05-14 19:43:08 +02:00
ghostty-vouch[bot] 47382f8dcb
Update VOUCHED list (#12680)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12678#issuecomment-4452472142)
from @trag1c.

Denounce: @zaviro

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-14 16:15:46 +00:00
Daniel Kinzler 54a38e8134 Distinguish resize and manual update using a combination of
max-position and position properties. Listening to drag events directly
did not work that well.
2026-05-14 15:45:29 +02:00
ghostty-vouch[bot] b23d567cd8
Update VOUCHED list (#12675)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12674#issuecomment-4445057781)
from @trag1c.

Vouch: @B1NAR10

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-13 20:43:34 +00:00
dependabot[bot] ee316e43c1
build(deps): bump actions/create-github-app-token from 3.1.1 to 3.2.0
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Changelog](https://github.com/actions/create-github-app-token/blob/main/CHANGELOG.md)
- [Commits](1b10c78c78...bcd2ba4921)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-13 01:38:02 +00:00
Daniel Kinzler e59e27f8bd Fix nested splits disappearing and focus being lost.
The cause of these bugs is that GTK can initially allocate
a split/surface a width/height of 0 which causes it to
get unmapped and lose focus. Additionally the split ratio is
only set once but not accurately for tiny splits, which can keep
a surface invisible even when the split gets resized later.

To fix these problems the split ratio is always checked and
possibly corrected when a split gets resized. Changes in a split
ratio caused by the user dragging the divider are detected
separately using an event controller. If a surface loses focus
we restore it once the surface becomes mapped again.
2026-05-12 14:13:35 +02:00
Lukas 0226bcf034
macOS: update window appearance for About and ConfigurationErrors 2026-05-12 09:20:08 +02:00
Lukas 2c6dd59406
macOS: fix render_thread "stuck" after dragging surface to another tab within the same window
The reason the thread is stuck is because the surface's occlusion state is set to invisible after target tab's activate while dragging, since the dragged surface is still in previous tree before dropping, and after dropping the occlusion state of this surface is not updated to visible, which causing the surface is accepting input but not rendering.
2026-05-12 09:18:52 +02:00
Lukas 366c34831a
macOS: fix first responder after dragging a non-focused surface
This fixes a bug: after dragging a non-focused surface from window A to window B **quickly without making B the key window**, the focused surface in window A is not receiving `keyDown` events.
2026-05-12 09:18:51 +02:00
Hua Jiang 81af65766f feat: add +toggle-quick-terminal IPC command
Expose toggle-quick-terminal as a proper IPC action so it can be
triggered via 'ghostty +toggle-quick-terminal' from the command line,
instead of calling the raw D-Bus org.gtk.Actions.Activate interface.

This follows the same pattern as the existing +new-window IPC command:

  - Add toggle_quick_terminal to apprt.ipc.Action enum (Zig + C ABI)
  - Create apprt/gtk/ipc/toggle_quick_terminal.zig (GTK D-Bus handler)
  - Route .toggle_quick_terminal in apprt/gtk/App.zig performIpc
  - Register toggle-quick-terminal GAction in application.zig
  - Add +toggle-quick-terminal CLI handler in cli/
  - Register in cli/ghostty.zig Action enum, runMain, and options
  - Add stub in apprt/embedded.zig
  - Update include/ghostty.h C header enum

Usage:
  ghostty +toggle-quick-terminal

Closes: #12618
2026-05-12 09:03:14 +08:00
Mitchell Hashimoto b0f8276658
build(deps): bump cachix/cachix-action from 1eb2ef646ac0255473d23a5907ad7b04ce94065c to 5f2d7c5294214f71b873db4b969586b980625e71 (#12651)
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action)
from 1eb2ef646ac0255473d23a5907ad7b04ce94065c to
5f2d7c5294214f71b873db4b969586b980625e71.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/cachix/cachix-action/blob/master/RELEASE.md">cachix/cachix-action's
changelog</a>.</em></p>
<blockquote>
<h1>Release</h1>
<ol>
<li>
<p>Create and push a new tag:</p>
<pre lang="console"><code>git tag v17
git push origin v17
</code></pre>
</li>
<li>
<p>Wait for CI to pass.</p>
</li>
<li>
<p><a href="https://github.com/cachix/cachix-action/releases/new">Create
a release</a> for the new tag.</p>
</li>
<li>
<p>Move the major version tag to the latest release:</p>
<pre lang="console"><code>git tag -fa v17
git push origin v17 --force
</code></pre>
</li>
</ol>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5f2d7c5294"><code>5f2d7c5</code></a>
fix: await main functions</li>
<li><a
href="4ee54539d7"><code>4ee5453</code></a>
rebuilt dist</li>
<li><a
href="9f82c7e332"><code>9f82c7e</code></a>
fix: ensure that the post-build hook never fails</li>
<li><a
href="a593539ec5"><code>a593539</code></a>
ci: add a workflow to auto-bump version in README</li>
<li><a
href="8d6d4b9006"><code>8d6d4b9</code></a>
docs: add release and contributing docs</li>
<li><a
href="6505427c13"><code>6505427</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/cachix-action/issues/213">#213</a>
from jleroux98/update-readme</li>
<li><a
href="5941c26199"><code>5941c26</code></a>
use regular tags</li>
<li><a
href="80a630b9fc"><code>80a630b</code></a>
update tags</li>
<li>See full diff in <a
href="1eb2ef646a...5f2d7c5294">compare
view</a></li>
</ul>
</details>
<br />


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-05-11 06:54:27 -07:00
ghostty-vouch[bot] 64131dcd41
Update VOUCHED list (#12656)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12616#discussioncomment-16876564)
from @pluiedev.

Vouch: @00JCIV00

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-11 08:07:48 +00:00
ghostty-vouch[bot] 611525ac3f
Update VOUCHED list (#12655)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12618#discussioncomment-16876561)
from @pluiedev.

Vouch: @thirstycrow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-11 08:07:26 +00:00
ghostty-vouch[bot] 4c6859447c
Update VOUCHED list (#12654)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12650#discussioncomment-16876487)
from @pluiedev.

Vouch: @athaapa

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-11 08:01:15 +00:00
Riccardo Mazzarini b771a3d4f1
libghostty-vt: preserve shell prompts on resize by default
This PR makes libghostty-vt preserve shell prompts across resize unless
the shell explicitly opts into prompt clearing/redraw with `redraw=1`.
2026-05-11 08:48:25 +02:00
dependabot[bot] b3c1f754ad
build(deps): bump cachix/cachix-action
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action) from 1eb2ef646ac0255473d23a5907ad7b04ce94065c to 5f2d7c5294214f71b873db4b969586b980625e71.
- [Release notes](https://github.com/cachix/cachix-action/releases)
- [Changelog](https://github.com/cachix/cachix-action/blob/master/RELEASE.md)
- [Commits](1eb2ef646a...5f2d7c5294)

---
updated-dependencies:
- dependency-name: cachix/cachix-action
  dependency-version: 5f2d7c5294214f71b873db4b969586b980625e71
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-11 00:28:49 +00:00
ghostty-vouch[bot] ce6a00bfbf
Update VOUCHED list (#12647)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12644#issuecomment-4415471290)
from @jcollie.

Denounce: @f1813483-netizen

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-10 14:02:12 +00:00
Jon Parise e3e9b51b79
macos: simplify workingDirectory setter (#12639)
This is a minor improvement to the computed property's `set` logic: we
can just use `.map {}` to unify the two optional paths.
2026-05-09 15:01:45 -04:00
Jon Parise 2b48045731 macos: simplify workingDirectory setter
This is a minor improvement to the computed property's `set` logic: we
can just use `.map {}` to unify the two optional paths.
2026-05-09 14:37:43 -04:00
kat a330ee93e8
i18n: add Basque (eu) translation (#12544)
Same as with icelandic (#12301) we may be even fewer than them but let's
have this translated into Basque.

I also volunteer for the basque translation team.
2026-05-09 16:12:57 +00:00
Mitchell Hashimoto 4bd8fa1e3e
macOS: normalize working directory paths with FilePath (#12614)
This fixes for
[Nushell](f342d8acfa/crates/nu-protocol/src/engine/engine_state.rs (L1012))
when opening Ghostty via Finder service and Shortcuts, also makes path
parsing more robust in AppleScript.

<img width="976" height="690" alt="image"
src="https://github.com/user-attachments/assets/d3c19481-39ce-4797-ba31-d431af16651d"
/>
2026-05-09 08:17:29 -07:00
Lukas 607152ec6d
macOS: normalize working directory paths with FilePath
This fixes for nuShell when opening Ghostty via Finder service and Shortcuts, also makes path parsing more robust in AppleScript.
2026-05-09 12:47:46 +02:00
Mikel Larreategi ec145bca9f
Fix translation errors in eu 2026-05-08 19:18:09 +02:00
ghostty-vouch[bot] 063ac3ecc5
Update VOUCHED list (#12613)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12612#issuecomment-4395645191)
from @trag1c.

Vouch: @raphamorim

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-07 08:56:04 +00:00
ghostty-vouch[bot] 0deaac08ed
Update VOUCHED list (#12606)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12604#issuecomment-4392933026)
from @jcollie.

Vouch: @mohshami

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-06 23:25:11 +00:00
Riccardo Mazzarini c44afa6250
fix: preserve active cursor position during reflow
This PR fixes an issue where reflowing could leave the active cursor
attached to a clipped trailing blank cell instead of following the
current write position.
2026-05-06 14:56:52 +02:00
Riccardo Mazzarini 3f11e695d0
fix: apply variation selectors to preceding codepoint
This fixes a bug where the variation selectors (VS15 & VS16) were
checked against the first codepoint in a cell instead of the previous
codepoint in the cell's grapheme cluster, causing them to be dropped if
the first codepoint was not a valid base.
2026-05-06 10:45:47 +02:00
Daniel Kinzler 57a9adce71 fix datastruct/SplitTree not calculating the correct new split ratio when resizing a split 2026-05-05 18:00:04 +02:00
Jon Parise ac103b8f75 nushell: replace ssh wrapper with ghostty +ssh
Replace the inline ssh integration with a thin wrapper that translates
GHOSTTY_SHELL_FEATURES into a `ghostty +ssh` command line. When no
ssh-* feature is enabled, the wrapper falls through to the real `ssh`
binary unchanged so nushell users without ssh integration get plain
ssh behavior.
2026-05-05 08:30:53 -04:00
Jon Parise e5378107eb elvish: replace ssh wrapper with ghostty +ssh
Replace the inline ssh integration with a thin wrapper that translates
GHOSTTY_SHELL_FEATURES into a `ghostty +ssh` command line.
2026-05-05 08:30:53 -04:00
Jon Parise 283dca130e fish: replace ssh wrapper with ghostty +ssh
Replace the inline ssh integration with a thin wrapper that translates
GHOSTTY_SHELL_FEATURES into a `ghostty +ssh` command line.
2026-05-05 08:30:52 -04:00
Jon Parise 2d112059a7 zsh: replace ssh wrapper with ghostty +ssh
Replace the inline ssh integration with a thin wrapper that translates
GHOSTTY_SHELL_FEATURES into a `ghostty +ssh` command line. The shell
wrapper no longer carries terminfo install, ControlMaster wiring, or
cache bookkeeping; it just maps the feature flags to flags on `+ssh`
and forwards everything else.
2026-05-05 08:30:52 -04:00
kat f9a9d33b3a
docs(input): add documentation for missing action parameters (#12579)
### AI Disclosure

Claude generated all the commits, I reviewed it and created this PR
2026-05-05 08:59:39 +00:00
Lukas 5874ce633c
Apply suggestions from code review
Co-authored-by: kat <65649991+00-kat@users.noreply.github.com>
Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com>
2026-05-05 09:47:06 +02:00
Jeffrey C. Ollie ac48a9b15b
build(deps): bump cachix/install-nix-action from 31.10.5 to 31.10.6 (#12584)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.10.5 to 31.10.6.
<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.10.6</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.34.6 -&gt; 2.34.7 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/275">cachix/install-nix-action#275</a>
<strong><a
href="https://github.com/NixOS/nix/security/advisories/GHSA-vh5x-56v6-4368">GHSA-vh5x-56v6-4368</a></strong>:
Fixes a coroutine stack-to-heap overflow via unbounded recursion in the
NAR directory parser. <strong>Severity: High.</strong>
<strong><a
href="https://github.com/NixOS/nix/security/advisories/GHSA-gr92-w2r5-qw5p">GHSA-gr92-w2r5-qw5p</a></strong>:
Fixes an absolute path traversal vulnerability when unpacking archives
to disk. Severity: Moderate.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.10.6">https://github.com/cachix/install-nix-action/compare/v31...v31.10.6</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8aa03977d8"><code>8aa0397</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/275">#275</a>
from cachix/create-pull-request/patch</li>
<li><a
href="21d0b780f0"><code>21d0b78</code></a>
nix: 2.34.6 -&gt; 2.34.7</li>
<li>See full diff in <a
href="ab739621df...8aa03977d8">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.10.5&new-version=31.10.6)](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-05-04 23:10:07 -05:00
dependabot[bot] 81e399c412
build(deps): bump cachix/install-nix-action from 31.10.5 to 31.10.6
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.10.5 to 31.10.6.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](ab739621df...8aa03977d8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-05 03:08:21 +00:00
Jon Parise 484d6ec66b cli: add an ssh-wrapping +ssh action
Add a drop-in `ssh` wrapper that sets up the remote environment for
Ghostty. Anything not consumed as one of our own flags is forwarded to
the real, wrapped `ssh` binary. It can be used directly (`ghostty +ssh
user@host`), aliased (`alias ssh='ghostty +ssh --'`), or invoked through
Ghostty's shell integration.

Before exec'ing ssh, `+ssh`:

- Forwards Ghostty environment to the remote (`--forward-env`): sets
  TERM=xterm-256color and requests SendEnv forwarding of COLORTERM,
  TERM_PROGRAM, and TERM_PROGRAM_VERSION.
- Installs Ghostty's terminfo on the remote (`--terminfo`), informed by
  our existing `ssh-cache` system and using our internal xterm-ghostty
  terminfo representation.

A third flag, `--cache`, controls cache use; `--cache=false` bypasses
both read and write, which is useful for scripting and for debugging
install failures without polluting the cache.

For shell integration, this replaces the per-shell logic (which made up
roughly a third of our shell integration scripts) with a simple wrapper
function that translates GHOSTTY_SHELL_FEATURES into a `ghostty +ssh`
command line. This commit only migrates the bash integration; the other
shells will follow separately.
2026-05-04 20:21:45 -04:00
Mitchell Hashimoto 563b085a4d
Fix zero-width grapheme attachment during pending wrap (#12581)
This PR fixes an issue where a zero-width combining mark could attach to
the wrong cell when the preceding character was written in the final
column and the cursor had a pending wrap.

The test I added used to fail before the fix, but it passes now.
2026-05-04 14:37:31 -07:00
Mitchell Hashimoto c2c0901ed0
Update iTerm2 colorschemes (#12562)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20260427-153600-5e4d1de
2026-05-04 14:17:29 -07:00
Riccardo Mazzarini c20fcfa1b4
Fix zero-width grapheme attachment during pending wrap
This PR fixes an issue where a zero-width combining mark could attach to
the wrong cell when the preceding character was written in the final
column and the cursor had a pending wrap.
2026-05-04 23:16:41 +02:00
Claude Opus 4.7 df44c6dd83
docs(input): document close_tab arguments 2026-05-04 18:39:02 +02:00
Claude Opus 4.7 b1b01741f6
docs(input): document navigate_search arguments 2026-05-04 16:57:56 +02:00
Claude Opus 4.7 248df8e7aa
docs(input): document copy_to_clipboard arguments 2026-05-04 16:57:37 +02:00
ghostty-vouch[bot] 1547dd667a
Update VOUCHED list (#12564)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12563#discussioncomment-16793038)
from @jcollie.

Vouch: @agoodkind

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-03 02:02:22 +00:00
mitchellh 28767f62b1 deps: Update iTerm2 color schemes 2026-05-03 00:30:37 +00:00
Mitchell Hashimoto f0bb6ed9ee
macos: avoid replaying keys that commit preedit (#12547)
Refs #10460
Related: #12518

When an input method commits all or part of marked text during keyDown,
AppKit returns the committed text through insertText. Treat that as text
committed by the input method instead of replaying the original key
event to the terminal.

Previously this path only handled arrow-key commits specially. A
control-key shortcut that commits preedit text could still be encoded as
the original control input after composition, such as ctrl+j becoming
LF.

Send committed preedit text as a text-only event for any key that causes
the commit. Only replay arrow navigation keys that the existing Korean
IME handling expects, and keep plain left-arrow suppressed because
AppKit already leaves the caret in place.

Before:
<img width="375" height="375" alt="before"
src="https://github.com/user-attachments/assets/1073b93f-625a-4881-8f95-67adefe9d3da"
/>

After:
<img width="375" height="375" alt="after"
src="https://github.com/user-attachments/assets/3e4be2a5-4df9-4cdd-bc95-e178ca44c7e7"
/>

AI usage: OpenAI Codex helped investigate, implement, test, and refine
this change. I reviewed and tested the resulting code.
2026-05-02 08:24:42 -07:00
Mitchell Hashimoto 058d054fa2
libghostty-vt: support building on macOS with Nix (#12548)
Adds support for building libghostty-vt on macOS with Nix.

Tested on aarch64-darwin. Tests pass as well.

_Claude used to speed up debugging process. All comments, commit
messages, and final code authored by me._
2026-05-02 08:14:33 -07:00
ghostty-vouch[bot] f27aa865af
Update VOUCHED list (#12552)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12542#discussioncomment-16785276)
from @00-kat.

Denounce: @MorgenGeluk

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-02 01:55:53 +00:00
Sander 7123bddc18
libghostty-vt: fix linker tests for darwin 2026-05-01 16:44:52 +02:00
Sander d17e5517c7
libghostty-vt: fix dependency path resolution errors
Zigs build infra computes relatives paths to build-time executables that use `setCwd.`
The logic is purely lexical and doesn't take into account symlinks, unlike `chdir` that follows symlinks.

If the `cwd` resolves to a different depth, then the relative path becomes incorrect.
2026-05-01 16:44:52 +02:00
Sander 9df670cb55
build: skip unnecessary steps for libghostty-vt 2026-05-01 16:22:23 +02:00
Sander a971bf16a0
libghostty-vt: support building nix derivation on darwin 2026-05-01 16:22:00 +02:00
Akinori Musha d60a16c146 macos: avoid replaying keys that commit preedit
Refs #10460
Related: #12518

When an input method commits all or part of marked text during keyDown,
AppKit returns the committed text through insertText. Treat that as
text committed by the input method instead of replaying the original key
event to the terminal.

Previously this path only handled arrow-key commits specially. A
control-key shortcut that commits preedit text could still be encoded as
the original control input after composition, such as ctrl+j becoming LF.

Send committed preedit text as a text-only event for any key that causes
the commit. Only replay arrow navigation keys that the existing Korean
IME handling expects, and keep plain left-arrow suppressed because AppKit
already leaves the caret in place.

AI usage: OpenAI Codex helped investigate, implement, test, and refine
this change. I reviewed and tested the resulting code.
2026-05-01 23:18:42 +09:00
Mikel Larreategi afb8fc7eb3
Update po/eu.po
Co-authored-by: kat <65649991+00-kat@users.noreply.github.com>
2026-05-01 13:51:01 +02:00
ghostty-vouch[bot] 35c0e2572f
Update VOUCHED list (#12545)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12544#issuecomment-4359105411)
from @trag1c.

Vouch: @erral

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-01 11:38:57 +00:00
Mikel Larreategi cbd43fd483 feature: add basque translation 2026-05-01 13:34:23 +02:00
Mitchell Hashimoto 4dcb09ada0
macos: suppress control-char input while composing (#12518)
macos: suppress control-char input while composing

When AppKit delivers a single C0 control character during marked-text
composition, Ghostty should treat it as input consumed by the composing
state instead of forwarding it to the terminal.

This prevents control-key IME actions, such as Japanese input shortcuts
like ctrl+h/j/m/n, from leaking into the terminal while composition is
still active. Printable text and non-composing control input continue
through the normal key path.

Refs #10460
Related: #2628, #4539
Vouched in #12169

Testing:
- xcodebuild test -scheme Ghostty -destination platform=macOS
-only-testing:GhosttyTests/SurfaceViewAppKitTests
- Manually tested Japanese IME control-key shortcuts on macOS

AI usage:
- OpenAI Codex helped investigate, implement, test, and refine this
change. I reviewed and tested the resulting code.
2026-04-30 06:48:58 -07:00
Mitchell Hashimoto 95b56eb525
macOS: fix focus state when toggling command palette from inline title editor (#12524)
A bug found while recording that menu fix.
> ~~Will link to an open issue if there is one.~~

When toggling the command palette from the inline title editor, the
first responder state of the surface is changed quickly from true to
false.

`makeFirstResponder:` is called by the title editor when finishing, but
it happens **after** the command palette is shown, so the `focused` is
set to `true` while the command palette is shown. (Could be an AppKit
issue as well, since the resign is not called after but the command
palette is receiving `keyDown`.)

Since `performKeyEquivalent(with:)` is called on all of the subviews
until one of the return `true` so the paste action is consumed by the
surface instead of the first responder (command palette).
2026-04-30 06:42:12 -07:00
Mitchell Hashimoto 1623daf21c
macOS: enable copy only when there’s actual selected text (#12521)
This matches the `peformable` definition and the default behaviors of
text editing on macOS.
2026-04-30 06:41:04 -07:00
Mitchell Hashimoto 25cd206e25
chore(macOS): remove Ghostty.xctestplan in project tree. (#12520)
`lastKnownFileType = file` will change to `text` if you checking out
branches with Xcode opened. But this was generated by Xcode in the first
place.

Anyway we don't need it to be in the project tree to run the tests, and
you can still open the test plan in scheme editor.
2026-04-30 06:39:09 -07:00
Mitchell Hashimoto 83ae47191a
Fall back to Zig-bundled Darwin headers when an SDK can't be found (#12534)
Currently, cross to Darwin uses the Darwin headers bundled with Zig.
However, if you're running a build _on_ Darwin, an error is thrown if
the SDK can't be found, even though the bundled headers are still
available.

Now, we continue to search for and prefer the installed SDK, but if it
can't be found, we fall back to the bundled headers rather than failing
the build.
2026-04-30 06:38:41 -07:00
ghostty-vouch[bot] f5664cd7b0
Update VOUCHED list (#12533)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12530#discussioncomment-16765566)
from @jcollie.

Vouch: @Samasaur1

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-30 06:29:58 +00:00
Sam f8f3b6f694
Fall back to Zig-bundled Darwin headers when an SDK can't be found
Currently, cross to Darwin uses the Darwin headers bundled with Zig.
However, if you're running a build _on_ Darwin, an error is thrown if
the SDK can't be found, even though the bundled headers are still
available.

Now, we continue to search for and prefer the installed SDK, but if it
can't be found, we fall back to the bundled headers rather than failing
the build.
2026-04-29 22:15:20 -07:00
Lukas 61595b5ec9
macOS: fix focus state when toggling command palette from inline title editor 2026-04-29 22:41:18 +02:00
Lukas 6fdca6bb53
macOS: enable copy only when there’s actual selected text 2026-04-29 19:33:09 +02:00
Lukas dbffe994db
chore: remove Ghostty.xctestplan in project tree.
`lastKnownFileType = file` will change to `text` if you checking out branches with Xcode opened. But this was generated by Xcode in the first place.

Anyway we don't need it to be in the project tree to run the tests, and you can still open the test plan in scheme editor.
2026-04-29 19:24:03 +02:00
Akinori Musha a43cc02ebd macos: suppress control-char input while composing
When AppKit delivers a single C0 control character during
marked-text composition, Ghostty should treat it as input consumed by
the composing state instead of forwarding it to the terminal.

This prevents control-key IME actions, such as Japanese input
shortcuts like ctrl+h/j/m/n, from leaking into the terminal while
composition is still active. Printable text and non-composing control
input continue through the normal key path.

AI usage: OpenAI Codex helped investigate, implement, test, and refine
this change. I reviewed and tested the resulting code.
2026-04-29 22:50:35 +09:00
Mitchell Hashimoto 6590196661
Fix speedy high-resolution scrolling on Linux (#12483)
Enforcing an absolute minimum of 1 for scroll events causes differing
scroll speeds between high-resolution and standard scroll wheels on
Linux. Since this was added to handle MacOS's precision scrolling
emulation, this patch alters the behaviour so that the absolute minimum
is only enforced on MacOS.

NB: This can't just be fixed by adjusting `mouse-scroll-multiplier`
since that affects *all* scroll events whether they're high-resolution
or not. Reducing `mouse-scroll-multiplier` to handle high-res scroll
events better makes scrolling unusably slow for regular scroll wheels
connected to the same machine.

Fixes #11648.
2026-04-27 13:33:46 -07:00
Aditya Bhargava 5871a2d4f0
zig-fmt cleanup 2026-04-27 16:28:23 -04:00
Aditya Bhargava 154169b054
Fix speedy high-resolution scrolling on Linux
Enforcing an absolute minimum of 1 for scroll events causes differing
scroll speeds between high-resolution and standard scroll wheels on
Linux. Since this was added to handle MacOS's precision scrolling
emulation, this patch alters the behaviour so that the absolute minimum
is only enforced on MacOS.

Fixes #11648.
2026-04-27 16:28:23 -04:00
Mitchell Hashimoto 2cbe706276
macOS: fix keybindings for end_search not working correctly (#12492)
This now fixes #11410 completely, `navigate_search:next` and
`navigate_search:previous` are already fixed in
18f2702225.

Also fixes: surface is not focused after ending search via menu bar
2026-04-27 13:14:08 -07:00
Mitchell Hashimoto 8925a91c5c
update zon2nix to 0.5.0 (#12488)
fix hash outputs for flatpak
2026-04-27 13:13:46 -07:00
Jeffrey C. Ollie acbaa47de5
switch back to older nixpkgs 2026-04-27 13:53:02 -05:00
Jeffrey C. Ollie 8f3d9b4690
update zon2nix to 0.5.0
fix hash outputs for flatpak
build with Zig 0.16 from nixpkgs
(which required fixing prettier reference in devShell.nix)
2026-04-27 12:42:04 -05:00
Lukas 97c5a21aba
macOS: fix ending search in menu bar does focus on surface 2026-04-27 19:03:06 +02:00
Lukas 1df7a5d3f3
macOS: update keybind for end_search 2026-04-27 18:55:31 +02:00
Mitchell Hashimoto 34cbb5fa81
feat: add middle-click action configuration (#12478)
This PR addresses
https://github.com/ghostty-org/ghostty/discussions/12108 implemented
similarly to https://github.com/ghostty-org/ghostty/pull/8254 to allow
middle click + TrackPoint scrolling on MacOS. `primary-paste` naming
comes from `gtk_enable_primary_paste`.

The following configuration values for `middle-click-action` are
provided:
- `primary-paste` - Paste from the selection (or system) clipboard per
`copy-on-select`.
- `ignore` - Do nothing, ignore the middle click.

Tested locally on macOS with Zig 0.15.2 using `zig build
-Doptimize=ReleaseFast`.

Thank you!
2026-04-27 09:29:29 -07:00
Mitchell Hashimoto 0b56ae2cc7
gtk: fix quick terminal breaking when manually toggled off while auto-hide is enabled (#12471)
Fixes quick terminal breaking when auto-hide is enabled and quick
terminal is manually toggled off (#11679).

`quick-terminal-autohide` is implemented by the `Window.propIsActive`
function in `apprt/gtk/class/window.zig` which calls
`Window.toggleVisibility` when the quick terminal window becomes
inactive (loses focus). However `Window.propIsActive` is also triggered
when you manually hide the quick terminal because hiding it causes the
window to become inactive. Normally that should just toggle the quick
terminal off and immediately back on, but there is also a re-entrancy
issue. Manually toggling off the terminal causes the
`Application.toggleQuickTerminal` (in `apprt/gtk/class/application.zig`)
to run which sets off the call chain `Window.toggleVisibility ->
gtk_widget_set_visible -> ... GTK signal/event handling ... ->
Window.propIsActive -> Window.toggleVisibility ->
gtk_widget_set_visible`.
The nested calls to `gtk_widget_set_visible` cause the GTK window state
to become corrupted. The window is marked visible, but is not actually
visible or just shows a placeholder. What exactly happens depends on the
compositor and how it handles moving window focus.

Reproduced the bug on KDE and hyprland and verified the fix on both.

### Changes

`apprt/gtk/class/window.zig`: added check to `Window.propIsActive` to
only toggle quick-terminal if it is inactive **and** visible.

### AI Disclosure

Found the bug without AI using "printf debugging" then traced it through
GTK with valgrind. Used GPT5.4 in setting up valgrind and researching
how signals/events move through GTK internally.
2026-04-27 09:26:24 -07:00
Mitchell Hashimoto 576d07ffc1
macOS: update tests and add test plan (#12473)
This updates UI tests and adds a test plan on disk, so we can change the
configuration to different ones with the host app.

If you changed the icon in regular ghostty config file, the tests can
only be run once, since the signature is changed after changing the
icon. Adding an on-disk test plan helps us to better control the
environment for the tests.
2026-04-27 09:25:51 -07:00
Mitchell Hashimoto 1ed22a5210
renderer: fix preedit range width (#12479)
Related to #12466

`Preedit.range()` returns an inclusive range, but the end position was
calculated as `start + w`. For wide preedit text, this covers one extra
cell.

In Debug builds, Korean IME composition between existing Hangul
characters can panic with:
`index out of bounds: index 2, len 2`

I reproduced this reliably when there are two Hangul characters to the
right of the cursor. For example, type `가나다`, move the cursor between
`가` and `나`, then start a new Korean IME composition. With the old range
calculation, the renderer skips the first wide character plus the head
cell of the next wide character, then resumes on that character's spacer
tail.

This changes the inclusive end to `start + (w - 1)` and adds focused
tests for narrow, wide, and right-edge preedit ranges.

This does not fully fix the visual behavior reported in #12466. The
adjacent character can still disappear during composition, so this PR
only fixes the crash side of the problem.
2026-04-27 09:24:55 -07:00
Mitchell Hashimoto c19ce03b3e
fix: update Se terminfo entry to reset cursor to configured default (#12487)
## Problem

Current `Se` sequence (reset cursor style) is `\E[2 q`, which always
sets steady block, regardless of user config.

## Solution

Update sequence to `\E[0 q`, which sets the cursor style to the user
configured default cursor.

fix https://github.com/ghostty-org/ghostty/issues/12482
Helps with neovim issue: https://github.com/neovim/neovim/issues/38987

## AI Disclosure

I didn't use AI for this, haha. Unless you count random questions to
learn about terminfo beforehand, but I relied on [legit
resources](https://invisible-island.net/xterm/terminfo.html) for real
info. It says:

>  Se resets the cursor style to the terminal power-on default.

I think the useful interpretation is to set the user configured default.
2026-04-27 09:23:51 -07:00
Mitchell Hashimoto 5031973623
input: remove translated in capi (#12490)
Follow up for a3462dd2bd

<img width="884" height="255" alt="image"
src="https://github.com/user-attachments/assets/da4e4dd5-e645-40ed-8e9c-0ed8c9aee1c4"
/>
2026-04-27 09:23:25 -07:00
Lukas 971753074b
input: remove translated in capi
Follow up for a3462dd2bd
2026-04-27 13:39:51 +02:00
Kyle Sower 6c68650920 fix: update Se terminfo entry to reset cursor to configured default 2026-04-26 22:31:01 -05:00
ghostty-vouch[bot] 8769d32202
Update VOUCHED list (#12485)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12484#discussioncomment-16723661)
from @jcollie.

Vouch: @kylesower

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-27 03:16:59 +00:00
dobbylee ac67a6160c renderer: fix preedit range width 2026-04-27 01:17:43 +09:00
Andrei Lebedev 12ac19939c
feat: add middle-click action configuration 2026-04-27 01:27:22 +10:00
Lukas df365baf18
test: add test plan and override default config when running tests 2026-04-26 14:49:20 +02:00
Lukas a7eaecf929
test: always use temporary config when running ui tests 2026-04-26 13:53:36 +02:00
Lukas b66258806e
test: only change themes in theme tests 2026-04-26 13:53:36 +02:00
Mitchell Hashimoto c74f6d56d1
os: use GetTempPathW for allocTmpDir on Windows (#12469)
`allocTmpDir` previously read `%TMP%` via `getenvW` and returned `null`
if the variable wasn't set, requiring each caller to to deal with the
nullable. Unfortunately, there isn't a platform-neutral default value
that makes sense for those cases (i.e. `/tmp` is POSIX-y).

We now use `GetTempPathW` on Windows, which is the official way to get
this directory: `TMP` → `TEMP` → `USERPROFILE` → `GetWindowsDirectoryW`.

With a real system call behind it, the function no longer needs to be
nullable: the only remaining failure modes are OOM (propagated) and the
syscall itself failing or returning data we can't decode. In those later
cases, we use `C:\Windows\Temp` as a fallback, similar to how we use
`/tmp` in the POSIX case.

The Windows path always allocates so it still must be paired with
`freeTmpDir`, which matches the existing contract.

---

*AI Disclosure:* I verified the Windows path using Claude and Zig's
cross-compilation capabilities because I don't have a Windows
environment in which to test this. I do fully understand the code based
on my prior life as a Windows game developer though.
2026-04-25 20:49:54 -07:00
Mitchell Hashimoto 278041c4bc
flatpak: terminate session if Ghostty disconnects from bus (#12427)
This makes sure that if Ghostty crashes, commands spawned are also
terminated automatically by the Flatpak Session Helper.

The few crashes I got left a lot of background processes, some of them
pretty heavy and took awhile to be figured out.
2026-04-25 20:49:33 -07:00
Jon Parise 8b90efd913 os: use GetTempPathW for allocTmpDir on Windows
`allocTmpDir` previously read `%TMP%` via `getenvW` and returned `null`
if the variable wasn't set, requiring each caller to to deal with the
nullable. Unfortunately, there isn't a platform-neutral default value
that makes sense for those cases (i.e. `/tmp` is POSIX-y).

We now use `GetTempPathW` on Windows, which is the official way to get
this directory: `TMP` → `TEMP` → `USERPROFILE` → `GetWindowsDirectoryW`.

With a real system call behind it, the function no longer needs to be
nullable: the only remaining failure modes are OOM (propagated) and the
syscall itself failing or returning data we can't decode. In those later
cases, we use `C:\Windows\Temp` as a fallback, similar to how we use
`/tmp` in the POSIX case.

The Windows path always allocates so it still must be paired with
`freeTmpDir`, which matches the existing contract.
2026-04-25 21:44:37 -04:00
Leorize 8b8f7136d0
flatpak: don't assume c_uint to be u32
Thanks pluie for the pointer.
2026-04-25 17:04:26 -07:00
Mitchell Hashimoto 67b5783bdd
os: RANDOM_BASENAME_LEN -> random_basename_len (#12467) 2026-04-25 13:34:28 -07:00
Jon Parise 13ada38ac4 os: RANDOM_BASENAME_LEN -> random_basename_len 2026-04-25 16:29:25 -04:00
Mitchell Hashimoto e9ca0f8c9a
core: Acquire renderer state mutex before calling processLinks (#12463)
Holding the renderer state mutex is a documented precondition of
`processLinks`, but `mouseButtonCallback` previously called the function
without the mutex.

This creates a race with the I/O thread's `processOutput`, which can
prune scrollback pages while `processLinks` is reading them, resulting
in a use-after-free segfault. See
https://github.com/ghostty-org/ghostty/discussions/12409 (Linux: crash
while selecting text).


57b5e1e250/src/Surface.zig (L4354-L4355)


57b5e1e250/src/Surface.zig (L3822-L3824)

995e4e375 (os: open) changed the body of `processLinks` to be
non-trivial and documented the precondition, but the lock was not held
at the call site.
2026-04-25 13:21:38 -07:00
Mitchell Hashimoto 0e0bcafed5
macOS: remove manual invalidateRestorableState() (#12464)
This should be safe to delete now after #12461.

I tested saving 27 tabs, 4 with 2 splits,
`TerminalRestorable.encode(with:` finished successfully.

And I check the breakpoints when the Sparkle sends
`-[NSRunningApplication treminate]`. The call stack at `-[NSResponder
invalidateRestorableState]` is pretty much the same as quitting via
`cmd+q`.
2026-04-25 13:16:08 -07:00
Mitchell Hashimoto aedf39f3bd
macOS: support migrations when restoring window state (#12461)
First two commits fix the issue when upgrading from 1.2.x to 1.3.x.
(#11304)

> To double check if this pr really fixes the issue, you can either
archive a release build, sign with the same profile, and override
manually.
> 
> Or you can find the `savedState` files (located in `~/Library/Daemon\
Containers/<uuid>`), can copy them the local build dir (which is what I
did), and run the debug build.

Following commits add tests for migrations and some logs.

**Currently the minimum version is set to 1.2.x**, since there's a lot
changes comparing to 1.1.x. It will be difficult to restore
`Ghostty.SplitNode` -> `SplitTree<Ghostty.SurfaceView>` without
introducing a lot of checks.
2026-04-25 13:15:50 -07:00
Mitchell Hashimoto 8e1dfbcf3e
os: add randomTmpPath for allocating temp paths (#12465)
Factor TempDir's name generation into a reusable `randomBasename` (16
random bytes, url-safe base64) and add `randomTmpPath` on top, which
composes `allocTmpDir` + `randomBasename` into a single allocated path
in the form `{TMPDIR}/{prefix}{random}` (`mktemp(1)`-ish).

This is convenient for callers who want a unique path under TMPDIR (for
a temporary file, socket, etc.) without having to think about basename
buffer sizing or path joining.

Also, use `std.base64.url_safe_no_pad.Encoder` instead of the custom
base64 alphabet, which is exactly equivalent.
2026-04-25 13:14:30 -07:00
Jon Parise c9d2285f63 os: add randomTmpPath for allocating temp paths
Factor TempDir's name generation into a reusable `randomBasename` (16
random bytes, url-safe base64) and add `randomTmpPath` on top, which
composes `allocTmpDir` + `randomBasename` into a single allocated path
in the form `{TMPDIR}/{prefix}{random}` (mktemp(1)-ish).

This is convenient for callers who want a unique path under TMPDIR (for
a temporary file, socket, etc.) without having to think about basename
buffer sizing or path joining.

Also, use `std.base64.url_safe_no_pad.Encoder` instead of the custom
base64 alphabet, which is exactly equivalent.
2026-04-25 15:52:40 -04:00
Lukas 385376185c
macOS: remove manual invalidateRestorableState() 2026-04-25 21:25:38 +02:00
Lukas 231f6f4c75
macOS: move the restoration logs 2026-04-25 21:06:20 +02:00
Lukas 72c03e7fb8
macOS: add window restoration tests 2026-04-25 21:06:20 +02:00
Lukas bfe07bb99e
macOS: add InternalState to cover migrations 2026-04-25 20:25:17 +02:00
Lukas 5b89671d51
macOS: make terminal restorable state compatible with 1.2.3(v5) 2026-04-25 20:22:59 +02:00
Lukas 8ebf4f70e5
macOS: make tab color optional 2026-04-25 20:09:55 +02:00
Mitchell Hashimoto b613ffcfd8
surface: respect semantic prompt boundaries for links (#12435)
Link detection currently expands the clicked location to a full line
before running the configured regexes. When semantic prompt markers are
present, this can cause prompt text and neighboring content to be
matched together even though they are distinct semantic regions.

Use semantic prompt boundaries when selecting the text to inspect for
link matching. This keeps prompt text separate from the content beside
it and avoids folding prompt text into double-click link/path selection.

Add a regression test that models a prompt and command on the same line
and verifies the prompt region and input region remain separate.

----

this is a fix for the issue users reported in
https://github.com/ghostty-org/ghostty/discussions/11415

**disclaimer**: I used codex addon within Cursor to research this
bug/regression and find a proper fix for it.
2026-04-25 10:32:15 -07:00
Vasyl Zuziak c4a671ba5a fix: remove test as has been suggested in comment 2026-04-25 19:26:22 +02:00
Mitchell Hashimoto c5c3cf16ba
feat: add GTK keybinds (matching the idiomatic Linux convention used by Firefox, GNOME Terminal, and VSCode) for move_tab (#12458)
> Re-submitting #11857, which was auto-closed pre-vouch. I'm now in the
vouched list.

## Summary

Adds default keybinds for `move_tab` on GTK/Linux, matching the
idiomatic Linux convention used by Firefox, GNOME Terminal, and VSCode:

- **`Ctrl+Shift+PageUp`** → `move_tab:-1` (move tab left)
- **`Ctrl+Shift+PageDown`** → `move_tab:1` (move tab right)

To free these keys, `jump_to_prompt` is reassigned to `Ctrl+Shift+Arrow
Up/Down`, which:
- Mirrors the macOS default (`Cmd+Shift+Arrow Up/Down`)
- Is currently unbound on GTK
- Maintains directional consistency (up = previous, down = next)

The new `move_tab` bindings use `putFlags` with `performable: true` to
match the pattern used by other tab actions (`previous_tab`,
`next_tab`).

Closes #4998

## Changes
- `src/config/Config.zig`: Reassign `jump_to_prompt` from
`Ctrl+Shift+PageUp/PageDown` to `Ctrl+Shift+Arrow Up/Down` (GTK only)
- `src/config/Config.zig`: Add `move_tab` default keybinds as
`Ctrl+Shift+PageUp/PageDown` (GTK only)

## Test plan
- [ ] Build on Linux/GTK: `zig build`
- [ ] Verify `Ctrl+Shift+PageUp` moves current tab left
- [ ] Verify `Ctrl+Shift+PageDown` moves current tab right
- [ ] Verify `Ctrl+Shift+Arrow Up` jumps to previous prompt
- [ ] Verify `Ctrl+Shift+Arrow Down` jumps to next prompt
- [ ] Verify `Ctrl+PageUp/PageDown` still switches tabs (unchanged)
- [ ] Verify macOS keybinds are unaffected
2026-04-25 10:10:33 -07:00
ghostty-vouch[bot] c9ba2b2afa
Update VOUCHED list (#12457)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11628#discussioncomment-16712930)
from @mitchellh.

Denounce: @4RH1T3CT0R7

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:54:04 +00:00
Enzo William 14c06312d5 feat: add default GTK keybinds for move_tab
Reassign jump_to_prompt from Ctrl+Shift+PageUp/PageDown to
Ctrl+Shift+Arrow Up/Down on GTK, freeing the idiomatic Linux
keybinds (Ctrl+Shift+PageUp/PageDown) for move_tab.

This matches the tab-moving keybinds used by Firefox, GNOME Terminal,
and VSCode. The new jump_to_prompt binding mirrors the macOS pattern
(Cmd+Shift+Arrow Up/Down).

Closes #4998

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-25 13:53:37 -03:00
ghostty-vouch[bot] 4d1bb9efe4
Update VOUCHED list (#12456)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11685#discussioncomment-16712917)
from @mitchellh.

Denounce: @enkr1

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:52:41 +00:00
Mitchell Hashimoto df4f981592
Fix Korean IME committed text handling for arrow keys (#12447)
Fixes #11461

- Send Korean IME committed text as a separate text-only key event when
arrow-key handling commits preedit text.
- Replay arrow navigation after the committed text is sent. Do not
replay plain Left Arrow to match Terminal.app behavior.
- Manually tested Arrow keys and Opt/Cmd+Arrow during Korean preedit on
macOS.
2026-04-25 09:47:37 -07:00
ghostty-vouch[bot] 03e08f0c89
Update VOUCHED list (#12455)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11795#discussioncomment-16712869)
from @mitchellh.

Vouch: @bch

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:46:35 +00:00
ghostty-vouch[bot] 5a3b0c9c49
Update VOUCHED list (#12454)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11858#discussioncomment-16712861)
from @mitchellh.

Vouch: @enzowilliam

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:45:31 +00:00
ghostty-vouch[bot] e0c71dd41b
Update VOUCHED list (#12453)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11882#discussioncomment-16712859)
from @mitchellh.

Vouch: @mpatankar6

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:45:08 +00:00
ghostty-vouch[bot] 0e707ba3f6
Update VOUCHED list (#12452)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11975#discussioncomment-16712831)
from @mitchellh.

Vouch: @rightaditya

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:43:11 +00:00
ghostty-vouch[bot] 51590ad7f1
Update VOUCHED list (#12451)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11993#discussioncomment-16712826)
from @mitchellh.

Vouch: @VoidNV

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:42:24 +00:00
Mitchell Hashimoto 69452b5c6f
Sync middle-click paste with copy-on-select (#12443)
Implements the behavior from #9788.

Today, middle-click paste always reads from the selection clipboard (or
the
system clipboard on platforms without a selection clipboard). With this
change
it follows `copy-on-select`:

- `true`: selection clipboard (unchanged)
- `clipboard`: system clipboard
- `false`: selection clipboard (also unchanged, preserves traditional
X11
  middle-click behavior)

The idea is symmetry: if `copy-on-select = clipboard` writes selections
to the
system clipboard, middle-click should come back from there too.

Also updated the config doc comment, which previously claimed
middle-click
"will always use the selection clipboard".

### Testing

`zig build test` passes locally (macOS, Zig 0.15.2).

Built and runtime-tested via the fork's CI:
https://github.com/007hacky007/ghostty/actions/runs/24707475544 - I'm
running the resulting binary daily and the three `copy-on-select` modes
behave as described above.
2026-04-25 09:39:12 -07:00
Mitchell Hashimoto 2dee1f1a3f
Update VOUCHED list (#12445)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12263#discussioncomment-16712767)
from @mitchellh.

Vouch: @thoutbeckers
2026-04-25 09:36:41 -07:00
ghostty-vouch[bot] ee81a6e1c6
Update VOUCHED list (#12450)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12108#discussioncomment-16712799)
from @mitchellh.

Vouch: @lebdron

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:36:12 +00:00
ghostty-vouch[bot] 4c046efbb1
Update VOUCHED list (#12449)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12141#discussioncomment-16712795)
from @mitchellh.

Vouch: @AkimioJR

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:35:39 +00:00
ghostty-vouch[bot] e0d0fbe0ad
Update VOUCHED list (#12448)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12169#discussioncomment-16712790)
from @mitchellh.

Vouch: @knu

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:34:38 +00:00
ghostty-vouch[bot] 8c3db43c86
Update VOUCHED list (#12446)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12272#discussioncomment-16712769)
from @mitchellh.

Vouch: @dkinzler

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:31:04 +00:00
github-actions[bot] e72774f2ab Update VOUCHED list
https://github.com/ghostty-org/ghostty/discussions/12263#discussioncomment-DC_kwDOHFhdAs4A_wQ_
2026-04-25 16:30:38 +00:00
ghostty-vouch[bot] fc7a064e80
Update VOUCHED list (#12444)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12305#discussioncomment-16712760)
from @mitchellh.

Vouch: @aaron-ang

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:29:37 +00:00
ghostty-vouch[bot] 119f3875d4
Update VOUCHED list (#12442)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12435#issuecomment-4320055303)
from @mitchellh.

Vouch: @ZuBB

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:26:24 +00:00
ghostty-vouch[bot] 667d467e24
Update VOUCHED list (#12441)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11987#discussioncomment-16712733)
from @mitchellh.

Vouch: @nouritsu

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:25:26 +00:00
ghostty-vouch[bot] c21ba8d826
Update VOUCHED list (#12440)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11632#discussioncomment-16712730)
from @mitchellh.

Vouch: @ajiblock

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:24:52 +00:00
Mitchell Hashimoto 8e2a13cb60
gtk/SurfaceScrolledWindow: wrap root child with another Adw.Bin (#12426)
Due to a known Gtk issue, the scrolled_window at the root of the
template is free-ed twice on dispose. This causes crashes when used with
GNOME 49 platform (Gtk 4.20, libadwaita 1.8.5).

Workaround this issue by wrapping the root child in another Adw.Bin,
similar to widgets like ResizeOverlay.

LLM was used to perform discovery against a manually recorded Valgrind
trace, and helped tracking down known fixes for this problem. The
comment in code was taken from another instance in the repository.

Fixes https://github.com/ghostty-org/ghostty/discussions/12306

Assisted-by: OpenAI GPT-5.4
2026-04-25 09:22:59 -07:00
ghostty-vouch[bot] b3d4f51ca7
Update VOUCHED list (#12439)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12347#discussioncomment-16712718)
from @mitchellh.

Vouch: @rjwittams

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:22:38 +00:00
ghostty-vouch[bot] 74045cc5d8
Update VOUCHED list (#12438)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12354#discussioncomment-16712711)
from @mitchellh.

Vouch: @007hacky007

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:21:57 +00:00
ghostty-vouch[bot] 98fb58b326
Update VOUCHED list (#12437)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12295#discussioncomment-16712704)
from @mitchellh.

Vouch: @dobbylee

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 16:20:20 +00:00
Leorize 560b7ba8e8 gtk/SurfaceScrolledWindow: wrap root child with another Adw.Bin
Due to a known Gtk issue, the scrolled_window at the root of the
template is free-ed twice on dispose. This causes crashes when used with
GNOME 49 platform (Gtk 4.20, libadwaita 1.8.5).

Workaround this issue by wrapping the root child in another Adw.Bin,
similar to widgets like ResizeOverlay.

LLM was used to perform discovery against a manually recorded Valgrind
trace, and helped tracking down known fixes for this problem.

Fixes https://github.com/ghostty-org/ghostty/discussions/12306

Assisted-by: OpenAI GPT-5.4
2026-04-25 09:18:21 -07:00
Mitchell Hashimoto 98d14aa66b
flatpak: update runtime to GNOME 50 (#12428)
Notable dependency changes:

- GTK: `4.20.4` -> `4.22.2`
- libadwaita: `1.8.5` -> `1.9.0`
2026-04-25 09:15:20 -07:00
dobbylee fa141a7262 Fix Korean IME committed text handling for arrow keys 2026-04-26 00:59:45 +09:00
ghostty-vouch[bot] c47a8091f1
Update VOUCHED list (#12436)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12409#discussioncomment-16712208)
from @00-kat.

Vouch: @jmr

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 14:51:36 +00:00
Jesse Rosenstock 28f4676b5d core: Acquire renderer state mutex before calling processLinks
Holding the renderer state mutex is a documented precondition of
`processLinks`, but `mouseButtonCallback` previously called
the function without the mutex.

This creates a race with the I/O thread's `processOutput`, which can
prune scrollback pages while `processLinks` is reading them, resulting
in a use-after-free segfault.  See
https://github.com/ghostty-org/ghostty/discussions/12409 (Linux: crash
while selecting text).

57b5e1e250/src/Surface.zig (L4354-L4355)

57b5e1e250/src/Surface.zig (L3822-L3824)

995e4e375 (os: open) changed the body of `processLinks` to be
non-trivial and documented the precondition, but the lock was not held
at the call site.
2026-04-25 16:36:45 +02:00
Vasyl Zuziak 85dc4b1842 surface: respect semantic prompt boundaries for links
Link detection currently expands the clicked location to a full line
before running the configured regexes. When semantic prompt markers
are present, this can cause prompt text and neighboring content to be
matched together even though they are distinct semantic regions.

Use semantic prompt boundaries when selecting the text to inspect for
link matching. This keeps prompt text separate from the content beside
it and avoids folding prompt text into double-click link/path
selection.

Add a regression test that models a prompt and command on the same
line and verifies the prompt region and input region remain separate.
2026-04-25 15:46:25 +02:00
Leorize 6fb86a819e
flatpak: update runtime to GNOME 50 2026-04-25 00:17:39 -07:00
ghostty-vouch[bot] 57b5e1e250
Update VOUCHED list (#12425)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12308#discussioncomment-16709130)
from @jcollie.

Vouch: @alaviss

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-25 05:45:32 +00:00
Mitchell Hashimoto 4ceeba4851
config: use Config to check key binding instead of App (#12415)
Previously `ghostty_app_key_is_binding` (unlike Surface) is just using
`config.keybind` to check whether a KeyEvent is in the set or not.

After this, I can add unit tests for keybinding more easily with dummy
configs.

I didn't find any usages of this in GTK, so it shouldn't affect
anything. ci will see if this is the case:)
2026-04-24 14:51:22 -07:00
Mitchell Hashimoto d35f02d83c
build: respect config.emit_xcframework for building libghostty-vt.xcframework on Darwin (#12267)
This fixes a hardcoded build issue on macOS where Zig unconditionally
forces xcodebuild -create-xcframework to run during compilation, even
when the caller explicitly specifies that they only want the raw
standard C objects/headers (-Demit-lib-vt).
2026-04-24 13:48:51 -07:00
Mitchell Hashimoto 5f892b691b
ci: fix 2026-04-24 13:39:45 -07:00
Mitchell Hashimoto 33fc2aac97
cleanups 2026-04-24 13:22:49 -07:00
0xDVC 44a2d8740a build: gate lib-vt xcframework on emit-xcframework with xcodebuild detection 2026-04-24 13:21:43 -07:00
0xDVC caad13e232 chore(fmt): zig fmt build.zig to pass test 2026-04-24 13:21:43 -07:00
N E I L O H E N E 4e2e765fd4 Merge branch 'main' into fix/xcframework-macos-dependency 2026-04-24 13:21:43 -07:00
0xDVC 38e8e54f98 build: make libghostty-vt xcframework emission explicit via -Demit-lib-vt-xcframework 2026-04-24 13:21:43 -07:00
0xDVC 4204dec94a build: respect config.emit_xcframework for building libghostty-vt.xcframework on Darwin
This fixes a hardcoded build issue on macOS where Zig unconditionally forces xcodebuild -create-xcframework to run during compilation, even when the caller explicitly specifies that they only want the raw standard C objects/headers (-Demit-lib-vt).

The Bug:
Around line 155 in build.zig, the libghostty-vt xcframework was being packaged unconditionally for Darwin builds. This caused developers (and wrappers like go-libghostty) attempting to natively build the vt library locally using only the minimal macOS Command Line Tools to experience an immediate crash, as xcodebuild -create-xcframework strictly demands a full Xcode application installation.

The Fix:
Guarded the GhosttyLibVt xcframework creation step with config.emit_xcframework. Because src/build/Config.zig intuitively forces emit_xcframework to default to false whenever emit_lib_vt is invoked, this structurally allows lightweight macOS builds to safely skip the xcodebuild invocation while still correctly compiling the standard .a object library files.
2026-04-24 13:21:43 -07:00
Mitchell Hashimoto 2ed382a155
libghostty: enable cross-compiling macOS from Linux/Windows (#12417)
This allows libghostty-vt to be cross-compiled for macOS from non-macOS
platforms. I've updated pkg/apple-sdk to fallback to Zig's embedded
macOS headers if the macOS SDK is not found. Additionally,
CombineArchivesStep has been updated to use Linux tooling on Linux. CI
updated to test this.
2026-04-24 13:19:11 -07:00
Mitchell Hashimoto 6b69ea0517
libghostty: enable cross-compiling macOS from Linux/Windows
This allows libghostty-vt to be cross-compiled for macOS from non-macOS
platforms. I've updated pkg/apple-sdk to fallback to Zig's embedded
macOS headers if the macOS SDK is not found.

Additionally, CombineArchivesStep has been updated to use Linux
tooling on Linux.
2026-04-24 13:04:38 -07:00
ghostty-vouch[bot] eee1018988
Update VOUCHED list (#12418)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11461#issuecomment-4315618982)
from @jcollie.

Vouch: @seyoungjeong

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-24 19:05:30 +00:00
Lukas 7c91cef28d
config: use Config to check key binding instead of App
Previously `ghostty_app_key_is_binding` (unlike Surface) is just using `config.keybind` to check whether a KeyEvent is in the set or not.

After this, I can add unit tests for keybinding more easily, with dummy configs.
2026-04-24 18:26:56 +02:00
trag1c 48ccec182a
ci: fix vouch-check-issue to checkout the template file (#12412) 2026-04-24 14:08:53 +02:00
trag1c 2f067e14f1
ci: fix vouch-check-issue to checkout the template file 2026-04-24 13:48:06 +02:00
Mitchell Hashimoto b0d359cbbd
more zon2nix update for improved 0.16 compatibility (#12405) 2026-04-23 21:50:26 -07:00
Mitchell Hashimoto 5f43437576
pkg/highway: no libc requirement (#12402)
This uses a custom fork Google Highway that removes all libc usage. For
most, it was logging and we can just remove it. For detection, we moved
this to an extern func implemented in Zig built using the Zig standard
library so we can avoid libc.

# Benchmark Results

All benchmarks use 50 MB pre-generated inputs (`ghostty-gen +utf8
--seed=42`)
built and run with `-Doptimize=ReleaseFast` on Apple Silicon
(aarch64-macos).

## Input Descriptions

| Input | Description |
|:------|:------------|
| ascii-only | 1-byte sequences only, printable ASCII |
| 2byte-only | 2-byte sequences only (Latin/Cyrillic/etc.) |
| 3byte-only | 3-byte sequences only (CJK/BMP) |
| 4byte-only | 4-byte sequences only (emoji/supplementary planes) |
| mixed-equal | Equal weight across all 4 lengths |
| mostly-ascii | ~80% ASCII, ~20% multibyte |
| cjk-heavy | ~80% 3-byte, ~20% other |
| 10pct-invalid | Equal-weight mix with 10% malformed sequences |

## Terminal Parser (byte-by-byte DFA, no SIMD)

| Input | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:------|----------:|---------:|---------:|---------:|
| ascii-only | 46.3 ± 0.8 | 45.4 | 48.1 | 1.00 |
| 2byte-only | 59.1 ± 1.2 | 57.8 | 62.7 | 1.28 ± 0.03 |
| 3byte-only | 65.4 ± 2.1 | 64.1 | 78.6 | 1.41 ± 0.05 |
| 4byte-only | 59.3 ± 1.3 | 57.2 | 63.5 | 1.28 ± 0.04 |
| mixed-equal | 180.7 ± 0.7 | 179.5 | 182.3 | 3.90 ± 0.07 |
| mostly-ascii | 59.3 ± 1.0 | 57.3 | 61.1 | 1.28 ± 0.03 |
| cjk-heavy | 142.4 ± 2.0 | 140.4 | 149.9 | 3.08 ± 0.07 |
| 10pct-invalid | 180.2 ± 1.5 | 178.4 | 184.9 | 3.89 ± 0.08 |

## Terminal Stream (SIMD UTF-8 decode + terminal handling)

| Input | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:------|----------:|---------:|---------:|---------:|
| ascii-only | 377.0 ± 8.7 | 357.1 | 386.4 | 2.42 ± 0.08 |
| 2byte-only | 664.5 ± 4.0 | 656.9 | 672.6 | 4.27 ± 0.11 |
| 3byte-only | 233.5 ± 0.9 | 231.1 | 234.8 | 1.50 ± 0.04 |
| 4byte-only | 155.5 ± 4.0 | 149.6 | 161.3 | 1.00 |
| mixed-equal | 467.0 ± 3.4 | 461.8 | 473.9 | 3.00 ± 0.08 |
| mostly-ascii | 470.8 ± 7.2 | 459.6 | 482.8 | 3.03 ± 0.09 |
| cjk-heavy | 338.4 ± 2.4 | 334.3 | 341.7 | 2.18 ± 0.06 |
| 10pct-invalid | 635.1 ± 3.5 | 630.5 | 640.8 | 4.08 ± 0.11 |

## Branch Comparison: `main` vs `fixed`

### Terminal Parser

| Input | main [ms] | fixed [ms] | Δ |
|:------|----------:|-----------:|:--|
| ascii-only | 46.9 ± 0.7 | 47.3 ± 0.9 | ~same |
| 2byte-only | 59.0 ± 0.5 | 59.1 ± 1.2 | ~same |
| 3byte-only | 65.9 ± 2.1 | 65.4 ± 2.1 | ~same |
| 4byte-only | 58.8 ± 0.5 | 59.3 ± 1.3 | ~same |
| mixed-equal | 182.5 ± 0.9 | 180.7 ± 0.7 | fixed 1% faster |
| mostly-ascii | 59.0 ± 0.5 | 59.3 ± 1.0 | ~same |
| cjk-heavy | 144.1 ± 1.7 | 142.4 ± 2.0 | ~same |
| 10pct-invalid | 181.7 ± 1.0 | 180.2 ± 1.5 | ~same |

### Terminal Stream

| Input | main [ms] | fixed [ms] | Δ |
|:------|----------:|-----------:|:--|
| ascii-only | 388.4 ± 8.8 | 383.1 ± 7.6 | ~same |
| 2byte-only | 687.7 ± 4.8 | 672.9 ± 2.6 | fixed 2% faster |
| 3byte-only | 235.5 ± 1.2 | 236.3 ± 2.5 | ~same |
| 4byte-only | 166.2 ± 2.9 | 159.9 ± 3.1 | fixed 4% faster |
| mixed-equal | 481.8 ± 3.3 | 480.7 ± 6.3 | ~same |
| mostly-ascii | 483.8 ± 6.7 | 475.9 ± 4.3 | ~same |
| cjk-heavy | 341.7 ± 3.1 | 341.6 ± 2.0 | ~same |
| 10pct-invalid | 647.6 ± 3.3 | 640.4 ± 3.4 | ~same |

No regressions in either benchmark. Fixed branch is equal or slightly
faster
across all inputs.

## Reproduction

```bash
# Generate inputs (do NOT regenerate when comparing branches)
for profile in \
  "--weight-one=1 --weight-two=0 --weight-three=0 --weight-four=0 --ascii-printable-only=true" \
  "--weight-one=0 --weight-two=1 --weight-three=0 --weight-four=0" \
  "--weight-one=0 --weight-two=0 --weight-three=1 --weight-four=0" \
  "--weight-one=0 --weight-two=0 --weight-three=0 --weight-four=1" \
  "--weight-one=1 --weight-two=1 --weight-three=1 --weight-four=1" \
  "--weight-one=10 --weight-two=1 --weight-three=1 --weight-four=0.5 --ascii-printable-only=true" \
  "--weight-one=1 --weight-two=0.5 --weight-three=10 --weight-four=0.5" \
  "--weight-one=1 --weight-two=1 --weight-three=1 --weight-four=1 --invalid-rate=0.1"; do
  ghostty-gen +utf8 --seed=42 $profile | head -c 50000000 > /tmp/ghostty-bench-data/<name>.dat
done

# Build
zig build -Demit-bench -Doptimize=ReleaseFast -Demit-macos-app=false

# Run
hyperfine --warmup 3 --min-runs 10 \
  './zig-out/bin/ghostty-bench +terminal-stream --data=<path>'
```
2026-04-23 21:50:10 -07:00
Mitchell Hashimoto bf3047b9b2
benchmark: isolate parser hot loop from code-layout shifts
Extract the tight per-byte parsing loop from TerminalParser.step into
a separate noinline function (parseAll). This eliminates a ~20%
benchmark regression that appeared after the highway vendor changes
despite zero changes to the parser source code.

The root cause: the parser benchmark processes 50 MB of input through
a byte-at-a-time DFA loop that is highly sensitive to instruction
cache-line placement on Apple Silicon. The M-series cores fetch
aligned 16-byte blocks; when the loop head lands near the end of a
64-byte cache line (offset 60), only one instruction fits in the
first fetch versus four when aligned to offset 48. This causes ~29%
more cycles for identical instruction counts.

Previously the loop was inlined into the large step() function, so
any code change anywhere in the binary (like the highway vendor
restructuring) could shift the loop across a cache-line boundary.
By making parseAll noinline, the loop gets its own function placement
that is stable regardless of surrounding code changes.
2026-04-23 21:36:39 -07:00
Mitchell Hashimoto 00dfd67bee
pkg/highway: replace resolveTargetQuery with direct CPU detection
The previous runtime_detect.zig called std.zig.system.resolveTargetQuery
which pulled in the entire Zig target/CPU model table infrastructure for
every architecture (~4,000 symbols, ~175 KB of data tables, ~130 KB of
code). This bloated the binary by ~500 KB and shifted code layout enough
to cause a measurable icache/branch-predictor regression in unrelated
hot paths like the terminal parser (~20% more cycles for identical
instruction counts).

Replace with minimal, direct CPU feature detection per architecture:
CPUID + XGETBV inline assembly on x86, sysctlbyname on Darwin AArch64,
and getauxval/prctl via std.os.linux (direct syscalls, no libc) on
Linux for AArch64, PPC, S390x, RISC-V, and LoongArch.

Split into per-architecture files under src/detect/ for
maintainability.
2026-04-23 21:23:12 -07:00
Mitchell Hashimoto 3c0b976d07
pkg/highway: requires libc headers 2026-04-23 20:48:25 -07:00
Jeffrey C. Ollie 055922faaa
more zon2nix update for improved 0.16 compatibility 2026-04-23 22:32:53 -05:00
Mitchell Hashimoto f3f9af6129
pkg/highway: vendor and modify to remain all libc usage 2026-04-23 20:28:43 -07:00
Mitchell Hashimoto bdb164a6e5
pkg/highway: expand detection to all platforms not just darwin 2026-04-23 15:28:59 -07:00
Mitchell Hashimoto c642e3104b
pkg/highway: Darwin builds don't rely on Apple headers
This uses a custom fork of `hwy/targtes.cpp` that uses an extern
function written in Zig to use Zig's standard CPU detection to avoid
a dependency on Apple SDK headers.

This is on the path to removing Apple SDK requirements to build 
libghostty-vt, but will require a lot more work outside of this. The goal 
is to get this out of our external dependencies first and then we can
work on removing the internal side.
2026-04-23 15:05:38 -07:00
Mitchell Hashimoto 2f1a30ddb0
font: add Windows font discovery backend (#12386)
Adds a FreeType-based `Discover` implementation for Windows. It walks
the system font directory (`%SYSTEMROOT%\Fonts`) and the per-user
directory (`%LOCALAPPDATA%\Microsoft\Windows\Fonts`), matches
descriptors by FreeType `family_name` (falling back to the SFNT name
table), and, when a codepoint is in the descriptor, filters on CMap
coverage.

Wired up as a new `.freetype_windows` backend which `Backend.default()`
now returns on Windows. Existing freetype-only paths are untouched and
no other platform is affected; cross-platform switches were extended to
handle the new enum value the same way they handle `.freetype`.

With this in place, the standard code paths (`+list-fonts`,
`SharedGridSet` font-family lookup, `CodepointResolver` fallback) work
on Windows without any `os.tag == .windows` branches in the caller.

Verified by the `build-libghostty-windows-gnu` CI job. No runtime binary
ships yet on Windows (no apprt), but this is a drop-in for the discovery
API that the Win32 apprt (and the revisited `+list-fonts` PR #12384)
will use. Once this lands, #12384 can be closed and `+list-fonts` will
work on Windows through the ordinary discovery code path, which
addresses the review feedback that `+list-fonts` should only show fonts
the internal discovery can find.

---

AI usage disclosure: developed with Claude Code (Claude Opus 4.7).
Claude drafted the implementation based on my design direction -- I
picked the "add a Discover backend" shape over the ad-hoc approach in
the earlier `+list-fonts` PR. I reviewed each diff and validated it with
a Windows GNU-ABI smoke build before pushing.

Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
2026-04-23 10:45:50 -07:00
Mitchell Hashimoto 48db54d7ef
pkg/simdutf: upgrade to simdutf v9, off our fork for nolibcxx (#12399) 2026-04-23 10:31:31 -07:00
Mitchell Hashimoto c1b685bc62
Add code for validating OpenType GLYF table entries (#12375)
This code was motivated by the need for the glyph protocol handler
(#12352) to be able to validate the provided `glyf` payload, without
having to link freetype or anything (because libghostty-vt needs to be
static). As such it's written specifically to meet those needs, but in
such a way that it can be expanded if we find a need for more in-depth
inspection of `glyf`s in the future.
2026-04-23 09:52:39 -07:00
Mitchell Hashimoto e89cc0b34c
pkg/simdutf: upgrade to simdutf v9, off our fork for nolibcxx 2026-04-23 09:51:20 -07:00
Qwerasd 464c50457b font/opentype: accept header-only simple glyf entry 2026-04-23 12:41:14 -04:00
Yasuhiro Matsumoto 0343a4d98f
address review: update DeferredFace test discover callsites
Two more holdouts in DeferredFace.zig test helpers calling
Fontconfig.init / CoreText.init with no args; Nix test CI surfaced
them for the fontconfig path.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-24 01:40:01 +09:00
Mitchell Hashimoto bc90a51282
build: fat static archive and ubsan fix for external linkers (#12217)
## Summary

> [!IMPORTANT]
> Stacked on #12214. Review that first. (i am targeting `main` so here
you will see the full changeset, including 12214

Two changes that make the static libghostty archive consumable by
external linkers (MSVC link.exe, .NET NativeAOT, Rust, Go, etc.):

**Fat static archive on all platforms**

The static archive previously only bundled vendored deps on macOS (via
libtool). On Windows and Linux the archive contained only the
Zig-compiled code, requiring consumers to find and link freetype,
harfbuzz, glslang, spirv-cross, simdutf, oniguruma, etc. separately.

Now all platforms produce a single fat archive:
- macOS: libtool (unchanged)
- Windows: zig ar qcL --format=coff (MSVC's lib.exe can't read
Zig-produced GNU-format archives, so we use the bundled LLVM archiver)
- Linux: ar -M with MRI scripts (same approach as libghostty-vt)

**MSVC ubsan suppression for C deps**

Zig's ubsan runtime can't be bundled on Windows (LNK4229), leaving
__ubsan_handle_* symbols unresolved. freetype, glslang, spirv-cross, and
highway already suppress ubsan. This adds MSVC-conditional suppression
to seven more: harfbuzz, libpng, dcimgui, wuffs, oniguruma, zlib, and
stb.

Gated on abi == .msvc so ubsan coverage is preserved on Linux/macOS.

## Test plan

- [x] zig build produces a fat ghostty-static.lib (~230MB) with ~200
object files
- [x] MSVC's lib /LIST can read the archive
- [x] .NET NativeAOT consumer resolves all symbols (0 unresolved)
- [x] Linux/macOS builds unaffected (ubsan remains enabled)
2026-04-23 09:33:05 -07:00
Yasuhiro Matsumoto fe725b5da1
address review: update shaper test discover callsites
CI on Windows (MSVC) surfaced three remaining callers of the old
zero-arg `Discover.init()` in shaper test helpers that the earlier
commit missed. Pass `lib` to match the new signature.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-24 01:27:58 +09:00
Mitchell Hashimoto d6d7bdbee5
fuzz: fix macOS AFL toolchain and linker setup for macOS 26.4 (#12398)
* Unset the Nix compiler and linker environment in the fuzz dev shell so
AFL++ uses the system or Homebrew Apple toolchain directly.
* Force afl-cc to link with lld because the newer Apple linker asserts
on the custom sections emitted by AFL's LLVM instrumentation.
* Pin fuzz-libghostty to the host target so the build does not inherit
stray SDK targets from the environment.
2026-04-23 09:18:47 -07:00
Mitchell Hashimoto ae1dd5666d
fuzz: fix macOS AFL toolchain and linker setup for macOS 26.4
On macOS 26.4, AFL builds were picking up Nix compiler-wrapper
variables and Apple SDK target settings from the shell environment.
That caused afl-cc to drive the wrong linker and target configuration,
which broke even simple fuzz harness builds. Unset the Nix compiler and 
linker environment in the fuzz dev shell so AFL++ uses the system or 
Homebrew Apple toolchain directly. 

Also force afl-cc to link with lld because the newer Apple linker
asserts on the custom sections emitted by AFL's LLVM
instrumentation. Finally, pin fuzz-libghostty to the host target so the
build does not inherit stray SDK targets from the environment.
2026-04-23 09:06:12 -07:00
Mitchell Hashimoto 239b97eccc
termio: run Windows shell commands without a cmd.exe wrapper (#12389)
On Windows the configured shell was always executed as `cmd.exe /C
<shell>`. That inserts a cmd.exe even for simple values like `command =
wsl ~` or `command = pwsh -NoLogo`, producing two processes where one
would do.

Two concrete side effects:

An extra cmd.exe appears in every Windows terminal's process tree
(visible in Task Manager / process listings), two processes per surface
where only one is the user's shell.

cmd.exe state set by AutoRun (`HKCU\Software\Microsoft\Command
Processor\AutoRun`, used commonly for DOSKEY aliases or `cd` in
`init.cmd`) lives in the wrapping cmd process, not in the user's shell.
Since AutoRun state like DOSKEY aliases is per-process, the user's
aliases don't reach the shell they actually interact with.

Run the shell value directly instead. If it contains whitespace, split
on whitespace into argv. A bare `cmd.exe` is resolved via `%COMSPEC%`
(the documented path to the current command processor). Other bare
values are left to PATH resolution in `Command.startWindows` (#12387).

The simple whitespace split does not honor Windows CLI quoting rules;
users who need quoted arguments should use the direct command form,
which takes an argv array as-is. For the common case (`wsl ~`, `pwsh
-NoLogo`, `cmd.exe /k init.cmd`, etc.) this covers the shapes users
actually write today.

Also skips the termios focus timer on Windows in `focusGained`, since
Windows has no termios -- the callback was arming a timer whose tick did
nothing and just added noise.

---

AI usage disclosure: developed with Claude Code (Claude Opus 4.7).
Claude drafted the implementation based on my design direction -- I
picked which pieces belong in this PR (drop the cmd wrapper, use
`%COMSPEC%`, skip the termios focus timer) and which belong in sibling
PRs. I reviewed each diff and validated it with a Windows GNU-ABI smoke
build before pushing.

Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
2026-04-23 09:05:47 -07:00
Jon Parise 04accc001d
os: trim trailing path separators from tmpdir (#12397)
Because we generally read this value from an environment variable, we
the resulting value can include a trailing slash (as on macOS). This
results in less-friendly path operations for callers who are building
paths based on this value.

`std.fs.path.join()` handles trailing slashes just fine, but it's an
allocating API. For callers who just want to format a path, they have to
assume they need to include their own path separator.

We can make this friendlier by always trimming trailing path separators
from the environment variable values before returning the slice.

This behavior matches "higher-level" languages' standard libraries (I
checked Python, Node, Ruby, and Perl). Other "systems" languages (Go,
Rust) just return the system value as-is, like we were doing before.
2026-04-23 12:03:36 -04:00
Mitchell Hashimoto b34c62bf04
Command: let CreateProcessW resolve the program via PATH (#12387)
Windows users often set bare command names in the Ghostty config
(`command = bash`) or pass them via `-e`, matching how they would on
Linux/macOS. Today that fails because `CreateProcessW` does not do
program search for `lpApplicationName` on its own.

Thanks to @qwerasd205 for pointing out that passing `NULL` for
`lpApplicationName` is exactly how Windows docs say to get program
search for free. This PR does that: drop the explicit utf16 conversion
for `lpApplicationName`, pass `null`, and make sure the program name is
the first token of `lpCommandLine`. Windows then walks parent-app dir,
CWD, system dirs, and PATH (and appends `.exe` for extensionless names).
The child also sees its `argv[0]` exactly as we wrote it rather than a
resolved absolute path, which is less surprising.

Net change is +15 / -7 in `src/Command.zig`; no new helpers, no changes
outside that file. The earlier version of this PR (which added
PATH/PATHEXT handling in `internal_os.path.expand`) is obsoleted by this
approach and has been force-pushed away.

---

AI usage disclosure: developed with Claude Code (Claude Opus 4.7).
Claude drafted the implementation based on my direction after
@qwerasd205's review suggested the NULL-lpApplicationName approach. I
reviewed the diff, built and verified it on the Windows GNU-ABI target,
and am responsible for the code landing here.

Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
2026-04-23 08:44:23 -07:00
Jon Parise 1ae27f95b4 os: trim trailing path separators from tmpdir
Because we generally read this value from an environment variable, we
the resulting value can include a trailing slash (as on macOS). This
results in less-friendly path operations for callers who are building
paths based on this value.

`std.fs.path.join()` handles trailing slashes just fine, but it's an
allocating API. For callers who just want to format a path, they have to
assume they need to include their own path separator.

We can make this friendlier by always trimming trailing path separators
from the environment variable values before returning the slice.

This behavior matches "higher-level" languages' standard libraries (I
checked Python, Node, Ruby, and Perl). Other "systems" languages (Go,
Rust) just return the system value as-is, like we were doing before.
2026-04-23 11:31:37 -04:00
Yasuhiro Matsumoto 8c5b8ac3c0
address review: add unit tests for Windows execCommand paths
Per review feedback, cover the four Windows branches added in the
parent commit:

- bare `cmd.exe` resolves via `%COMSPEC%` (with documented fallback)
- bare non-cmd shell (`pwsh.exe`) is passed through unchanged
- shell value with arguments (`wsl ~`) is split on whitespace
- direct command is passed through without modification

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 23:08:58 +09:00
Yasuhiro Matsumoto 5aef2541b0
address review: Discover.init takes a Library across all backends
Per review feedback, drop the `if (Discover == Windows)` comptime
branches in SharedGridSet and list_fonts by making every backend's
`init` take a Library and ignore it when unused. Call sites just do
`Discover.init(self.font_lib)` now.

Also adds a discovery test for the Windows backend that looks up
Arial and checks the returned face has the 'A' codepoint.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 23:06:21 +09:00
Mitchell Hashimoto 7629c4ba84
macOS: fix command parsing in NewTerminalIntent (#12392)
Fixes #12391, regression from #10765
2026-04-23 06:34:54 -07:00
Mitchell Hashimoto 70bd66c081
macOS: check `abnormal-command-exit-runtime` when process exits (#12393)
<img width="849" height="434" alt="image"
src="https://github.com/user-attachments/assets/81c89d8d-6f0a-4bb9-b942-6734ff616bf9"
/>
2026-04-23 06:34:08 -07:00
Lukas b0b23f53a7
macOS: check abnormal-command-exit-runtime when process exits
Signed-off-by: Lukas <134181853+bo2themax@users.noreply.github.com>
2026-04-23 11:35:51 +02:00
Lukas a8ed37a791
macOS: fix command parsing in NewTerminalIntent
Fixes #12391, regression from #10765

Signed-off-by: Lukas <134181853+bo2themax@users.noreply.github.com>
2026-04-23 11:35:34 +02:00
Yasuhiro Matsumoto c32e88c6a7
Command: let CreateProcessW resolve the program via PATH
Pass null for lpApplicationName and put the program as the first
token of lpCommandLine. Per the Windows docs, this makes
CreateProcessW perform the standard program search (parent-app dir,
CWD, system dirs, PATH) and append ".exe" when the name has no
extension.

So a bare command name like `wsl` or `pwsh` from the Ghostty config
now resolves without any PATH/PATHEXT handling on our side. The
child also sees its argv[0] exactly as written rather than replaced
with the resolved absolute path.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 14:40:13 +09:00
Yasuhiro Matsumoto fe2a909782
font/discovery: use %SYSTEMROOT%\Fonts instead of a hardcoded path
Resolve the system font directory from SYSTEMROOT rather than assuming
it lives on C:. If SYSTEMROOT is somehow unset we skip the system
directory instead of falling back to a literal drive letter.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 14:32:49 +09:00
Yasuhiro Matsumoto 61fce4d0a4
font: add Windows font discovery backend
Adds a FreeType-based Discover implementation for Windows that walks
the system (C:\Windows\Fonts) and per-user
(%LOCALAPPDATA%\Microsoft\Windows\Fonts) font directories, matching
descriptors via family_name / SFNT name table and optionally codepoint
presence.

Wired up as a new .freetype_windows backend which Backend.default() now
returns on Windows. Existing freetype-only paths are untouched.

With this in place, standard code paths -- +list-fonts, SharedGridSet
font-family lookup, CodepointResolver fallback -- work on Windows
without any os.tag == .windows branches in the caller.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 14:32:47 +09:00
Yasuhiro Matsumoto ef7ecbd3e5
termio: run Windows shell commands without a cmd.exe wrapper
On Windows the shell value was always executed as `cmd.exe /C <shell>`.
For even a simple `command = wsl ~` this spawned two processes (the
cmd wrapper and the user's actual shell) and had visible side effects:
an extra cmd.exe in the process tree, and cmd AutoRun state (DOSKEY
aliases, `cd` in init.cmd, etc.) running in the wrapper rather than
the user's shell, since AutoRun is per-process.

Run the shell value directly. If it contains whitespace, split on
whitespace into argv. Bare `cmd.exe` is resolved via %COMSPEC% which
is the documented path to the current command processor; other bare
values are left to PATH resolution in Command.startWindows.

The simple whitespace split does not honor Windows CLI quoting rules.
Users who need quoted arguments should use the direct command form.

Also skip the termios focus timer on Windows since Windows has no
termios; the focusGained callback was starting a timer whose callback
would then do nothing.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 14:31:06 +09:00
Alessandro De Blasis 08a2d9b224 build: share combineArchives and fix internal archive names
Extract CombineArchivesStep.zig so both GhosttyLib and GhosttyLibVt
use the same archive-combining logic. Uses libtool on Darwin and the
cross-platform combine_archives build tool elsewhere.

Renames the internal library's fat archive outputs from ghostty to
ghostty-internal, matching the pkg-config rename from PR 12214.
2026-04-23 05:47:28 +02:00
Alessandro De Blasis a10854654d build: disable ubsan in C deps for MSVC static linking
Zig's ubsan runtime cannot be bundled on Windows (LNK4229),
leaving __ubsan_handle_* symbols unresolved when the static
archive is consumed by an external linker like MSVC link.exe.

freetype, glslang, spirv-cross, and highway already suppress
ubsan unconditionally. Add MSVC-conditional suppression to the
seven C dependencies that were missing it: harfbuzz, libpng,
dcimgui, wuffs, oniguruma, zlib, and stb.

The fix is gated on abi == .msvc so ubsan coverage is preserved
on Linux and macOS where bundle_ubsan_rt works.
2026-04-23 05:23:15 +02:00
Alessandro De Blasis 94e638d084 build: produce fat static archive on all platforms
The static libghostty archive previously only bundled vendored
dependencies on macOS (via libtool). On Windows and Linux the
archive contained only the Zig-compiled code, leaving consumers
to discover and link freetype, harfbuzz, glslang, spirv-cross,
simdutf, oniguruma, and other vendored deps separately.

Now all platforms produce a single fat archive:
- macOS: libtool (unchanged)
- Windows: zig ar qcL --format=coff (LLVM archiver with the L
  flag to flatten nested archives; MSVC's lib.exe cannot read
  Zig-produced GNU-format archives)
- Linux: ar -M with MRI scripts (same as libghostty-vt)

This makes the static library self-contained for consumers like
.NET NativeAOT that link via the platform linker (MSVC link.exe)
and need all symbols resolved from a single archive.
2026-04-23 05:23:15 +02:00
Jeffrey C. Ollie e88c6c0991
ci: add GNU-ABI Windows library build job (#12383)
Adds a new CI job `build-libghostty-windows-gnu` that exercises the
GNU-ABI Windows library build path. The existing
`build-libghostty-vt-windows` job covers the MSVC ABI; with the recent
fixes (#12373 / #12381 / #12382) the GNU path is now viable, and this
job catches regressions before the upcoming Win32 apprt (discussion
#2563) starts to depend on it.

Named `build-libghostty-windows-gnu` rather than following the
`build-libghostty-vt-*` convention because this job also builds
`ghostty-internal.dll`, not just libghostty-vt. Happy to rename if you
prefer a different convention.

Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
2026-04-22 21:35:53 -05:00
Yasuhiro Matsumoto 8f49ed6c32
ci: add GNU-ABI Windows library build job
The existing `build-libghostty-vt-windows` job builds libghostty-vt
with the MSVC ABI. The Win32 apprt (discussion #2563) will target
the GNU ABI, so add a parallel job that exercises the GNU-ABI path
to catch bitrot.

The job runs `zig build -Dtarget=native-native-gnu -Dapp-runtime=none`
which produces ghostty-vt.dll and ghostty-internal.dll without
requiring a platform-specific apprt.
2026-04-23 11:05:44 +09:00
Jeffrey C. Ollie db210e4d7f
windows: disable C++ ubsan regardless of ABI (#12381)
Widens the existing `-fno-sanitize=undefined` gate from `abi == .msvc`
to `os.tag == .windows`. The same undefined `__ubsan_handle_*` link
errors from simdutf/highway also reproduce on Windows GNU ABI, and the
fix is identical.

Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
2026-04-22 20:55:13 -05:00
Jeffrey C. Ollie 1979b1c8d6
build: pass zig exe path to combine_archives (#12382)
`combine_archives` spawns `zig ar -M`, hard-coding the command name
`"zig"` and relying on the binary being on `PATH`. On Windows when the
build is driven by an absolute zig.exe path (common in CI and
Scoop/winget installs), this surfaces as `error: FileNotFound`.

Pass `b.graph.zig_exe` explicitly so the tool always uses the exact zig
binary driving the build, matching how other build tools in this repo
spawn zig subcommands.

Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
2026-04-22 20:54:27 -05:00
Jeffrey C. Ollie b526175782
build(deps): bump cachix/install-nix-action from 31.10.4 to 31.10.5 (#12380)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.10.4 to 31.10.5.
<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.10.5</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.34.5 -&gt; 2.34.6 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/274">cachix/install-nix-action#274</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.10.5">https://github.com/cachix/install-nix-action/compare/v31...v31.10.5</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ab739621df"><code>ab73962</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/274">#274</a>
from cachix/create-pull-request/patch</li>
<li><a
href="41e4d4a5ae"><code>41e4d4a</code></a>
nix: 2.34.5 -&gt; 2.34.6</li>
<li>See full diff in <a
href="616559265b...ab739621df">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.10.4&new-version=31.10.5)](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-04-22 20:32:49 -05:00
Yasuhiro Matsumoto 5c4ab6c0de
build: pass zig exe path to combine_archives
`combine_archives` spawns `zig ar -M` to combine static archives via
an MRI script. It hard-coded the command name `"zig"` and relied on
the binary being on `PATH`, which fails on Windows when the build is
driven by an absolute zig.exe path (common in CI and in Scoop/winget
installs where PATH isn't populated at build time). The failure
surfaces as `error: FileNotFound` from `Child.spawn`.

Pass `b.graph.zig_exe` as the first argument so the tool always uses
the exact zig binary that is driving the build, matching how other
build tools in this repo spawn zig subcommands.
2026-04-23 09:59:41 +09:00
Yasuhiro Matsumoto 83a3e5aba7
windows: disable C++ ubsan regardless of ABI
The existing `-fno-sanitize=undefined` flag was gated on `abi == .msvc`
to avoid undefined `__ubsan_handle_*` references from simdutf/highway.
The same linker error reproduces on Windows GNU ABI for the same
reason: the Zig-bundled libraries don't provide a matching UBSan
runtime for these C/C++ objects in our build configurations.

Widen the condition to `os.tag == .windows` so both MSVC and GNU
Windows targets skip ubsan for these C++ deps.
2026-04-23 09:59:12 +09:00
dependabot[bot] ce3c319ab1
build(deps): bump cachix/install-nix-action from 31.10.4 to 31.10.5
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.10.4 to 31.10.5.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](616559265b...ab739621df)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-23 00:16:27 +00:00
Jeffrey C. Ollie 880a599d66
windows: provide DllMain stub for non-MSVC ABI (#12373)
Part of preparation for adding a Win32 application runtime (discussion
#2563). One of three small, independent build fixes that together
unblock the Windows GNU-ABI library build.

On Windows with non-MSVC ABI, `pub const DllMain` resolved to `void` (a
type), and Zig's stdlib `start.zig` then tried to call it as a function
via `root.DllMain(...)`, failing to compile with "type 'type' not a
function".

This restructures the conditional so MSVC keeps its existing CRT-init
handler unchanged, non-MSVC Windows gets a no-op `BOOL` handler, and
non-Windows continues to resolve to `void`.

Verified: `zig build -Dtarget=native-native-gnu -Dapp-runtime=none
[-Doptimize=ReleaseSafe]` now builds cleanly on Windows.
2026-04-22 19:14:09 -05:00
Qwerasd 50869952af font/opentype: use packed struct for glyf point flags
Also fixes a logic bug where we weren't counting the length of x
coordinates and y coordinates correctly when we had repeated flags.
2026-04-22 13:40:24 -04:00
Yasuhiro Matsumoto 5a84afef29
address review: collapse DllMain into a single struct
Per review feedback (#12373), fold the nested `if/else if/else` into a
single Windows-gated struct whose handler picks up the abi difference
via a comptime check. This removes the duplicated `const BOOL = ...`
block that the two per-abi structs shared.
2026-04-23 02:17:04 +09:00
ghostty-vouch[bot] 2a3d93f77b
Update VOUCHED list (#12374)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12168#discussioncomment-16672511)
from @jcollie.

Vouch: @mattn

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-22 15:56:43 +00:00
Yasuhiro Matsumoto 2d4d47ed82
windows: provide DllMain stub for non-MSVC ABI
Part of preparation for upstreaming a Win32 application runtime
(see discussion #2563). This is one of three small build-related
fixes that unblock the Windows GNU-ABI library build.

When targeting Windows with GNU ABI, the existing `DllMain` declaration
falls through to `void` (a type), which Zig stdlib's `start.zig` then
attempts to call as a function via `root.DllMain(...)` - producing the
compile error "type 'type' not a function".

Restructure the conditional so that:
  - non-Windows builds keep `DllMain = void`
  - Windows + MSVC keeps the existing CRT-init handler (unchanged)
  - Windows + non-MSVC gets a no-op `BOOL` handler

This unblocks `zig build -Dtarget=native-native-gnu -Dapp-runtime=none`
on Windows.
2026-04-23 00:42:23 +09:00
Jeffrey C. Ollie 98b7ad4c49
libghostty-vt: fix broken dynamic linking with pkg-config (#12364)
~`${prefix}/include` and `${prefix}/lib` are incorrect under
split-prefix installs (e.g. Nix multi-output). Use `b.h_dir` /
`b.lib_dir` instead and drop the unneeded Nix postInstall/postFixup
hooks.~

Refactors the libghostty-vt derivation to:

- fix `libdir` pointing to the wrong output in the pkg-config files.
This would throw a missing library error at runtime.
- reduce the amount of manual copying, linking, and patching of files.

An earlier version of this PR used the zig compiler + `.pc` files to do
this. People pointed out concerns, so I came up with a simpler solution.

Claude Code was used to debug and write an initial fix. Final changes
rewritten and simplified by me. No AI was used to write comments,
descriptions, etc.
2026-04-22 10:35:02 -05:00
Qwerasd d778be20dd font/opentype: add glyf table entry validation
We want to have this for the glyph protocol so that we can validate
passed glyf data in libghostty without having to link freetype or
anything like that.
2026-04-21 19:27:54 -04:00
Sander 733abbcc39
libghostty-vt: revert .pc changes and use Nix to fix them
Keeps the .pc files templated and instead uses Nix to rewrite the libdir for the static library.
2026-04-21 23:20:06 +02:00
Domen Kožar 38d6451d73 libghostty-vt: emit resolved include/lib dirs in .pc files
`${prefix}/include` and `${prefix}/lib` are wrong under split-prefix installs (e.g. Nix multi-output).
Use `b.h_dir` / `b.lib_dir` instead and drop the unneeded Nix postInstall/postFixup hooks.

Co-Authored-By: Sander <hey@sandydoo.me>
2026-04-21 20:03:53 +02:00
Mitchell Hashimoto 6e0b0311e4
Use patched Zig 0.15.2 on macOS to avoid Xcode 26.4 issue (#12363)
This updates our Nix flake to use the Homebrew bottled Zig 0.15.2 which
contains a patch to work around the issue with Zig 0.15.x and Xcode
26.4.
2026-04-21 09:57:41 -07:00
Mitchell Hashimoto d2f86028bb
Use patched Zig 0.15.2 on macOS to avoid Xcode 26.4 issue
This updates our Nix flake to use the Homebrew bottled Zig 0.15.2 which
contains a patch to work around the issue with Zig 0.15.x and Xcode
26.4.
2026-04-21 09:40:47 -07:00
Mitchell Hashimoto 62fdd885e0
macOS: open preferred config if exists (#12321)
This helps developers like me to use a separate config for debugging
(which is already supported by the environment variable
`GHOSTTY_CONFIG_PATH`).

I can already use the local scheme to load a debugging config file, but
when opening the config file through Ghostty, it will still open the
default config.

This changes doesn't affect the release build, since `configPath` is
only set in the DEBUG build.
2026-04-21 09:23:29 -07:00
Mitchell Hashimoto 95c61e2880
docs,ci: clarify that users can never open issues (#12335)
I removed the entire paragraph in CONTRIBUTING.md because the "Quick
Guide" section explains it all better already.
2026-04-21 09:23:06 -07:00
Mitchell Hashimoto a6105b3b10
build(xcframework): exclude libghostty-vt headers from GhosttyKit (#12360)
The GhosttyKit xcframework previously shipped the entire include/
directory, which pulled in the libghostty-vt headers under
include/ghostty/. Because those headers are not referenced from the
ghostty.h umbrella, Clang's module system emitted "umbrella header for
module 'GhosttyKit' does not include header 'ghostty/vt/*.h'" warnings
in Xcode builds.

Stage only ghostty.h and module.modulemap via addWriteFiles so the
xcframework Headers directory contains exactly the GhosttyKit API,
mirroring the pattern used in GhosttyLibVt.xcframework.

## AI disclosure

Claude made the changes (including the commit message), I reviewed and
tested them.
2026-04-21 09:22:47 -07:00
ghostty-vouch[bot] 58af471a01
Update VOUCHED list (#12362)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12361#discussioncomment-16656763)
from @jcollie.

Vouch: @sandydoo

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-21 15:02:46 +00:00
Claude e9a196c67b
build(xcframework): exclude libghostty-vt headers from GhosttyKit
The GhosttyKit xcframework previously shipped the entire include/
directory, which pulled in the libghostty-vt headers under
include/ghostty/. Because those headers are not referenced from the
ghostty.h umbrella, Clang's module system emitted "umbrella header for
module 'GhosttyKit' does not include header 'ghostty/vt/*.h'" warnings
in Xcode builds.

Stage only ghostty.h and module.modulemap via addWriteFiles so the
xcframework Headers directory contains exactly the GhosttyKit API,
mirroring the pattern used in GhosttyLibVt.xcframework.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 14:43:21 +02:00
Jeffrey C. Ollie 3a1482d1a2
build(deps): bump namespacelabs/nscloud-cache-action from 1.4.2 to 1.4.3 (#12355)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.4.2 to 1.4.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/namespacelabs/nscloud-cache-action/releases">namespacelabs/nscloud-cache-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.4.3</h2>
<h2>What's Changed</h2>
<ul>
<li>
<p>Add npm mode by <a
href="https://github.com/rcrowe"><code>@​rcrowe</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/118">namespacelabs/nscloud-cache-action#118</a></p>
</li>
<li>
<p>Use repeated --path arguments instead of comma-separated values by <a
href="https://github.com/annervisser"><code>@​annervisser</code></a> in
<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/112">namespacelabs/nscloud-cache-action#112</a></p>
</li>
<li>
<p>Bump the minor-actions-dependencies group across 1 directory with 7
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/115">namespacelabs/nscloud-cache-action#115</a></p>
</li>
<li>
<p>Add manual-paths mode test with multiple paths by <a
href="https://github.com/annervisser"><code>@​annervisser</code></a> in
<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/111">namespacelabs/nscloud-cache-action#111</a></p>
</li>
<li>
<p>Bump the minor-npm-dependencies group across 1 directory with 6
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/116">namespacelabs/nscloud-cache-action#116</a></p>
</li>
<li>
<p>Add major-actions-dependencies Dependabot group by <a
href="https://github.com/rcrowe"><code>@​rcrowe</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/119">namespacelabs/nscloud-cache-action#119</a></p>
</li>
<li>
<p>Upgrade <code>@​namespacelabs/actions-toolkit</code> to 0.3.0 by <a
href="https://github.com/rcrowe"><code>@​rcrowe</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/125">namespacelabs/nscloud-cache-action#125</a></p>
</li>
<li>
<p>Bump the major-actions-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/123">namespacelabs/nscloud-cache-action#123</a></p>
</li>
<li>
<p>Bump the minor-actions-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/122">namespacelabs/nscloud-cache-action#122</a></p>
</li>
<li>
<p>Bump eslint from 9.39.4 to 10.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/121">namespacelabs/nscloud-cache-action#121</a></p>
</li>
<li>
<p>Bump typescript from 5.9.3 to 6.0.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/120">namespacelabs/nscloud-cache-action#120</a></p>
</li>
<li>
<p>Bump <code>@​eslint/js</code> from 9.39.4 to 10.0.1 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/102">namespacelabs/nscloud-cache-action#102</a></p>
</li>
<li>
<p>Bump typescript from 6.0.2 to 6.0.3 in the minor-npm-dependencies
group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/126">namespacelabs/nscloud-cache-action#126</a></p>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/namespacelabs/nscloud-cache-action/compare/v1...v1.4.3">https://github.com/namespacelabs/nscloud-cache-action/compare/v1...v1.4.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="15799a6b54"><code>15799a6</code></a>
Bump typescript from 6.0.2 to 6.0.3 in the minor-npm-dependencies group
(<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/126">#126</a>)</li>
<li><a
href="a74ba09be4"><code>a74ba09</code></a>
Add npm mode test (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/118">#118</a>)</li>
<li><a
href="3accca63b2"><code>3accca6</code></a>
Bump <code>@​eslint/js</code> from 9.39.2 to 10.0.1 (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/102">#102</a>)</li>
<li><a
href="320beceb2e"><code>320bece</code></a>
Bump typescript from 5.9.3 to 6.0.2 (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/120">#120</a>)</li>
<li><a
href="7b579df1e2"><code>7b579df</code></a>
Bump eslint from 9.39.4 to 10.2.0 (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/121">#121</a>)</li>
<li><a
href="0170534ed6"><code>0170534</code></a>
Bump the minor-actions-dependencies group with 3 updates (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/122">#122</a>)</li>
<li><a
href="04d1d76ca0"><code>04d1d76</code></a>
Bump the major-actions-dependencies group across 1 directory with 4
updates (...</li>
<li><a
href="0496385e4a"><code>0496385</code></a>
Upgrade <code>@​namespacelabs/actions-toolkit</code> to 0.3.0 (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/125">#125</a>)</li>
<li><a
href="e14531ae78"><code>e14531a</code></a>
Add major-actions-dependencies Dependabot group (<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/119">#119</a>)</li>
<li><a
href="1f34f9763c"><code>1f34f97</code></a>
Bump the minor-npm-dependencies group across 1 directory with 6 updates
(<a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/116">#116</a>)</li>
<li>Additional commits viewable in <a
href="a90bb5d4b2...15799a6b54">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=namespacelabs/nscloud-cache-action&package-manager=github_actions&previous-version=1.4.2&new-version=1.4.3)](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-04-20 22:34:08 -05:00
dependabot[bot] 5eeb4d9d68
build(deps): bump namespacelabs/nscloud-cache-action from 1.4.2 to 1.4.3
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](a90bb5d4b2...15799a6b54)

---
updated-dependencies:
- dependency-name: namespacelabs/nscloud-cache-action
  dependency-version: 1.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-21 00:53:07 +00:00
Mitchell Hashimoto c3c8572f7f
update zon2nix (#12337)
Adds better Zig 0.16 compatibility.
2026-04-20 11:52:59 -07:00
Mitchell Hashimoto 61363e80d1
macOS: fix App Icon update in Finder (#12344)
Looks like `NSWorkspace.shared.setIcon` can only be called from the main
App, DockTilePlugin is sandboxed and doesn't have the permission to
`file-write-finderinfo`.

<img width="1186" height="144" alt="image"
src="https://github.com/user-attachments/assets/e5ea4f1c-718c-493a-bda2-32787881881e"
/>


It works fine in debug, but not in release. This fixes #11489
2026-04-20 11:52:43 -07:00
007hacky007 50e8ebaf60 surface: sync middle-click paste source with copy-on-select
Middle-click paste previously always read from the selection clipboard
(falling back to the standard clipboard on platforms without one).

Now the paste source follows copy-on-select:
- copy-on-select = true: paste from selection clipboard (unchanged)
- copy-on-select = clipboard: paste from system clipboard
- copy-on-select = false: paste from selection clipboard (unchanged)

Fixes ghostty-org/ghostty#9788.
2026-04-20 19:56:45 +02:00
Lukas afdae7293a
macos: add pid and tty properties to AppleScript terminal and App Intents TerminalEntity (#11922) 2026-04-20 18:10:57 +02:00
Mitchell Hashimoto 4446dbae33
Misc APC improvements (#12349)
* Fix a memory leak when invalid Kitty graphics data is sent via APC
(this is the only commit for backporting to 1.3.2)
* Add `max_bytes` to limit size of buffered APC data by protocol to
prevent DoS, default to reasonable values
* libghostty: expose max bytes APC options
2026-04-20 09:10:50 -07:00
Mitchell Hashimoto 0069e28cc6
libghostty: expose the APC max byte limits 2026-04-20 08:57:51 -07:00
Mitchell Hashimoto 0509f00ad2
terminal/apc: introduce a max_bytes parameter to prevent DoS 2026-04-20 08:53:02 -07:00
Mitchell Hashimoto 83027407e6
terminal: fix memory leak that could happen with invalid Kitty image cmd 2026-04-20 08:45:41 -07:00
Christo Wilken 9a9002202b macos: add pid and tty properties to AppleScript terminal class
Expose the foreground process PID and TTY device path as read-only properties on the AppleScript terminal class and App Intents TerminalEntity. This enables reliable process-to-terminal mapping for automation tools when multiple terminals share the same CWD.

Closes #11592
Closes #10756

Session: 019d341c-a165-7843-a2f7-2f426114cf17
2026-04-20 15:16:03 +02:00
Lukas c7a73076e9
macOS: fix App Icon update in Finders
Looks like  `NSWorkspace.shared.setIcon` can only be called from the main App, DockTilePlugin is sandboxed and doesn't have the permission to `file-write-finderinfo`.

It works fine in debug, but not in release. This fixes #11489, #11290
2026-04-20 12:56:55 +02:00
Mitchell Hashimoto dcc39dcd40
android: Avoid referencing POSIX shared memory functions (#12341)
Stop trying to use POSIX shared memory functions such as `shm_open` on
Android as it's unsupported and the platform libc does not have those
symbols.

This avoids an error such as the below when trying to use
`libghostty-vt` on Android:

> dlopen failed: cannot locate symbol "shm_open" referenced by [..]
2026-04-19 15:21:26 -07:00
Fredrik Fornwall adb0d793af
android: Avoid referencing POSIX shared memory functions
Stop trying to use POSIX shared memory functions such as
`shm_open` on Android as it's unsupported and the platform libc does not
have those symbols.

This avoids an error such as the below when trying to use
`libghostty-vt` on Android:

> dlopen failed: cannot locate symbol "shm_open" referenced by [..]
2026-04-19 23:44:37 +02:00
ghostty-vouch[bot] d69d937a93
Update VOUCHED list (#12340)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12339#discussioncomment-16627477)
from @jcollie.

Vouch: @fornwall

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-19 21:38:47 +00:00
Kat ed29fd56dd
Translation documentation-related typos + CODEOWNERS update (#12336) 2026-04-19 20:42:30 +00:00
Kat 2e33589e23
Avoid marking files as owned by ghostty-org/localization.
That team and its children have a very large number of members, so
requests for review from them would make for a mass ping.
2026-04-20 06:23:55 +10:00
Jeffrey C. Ollie 2db58a63fe
update zon2nix 2026-04-19 10:51:57 -05:00
Kat 49cd2ba80b
Mark i18n_locales.zig as owned by ghostty-org/localization/manager. 2026-04-20 01:25:08 +10:00
Kat 8a6c664686
Fix typo in i18n_locales.zig. 2026-04-20 01:22:09 +10:00
Kat 9cbca54597
Fix typo + improve fluency in README_TRANSLATORS § Viewing translations. 2026-04-20 01:22:09 +10:00
Kat 28b7ef12c3
i18n: add Belarusian translation (be) (#12284)
This PR adds Belarusian (be) language support to Ghostty.

## Changes

- `po/be.po` — new Belarusian translation file (80 strings)
- `src/os/i18n_locales.zig` — added `be` locale
- `CODEOWNERS` — added `/po/be.po @ghostty-org/be_BY`

## Notes

Terminology was cross-referenced with:
- KDE Belarusian translations (l10n.kde.org)
- qBittorrent Belarusian translation
- far2l Belarusian translation
- Ubuntu Belarusian Translators Dictionary
2026-04-19 14:48:32 +00:00
Lukas 7a3e3dc8d2
macOS: fix #12266 by using the correct coordinates for the hitTest (#12322)
Fixes #12266, regression of #11872.
2026-04-19 15:51:49 +02:00
trag1c cb518e6afd
ci: use a custom template for ghostty-vouch issue comments 2026-04-19 15:41:41 +02:00
trag1c 22f9233a0f
contributing: don't encourage opening an issue 2026-04-19 15:41:41 +02:00
Illia Krauchanka f370099d34 i18n: address review feedback (be) 2026-04-19 08:35:31 -03:00
Lukas 5939b8c1be
macOS: fix 12266 by using the correct coordinates for the hitTest
Regression of #11872
2026-04-17 20:05:18 +02:00
Lukas 9bad9365b0
macOS: open preferred config if exists 2026-04-17 15:29:29 +02:00
Mitchell Hashimoto ca7516bea6
macOS: move KeyStateIndicator on top of exit bar (#12282) 2026-04-16 20:33:48 -07:00
Leorize 7cc9cc8ba8
flatpak: terminate session if Ghostty disconnects from bus
This makes sure that if Ghostty crashes, commands spawned are also
terminated automatically by the Flatpak Session Helper.
2026-04-16 00:23:46 -07:00
Aaron Ang 41878d6f79 snap: export TERMINFO_DIRS so child shells find xterm-ghostty
Without this, shells spawned by ghostty cannot find the xterm-ghostty
terminfo entry because ncurses only searches standard system paths.
The snap's terminfo lives inside the snap sandbox and is inaccessible
unless TERMINFO_DIRS is set explicitly.
2026-04-15 22:42:51 -04:00
ghostty-vouch[bot] 9e080c5a40
Update VOUCHED list (#12302)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12301#issuecomment-4255856979)
from @trag1c.

Vouch: @bleikurr

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-15 21:56:04 +00:00
Mitchell Hashimoto d85051a530
macOS: fix shortcuts not showing on menu item for `scroll_to_selection` and `search_selection` (#12281)
…

Incorrect link after 9b6a3be993 and
7d0157e69a

Reload following config and see the menu
```
keybind = cmd+j=scroll_to_selection
keybind = cmd+m=search_selection
```

<img width="473" height="222" alt="image"
src="https://github.com/user-attachments/assets/f92c6024-e7f4-496d-9aed-43103c21794d"
/>
2026-04-15 14:15:38 -07:00
Mitchell Hashimoto 551bf0af3f
terminal: fix viewport pin during resize reflow (#12300)
Maybe related to #12298?

When Screen resize forwards the active cursor into PageList reflow, a
history-pinned viewport can be remapped into the active area before the
preserved-cursor grow step finishes. The old code kept treating that
viewport as a history pin during the intermediate grow calls, which left
too few rows beneath the pin and tripped the viewport integrity checks.

Fix this by normalizing the viewport back to active as soon as reflow
moves the pinned row into the active area. Add a Screen-level regression
test that exercises the full resize path with bounded scrollback and
wrapped rows, and document the setup so the unwrap and viewport
transition are clear.
2026-04-15 14:04:09 -07:00
Mitchell Hashimoto 815ccb060b
terminal: fix viewport pin during resize reflow
Maybe related to #12298?

When Screen resize forwards the active cursor into PageList reflow, a
history-pinned viewport can be remapped into the active area before the
preserved-cursor grow step finishes. The old code kept treating that
viewport as a history pin during the intermediate grow calls, which left
too few rows beneath the pin and tripped the viewport integrity checks.

Fix this by normalizing the viewport back to active as soon as reflow
moves the pinned row into the active area. Add a Screen-level regression
test that exercises the full resize path with bounded scrollback and
wrapped rows, and document the setup so the unwrap and viewport
transition are clear.
2026-04-15 13:59:54 -07:00
Mitchell Hashimoto 43a05dc968
libghostty: Remove all libc++ and libc++ ABI dependencies (#12291)
This updates simdutf to my fork which has a SIMDUTF_NO_LIBCXX option
that removes all libc++ and libc++ ABI dependencies. The plan is to open
an upstream PR with this, but I want to verify it here first.

From there, the hand-written simd code we have has been updated to also
no longer use any libc++ features. Part of this required removing utfcpp
since it depended on libc++ (`<iterator>`).

libghostty-vt now only depends on libc.

## Benchmark Results

| Corpus | Current `HEAD` median | `main` median | Delta vs `main` |
Notes |
| --- | ---: | ---: | ---: | --- |
| `valid-mixed-1g-seed1.bin` | `9.245s` | `9.111s` | `1.5%` slower |
Near tie; `main` remains slightly faster on fully valid input |
| `malformed-mixed-1g-seed1-rate0.005.bin` | `9.251s` | `12.705s` |
`37.3%` faster | Large improvement on malformed UTF-8 input |

Approximate throughput from the medians:

- Valid corpus: current `HEAD` `110.8 MiB/s`, `main` `112.4 MiB/s`
- Malformed corpus: current `HEAD` `110.7 MiB/s`, `main` `80.6 MiB/s`
2026-04-15 11:36:16 -07:00
Mitchell Hashimoto e51de8b58f
libghostty: Remove all libc++ and libc++ ABI dependencies
This updates simdutf to my fork which has a SIMDUTF_NO_LIBCXX option
that removes all libc++ and libc++ ABI dependencies. 

From there, the hand-written simd code we have has been updated to also
no longer use any libc++ features. Part of this required removing utfcpp
since it depended on libc++ (`<iterator>`).

libghostty-vt now only depends on libc.
2026-04-15 10:27:05 -07:00
Mitchell Hashimoto efa8da6aea
nix: update to the latest zon2nix (#12299) 2026-04-15 09:26:29 -07:00
Jeffrey C. Ollie f53d3ab8a3
nix: update to the latest zon2nix 2026-04-15 11:21:25 -05:00
Mitchell Hashimoto 29f92c0c8b
benchmark: add AGENTS, improve UTF-8 synthetic data (#12297)
This updates our synthetic generator for UTF-8 to expose:

  - Flags to change 1/2/3/4-byte UTF-8 character distribution
- Flags to have only printable characters so we can benchmark pure UTF-8
vs our control sequence finder.
- Flags to have invalid characters so we can benchmark our error
handling.

This also adds an AGENTS.md to src/benchmark so agents can do the right
thing more easily.

These are necessary to robustly benchmark our libc++ removal PR.
2026-04-15 09:09:11 -07:00
Mitchell Hashimoto 9c49c34356
benchmark: add AGENTS, improve UTF-8 synthetic data
This updates our synthetic generator for UTF-8 to expose:

  - Flags to change 1/2/3/4-byte UTF-8 character distribution
  - Flags to have only printable characters so we can benchmark
    pure UTF-8 vs our control sequence finder.
  - Flags to have invalid characters so we can benchmark our error
    handling.

This also adds an AGENTS.md to src/benchmark so agents can do the right
thing more easily.
2026-04-15 08:28:36 -07:00
ghostty-vouch[bot] 49a43bf560
Update VOUCHED list (#12285)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12284#issuecomment-4247088526)
from @trag1c.

Vouch: @illiakrauchanka

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-14 20:55:42 +00:00
illia krauchanka 053dee8db2 i18n: replace гартаць with пракручваць (be) 2026-04-14 17:51:36 -03:00
illia krauchanka 43811534b9 i18n: replace змесціва with змест (be) 2026-04-14 17:43:55 -03:00
illia krauchanka 3ee0b0a77b i18n: fix gender agreement for match translations (be) 2026-04-14 17:43:37 -03:00
illia krauchanka ff9ca55b58 i18n: fix terminology in Belarusian translation (be) 2026-04-14 17:42:44 -03:00
illia krauchanka 4f3a9cb0c6 i18n: add Belarusian translation (be) 2026-04-14 17:27:37 -03:00
Lukas b7d0be8e74
macOS: move KeyStateIndicator on top of exit bar 2026-04-14 19:55:46 +02:00
Lukas 858e856e2e
macOS: fix shortcuts not showing on menu item for `scroll_to_selection` and `search_selection`
Incorrect link after 9b6a3be993 and 7d0157e69a
2026-04-14 19:21:16 +02:00
Mitchell Hashimoto 79a470d9a3
macOS: refactor MenuShortcutManager (#12271)
Closes #11995

Yet another small step to fix menu shortcut-related issues.

1. Create `MenuShortcutKey` from `NSMenuItem` and `KeyboardShortcut`.
2. Add `updateMenuShortcut` to update to Ghostty ones only.

Doesn't contain any actual changes to pass previous test cases.
2026-04-14 07:05:10 -07:00
Lukas 6033c12790
macOS: reset menu shortcuts when its not updated 2026-04-13 19:59:20 +02:00
Lukas fe8a6464b9
macOS: update MenuShortcutKey 2026-04-13 19:56:56 +02:00
Daniel Kinzler 2648668da9 fix quick-terminal breaking when it is manually toggled while autohide is enabled 2026-04-13 19:01:56 +02:00
ghostty-vouch[bot] 158b97607c
Update VOUCHED list (#12268)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12267#issuecomment-4237110063)
from @mitchellh.

Vouch: @0xDVC

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-13 14:23:27 +00:00
Mitchell Hashimoto 4f36896ddb
macOS: add bottom bar when child exits (#12251)
### Closes #7649

The bar lives alongside URL Hover in VStack at the bottom. The current
body of SurfaceView is becoming rather long and complicated, so this pr
also contains some refactors:

- Move URL Hover to a separate file

> The text is copied from previous input string to keep it consistent,
also I’m confused with text on GTK so this is my first choice, but it
can be changed as the same as GTK.

Separate prs will be opened for:
1. Set to Read-only after exits
2. Hide cursor when in Read-only

### Preview


https://github.com/user-attachments/assets/eb44e211-eac5-4f40-836c-4912b18dfb01
2026-04-13 06:47:47 -07:00
Mitchell Hashimoto 4699a3f795
macOS: Command palette highlight matches (#12264)
- Highlight matching text in command palette search results
- Support initials matching
- Trim query before filtering commands

### AI Disclosure

Claude wrote most of it. I tested and reviewed it myself.

<img width="1544" height="297" alt="image"
src="https://github.com/user-attachments/assets/6ed98538-d6d3-48a0-8bb0-ac705611d058"
/>
2026-04-13 06:44:27 -07:00
Mitchell Hashimoto ec434ec096
zon2nix: update to a version that is compatible with Zig 0.16 (#12259)
The `zon2nix` binary is now compiled with Zig 0.16, but it still
produces Zig 0.15 compatible output (in fact the output is identical to
previous versions).
2026-04-13 06:43:44 -07:00
Mitchell Hashimoto fab8777931
core: implement backarrow key mode (DECBKM) - mode 67 (#12226)
This mode allows programs to modify the code that the `backspace` key
(backarrow key in DEC parlance) sends. If this mode is
`off`/`false`/`reset` (the default, the same as before this PR), we send
the byte `0x7f`. If this mode is `on`/`true`/`set` we send the byte
`0x08`.

<img width="659" height="715" alt="Screenshot From 2026-04-09 11-00-25"
src="https://github.com/user-attachments/assets/4f3e14ac-757d-4bb2-9fc5-b17019ad35d5"
/>
2026-04-13 06:43:30 -07:00
Lukas 073dd8a399
macOS: trim query before filtering commands 2026-04-13 12:47:48 +02:00
Lukas 2e169c42e8
macOS: Support initials matching in command palette search
Extend String.matchedIndices(for:) to fall back to initials
matching when no substring match is found. Typing the first letter
of each word now matches commands, e.g. "tbo" matches "Toggle
Background Opacity", with each matched initial highlighted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:47:47 +02:00
Lukas 2bdc6bb1f7
macOS: Highlight matching text in command palette search results
Add String.matchedIndices(for:) to find substring matches and use
it to bold and tint matched characters with the accent color in
both titles and subtitles. Title matches take priority — subtitles
are only highlighted when the title didn't match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:47:47 +02:00
Lukas 38e64c3706
macOS: add bottom bar when child exits 2026-04-13 10:08:13 +02:00
Lukas c2a93db591
macOS: move url hover to a separate file 2026-04-13 08:18:11 +02:00
Jeffrey C. Ollie 1443e7a9cd
zon2nix: use github mirror 2026-04-12 22:46:57 -05:00
Jeffrey C. Ollie f29d5d4150
zon2nix: update to a version that is compatible with Zig 0.16
The `zon2nix` binary is now compiled with Zig 0.16, but it still produces
Zig 0.15 compatible output (in fact the output is identical to previous
versions).
2026-04-12 21:44:44 -05:00
Jeffrey C. Ollie 01825411ab
build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1 (#12258)
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 7.0.0 to 7.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update the readme with direct upload details by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/795">actions/upload-artifact#795</a></li>
<li>Readme: bump all the example versions to v7 by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/796">actions/upload-artifact#796</a></li>
<li>Include changes in typespec/ts-http-runtime 0.3.5 by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/797">actions/upload-artifact#797</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v7...v7.0.1">https://github.com/actions/upload-artifact/compare/v7...v7.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="043fb46d1a"><code>043fb46</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/797">#797</a>
from actions/yacaovsnc/update-dependency</li>
<li><a
href="634250c138"><code>634250c</code></a>
Include changes in typespec/ts-http-runtime 0.3.5</li>
<li><a
href="e454baaac2"><code>e454baa</code></a>
Readme: bump all the example versions to v7 (<a
href="https://redirect.github.com/actions/upload-artifact/issues/796">#796</a>)</li>
<li><a
href="74fad66b98"><code>74fad66</code></a>
Update the readme with direct upload details (<a
href="https://redirect.github.com/actions/upload-artifact/issues/795">#795</a>)</li>
<li>See full diff in <a
href="bbbca2ddaa...043fb46d1a">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=7.0.0&new-version=7.0.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-04-12 21:25:14 -05:00
Jeffrey C. Ollie 6b97d911df
build(deps): bump actions/create-github-app-token from 3.0.0 to 3.1.1 (#12257)
Bumps
[actions/create-github-app-token](https://github.com/actions/create-github-app-token)
from 3.0.0 to 3.1.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's
releases</a>.</em></p>
<blockquote>
<h2>v3.1.1</h2>
<h2><a
href="https://github.com/actions/create-github-app-token/compare/v3.1.0...v3.1.1">3.1.1</a>
(2026-04-11)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>improve error message when app identifier is empty (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/362">#362</a>)
(<a
href="07e2b76066">07e2b76</a>),
closes <a
href="https://redirect.github.com/actions/create-github-app-token/issues/249">#249</a></li>
</ul>
<h2>v3.1.0</h2>
<h1><a
href="https://github.com/actions/create-github-app-token/compare/v3.0.0...v3.1.0">3.1.0</a>
(2026-04-11)</h1>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump p-retry from 7.1.1 to 8.0.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/357">#357</a>)
(<a
href="3bbe07d928">3bbe07d</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>add <code>client-id</code> input and deprecate <code>app-id</code>
(<a
href="https://redirect.github.com/actions/create-github-app-token/issues/353">#353</a>)
(<a
href="e6bd4e6970">e6bd4e6</a>)</li>
<li>update permission inputs (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/358">#358</a>)
(<a
href="076e9480ca">076e948</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1b10c78c78"><code>1b10c78</code></a>
build(release): 3.1.1 [skip ci]</li>
<li><a
href="07e2b76066"><code>07e2b76</code></a>
fix: improve error message when app identifier is empty (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/362">#362</a>)</li>
<li><a
href="ea0121618b"><code>ea01216</code></a>
ci: remove publish-immutable-action workflow (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/361">#361</a>)</li>
<li><a
href="7bd0371149"><code>7bd0371</code></a>
build(release): 3.1.0 [skip ci]</li>
<li><a
href="e6bd4e6970"><code>e6bd4e6</code></a>
feat: add <code>client-id</code> input and deprecate <code>app-id</code>
(<a
href="https://redirect.github.com/actions/create-github-app-token/issues/353">#353</a>)</li>
<li><a
href="076e9480ca"><code>076e948</code></a>
feat: update permission inputs (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/358">#358</a>)</li>
<li><a
href="3bbe07d928"><code>3bbe07d</code></a>
fix(deps): bump p-retry from 7.1.1 to 8.0.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/357">#357</a>)</li>
<li><a
href="28a99e369c"><code>28a99e3</code></a>
build(deps-dev): bump c8 from 10.1.3 to 11.0.0</li>
<li><a
href="4df50600ef"><code>4df5060</code></a>
build(deps-dev): bump open-cli from 8.0.0 to 9.0.0</li>
<li><a
href="4843c538d9"><code>4843c53</code></a>
build(deps-dev): bump the development-dependencies group with 3
updates</li>
<li>See full diff in <a
href="f8d387b68d...1b10c78c78">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=3.0.0&new-version=3.1.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-04-12 21:24:32 -05:00
Jeffrey C. Ollie 2c9f57f8b0
build(deps): bump docker/build-push-action from 7.0.0 to 7.1.0 (#12256)
Bumps
[docker/build-push-action](https://github.com/docker/build-push-action)
from 7.0.0 to 7.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.1.0</h2>
<ul>
<li>Git context <a
href="https://docs.docker.com/build/concepts/context/#url-queries">query
format</a> support by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/build-push-action/pull/1505">docker/build-push-action#1505</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.79.0 to 0.87.0 by
<a href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1505">docker/build-push-action#1505</a></li>
<li>Bump brace-expansion from 1.1.12 to 1.1.13 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1500">docker/build-push-action#1500</a></li>
<li>Bump fast-xml-parser from 5.4.2 to 5.5.7 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1489">docker/build-push-action#1489</a></li>
<li>Bump flatted from 3.3.3 to 3.4.2 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1491">docker/build-push-action#1491</a></li>
<li>Bump glob from 10.3.12 to 10.5.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1490">docker/build-push-action#1490</a></li>
<li>Bump handlebars from 4.7.8 to 4.7.9 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1497">docker/build-push-action#1497</a></li>
<li>Bump lodash from 4.17.23 to 4.18.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1510">docker/build-push-action#1510</a></li>
<li>Bump picomatch from 4.0.3 to 4.0.4 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1496">docker/build-push-action#1496</a></li>
<li>Bump undici from 6.23.0 to 6.24.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1486">docker/build-push-action#1486</a></li>
<li>Bump vite from 7.3.1 to 7.3.2 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1509">docker/build-push-action#1509</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.0.0...v7.1.0">https://github.com/docker/build-push-action/compare/v7.0.0...v7.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bcafcacb16"><code>bcafcac</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1509">#1509</a>
from docker/dependabot/npm_and_yarn/vite-7.3.2</li>
<li><a
href="18e62f1158"><code>18e62f1</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1510">#1510</a>
from docker/dependabot/npm_and_yarn/lodash-4.18.1</li>
<li><a
href="46580d2c9d"><code>46580d2</code></a>
chore: update generated content</li>
<li><a
href="3f80b252ca"><code>3f80b25</code></a>
chore(deps): Bump lodash from 4.17.23 to 4.18.1</li>
<li><a
href="efeec9557c"><code>efeec95</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1505">#1505</a>
from crazy-max/refactor-git-context</li>
<li><a
href="ddf04b08eb"><code>ddf04b0</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1511">#1511</a>
from docker/dependabot/github_actions/crazy-max-dot-...</li>
<li><a
href="db08d97a08"><code>db08d97</code></a>
chore(deps): Bump the crazy-max-dot-github group with 2 updates</li>
<li><a
href="ef1fb9688f"><code>ef1fb96</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1508">#1508</a>
from docker/dependabot/github_actions/docker/login-a...</li>
<li><a
href="2d8f2a1a37"><code>2d8f2a1</code></a>
chore: update generated content</li>
<li><a
href="919ac7bd7d"><code>919ac7b</code></a>
fix test since secrets are not written to temp path anymore</li>
<li>Additional commits viewable in <a
href="d08e5c354a...bcafcacb16">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=7.0.0&new-version=7.1.0)](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-04-12 21:23:41 -05:00
Jeffrey C. Ollie 922b610632
build(deps): bump peter-evans/create-pull-request from 8.1.0 to 8.1.1 (#12255)
Bumps
[peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request)
from 8.1.0 to 8.1.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/peter-evans/create-pull-request/releases">peter-evans/create-pull-request's
releases</a>.</em></p>
<blockquote>
<h2>Create Pull Request v8.1.1</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps-dev): bump the npm group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4305">peter-evans/create-pull-request#4305</a></li>
<li>build(deps): bump minimatch by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4311">peter-evans/create-pull-request#4311</a></li>
<li>build(deps): bump the github-actions group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4316">peter-evans/create-pull-request#4316</a></li>
<li>build(deps): bump <code>@​tootallnate/once</code> and
jest-environment-jsdom by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4323">peter-evans/create-pull-request#4323</a></li>
<li>build(deps-dev): bump undici from 6.23.0 to 6.24.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4328">peter-evans/create-pull-request#4328</a></li>
<li>build(deps-dev): bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4334">peter-evans/create-pull-request#4334</a></li>
<li>build(deps): bump picomatch by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4339">peter-evans/create-pull-request#4339</a></li>
<li>build(deps-dev): bump handlebars from 4.7.8 to 4.7.9 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4344">peter-evans/create-pull-request#4344</a></li>
<li>build(deps-dev): bump the npm group with 3 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4349">peter-evans/create-pull-request#4349</a></li>
<li>fix: retry post-creation API calls on 422 eventual consistency
errors by <a
href="https://github.com/peter-evans"><code>@​peter-evans</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/4356">peter-evans/create-pull-request#4356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/peter-evans/create-pull-request/compare/v8.1.0...v8.1.1">https://github.com/peter-evans/create-pull-request/compare/v8.1.0...v8.1.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5f6978faf0"><code>5f6978f</code></a>
fix: retry post-creation API calls on 422 eventual consistency errors
(<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4356">#4356</a>)</li>
<li><a
href="d32e88dac7"><code>d32e88d</code></a>
build(deps-dev): bump the npm group with 3 updates (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4349">#4349</a>)</li>
<li><a
href="8170bccad1"><code>8170bcc</code></a>
build(deps-dev): bump handlebars from 4.7.8 to 4.7.9 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4344">#4344</a>)</li>
<li><a
href="00418193b4"><code>0041819</code></a>
build(deps): bump picomatch (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4339">#4339</a>)</li>
<li><a
href="b993918c85"><code>b993918</code></a>
build(deps-dev): bump flatted from 3.3.1 to 3.4.2 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4334">#4334</a>)</li>
<li><a
href="36d7c8468b"><code>36d7c84</code></a>
build(deps-dev): bump undici from 6.23.0 to 6.24.0 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4328">#4328</a>)</li>
<li><a
href="a45d1fb447"><code>a45d1fb</code></a>
build(deps): bump <code>@​tootallnate/once</code> and
jest-environment-jsdom (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4323">#4323</a>)</li>
<li><a
href="3499eb6183"><code>3499eb6</code></a>
build(deps): bump the github-actions group with 2 updates (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4316">#4316</a>)</li>
<li><a
href="3f3b473b8c"><code>3f3b473</code></a>
build(deps): bump minimatch (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4311">#4311</a>)</li>
<li><a
href="6699836a21"><code>6699836</code></a>
build(deps-dev): bump the npm group with 2 updates (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/4305">#4305</a>)</li>
<li>See full diff in <a
href="c0f553fe54...5f6978faf0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=peter-evans/create-pull-request&package-manager=github_actions&previous-version=8.1.0&new-version=8.1.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-04-12 21:22:53 -05:00
Jeffrey C. Ollie 3ef500b3c8
build(deps): bump softprops/action-gh-release from 2.6.1 to 3.0.0 (#12254)
Bumps
[softprops/action-gh-release](https://github.com/softprops/action-gh-release)
from 2.6.1 to 3.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<p><code>3.0.0</code> is a major release that moves the action runtime
from Node 20 to Node 24.
Use <code>v3</code> on GitHub-hosted runners and self-hosted fleets that
already support the
Node 24 Actions runtime. If you still need the last Node 20-compatible
line, stay on
<code>v2.6.2</code>.</p>
<h2>What's Changed</h2>
<h3>Other Changes 🔄</h3>
<ul>
<li>Move the action runtime and bundle target to Node 24</li>
<li>Update <code>@types/node</code> to the Node 24 line and allow future
Dependabot updates</li>
<li>Keep the floating major tag on <code>v3</code>; <code>v2</code>
remains pinned to the latest <code>2.x</code> release</li>
</ul>
<h2>v2.6.2</h2>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<h3>Other Changes 🔄</h3>
<ul>
<li>chore(deps): bump picomatch from 4.0.3 to 4.0.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/775">softprops/action-gh-release#775</a></li>
<li>chore(deps): bump brace-expansion from 5.0.4 to 5.0.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/777">softprops/action-gh-release#777</a></li>
<li>chore(deps): bump vite from 8.0.0 to 8.0.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/781">softprops/action-gh-release#781</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/softprops/action-gh-release/compare/v2...v2.6.2">https://github.com/softprops/action-gh-release/compare/v2...v2.6.2</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>3.0.0</h2>
<p><code>3.0.0</code> is a major release that moves the action runtime
from Node 20 to Node 24.
Use <code>v3</code> on GitHub-hosted runners and self-hosted fleets that
already support the
Node 24 Actions runtime. If you still need the last Node 20-compatible
line, stay on
<code>v2.6.2</code>.</p>
<h2>What's Changed</h2>
<h3>Other Changes 🔄</h3>
<ul>
<li>Move the action runtime and bundle target to Node 24</li>
<li>Update <code>@types/node</code> to the Node 24 line and allow future
Dependabot updates</li>
<li>Keep the floating major tag on <code>v3</code>; <code>v2</code>
remains pinned to the latest <code>2.x</code> release</li>
</ul>
<h2>2.6.2</h2>
<h2>What's Changed</h2>
<h3>Other Changes 🔄</h3>
<ul>
<li>chore(deps): bump picomatch from 4.0.3 to 4.0.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/775">softprops/action-gh-release#775</a></li>
<li>chore(deps): bump brace-expansion from 5.0.4 to 5.0.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/777">softprops/action-gh-release#777</a></li>
<li>chore(deps): bump vite from 8.0.0 to 8.0.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/781">softprops/action-gh-release#781</a></li>
</ul>
<h2>2.6.1</h2>
<p><code>2.6.1</code> is a patch release focused on restoring linked
discussion thread creation when
<code>discussion_category_name</code> is set. It fixes
<code>[#764](https://github.com/softprops/action-gh-release/issues/764)</code>,
where the draft-first publish flow
stopped carrying the discussion category through the final publish
step.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: preserve discussion category on publish by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/765">softprops/action-gh-release#765</a></li>
</ul>
<h2>2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b430933298"><code>b430933</code></a>
release: cut v3.0.0 for Node 24 upgrade (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/670">#670</a>)</li>
<li><a
href="c2e35e05a7"><code>c2e35e0</code></a>
chore(deps): bump the npm group across 1 directory with 7 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/783">#783</a>)</li>
<li><a
href="3bb12739c2"><code>3bb1273</code></a>
release 2.6.2</li>
<li><a
href="c34030fec9"><code>c34030f</code></a>
chore: bump node to 24.14.1</li>
<li><a
href="8975bd05c0"><code>8975bd0</code></a>
chore(deps): bump vite from 8.0.0 to 8.0.5 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/781">#781</a>)</li>
<li><a
href="f71937f44d"><code>f71937f</code></a>
chore(deps): bump brace-expansion from 5.0.4 to 5.0.5 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/777">#777</a>)</li>
<li><a
href="3f0d239d58"><code>3f0d239</code></a>
chore(deps): bump picomatch from 4.0.3 to 4.0.4 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/775">#775</a>)</li>
<li>See full diff in <a
href="153bb8e044...b430933298">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=softprops/action-gh-release&package-manager=github_actions&previous-version=2.6.1&new-version=3.0.0)](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-04-12 21:21:41 -05:00
dependabot[bot] e30c2bd86b
build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](bbbca2ddaa...043fb46d1a)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 00:23:37 +00:00
dependabot[bot] c2a1ac5866
build(deps): bump actions/create-github-app-token from 3.0.0 to 3.1.1
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 3.0.0 to 3.1.1.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](f8d387b68d...1b10c78c78)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: 3.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 00:23:33 +00:00
dependabot[bot] 470605f0ab
build(deps): bump docker/build-push-action from 7.0.0 to 7.1.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](d08e5c354a...bcafcacb16)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 00:23:26 +00:00
dependabot[bot] b0cfc595f2
build(deps): bump peter-evans/create-pull-request from 8.1.0 to 8.1.1
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 8.1.0 to 8.1.1.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](c0f553fe54...5f6978faf0)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-version: 8.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 00:23:23 +00:00
dependabot[bot] ea2753b819
build(deps): bump softprops/action-gh-release from 2.6.1 to 3.0.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.1 to 3.0.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](153bb8e044...b430933298)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 00:23:17 +00:00
Jeffrey C. Ollie 3a9ae7a0f2
decbkm: expose DECBKM to libghostty-vt 2026-04-12 16:04:16 -05:00
Jeffrey C. Ollie de4992c2b2
decbkm: use if statements instead of named blocks 2026-04-12 15:40:55 -05:00
Jeffrey C. Ollie 203895e3f7
decbkm: address review comments
* Don't alter Kitty keyboard protocol responses. Kitty does not support
  DECBKM so KKP doesn't take DECBKM into consideration.
* Make better use of the function key lookup to control what sequence is
  returned when backspace is pressed using the legacy encoding.
2026-04-12 15:40:54 -05:00
Jeffrey C. Ollie aea70a5f7c
core: implement backarrow key mode (DECBKM) - mode 67
This mode allows programs to modify the code that the `backspace`
key (backarrow key in DEC parlance) sends. If this mode is
`off`/`false`/`reset` (the default, the same as before this PR), we
send the byte `0x7f`. If this mode is `on`/`true`/`set` we send the
byte `0x08`.
2026-04-12 15:40:54 -05:00
Mitchell Hashimoto 94cd3da8bc
build: add ghostty-internal pkg-config modules (shared + static) (#12214)
## Summary
Mirror the `libghostty-vt-static` pkg-config pattern from #12210 for the
internal library.

- Add `ghostty-internal.pc` (shared, `-lghostty`) and
`ghostty-internal-static.pc` (static, direct archive reference) so
consumers can discover either variant via pkg-config
- Named `ghostty-internal` to distinguish from the public
`libghostty-vt` API
- Static module points at the platform-correct archive name
(`ghostty-static.lib` on Windows, `libghostty.a` elsewhere)
- pkg-config files are generated during shared builds and installed via
`GhosttyLib.install()`

## Test plan

- [x] `zig build` succeeds (default target)
- [x] `ghostty-internal.pc` and `ghostty-internal-static.pc` appear in
`zig-out/share/pkgconfig/`
- [x] Static `.pc` points at `ghostty-static.lib` (Windows) /
`libghostty.a` (Unix)
- [x] Shared `.pc` uses standard `-L -l` flags
- [x] Existing `libghostty-vt` pkg-config files are unaffected
2026-04-12 13:18:03 -07:00
Mitchell Hashimoto d2b79bea77
macOS: fix the arrow alignment of the secure input popover (#12249) 2026-04-12 13:16:15 -07:00
Mitchell Hashimoto 7f6d2a44b8
macOS: fix cannot rebind super+up and super+down (#12245)
Fix: #11989
Cause identified to: ab352b5af9
Original PR: #10003
Problem: I don't think it is OK to hard code the keybind like this at
all. Ghostty's config is flexible enough to achieve this.
Proposal: Revert the above commit via this PR.

@yasuf @bo2themax
2026-04-12 13:16:06 -07:00
Mitchell Hashimoto 032596442f
macOS: clean up duplicated declarations in SurfaceView_AppKit/UIKit (#12250)
Added a shared `OSSurfaceView` as the base class to share common
variables and functions across platforms.

Each commit contains a small change to move one or two variables or
functions to `OSSurfaceView`.
2026-04-12 13:15:52 -07:00
Lukas 53019991f7
macOS: fix the arrow alignment of the secure input popover 2026-04-12 16:04:41 +02:00
Lukas bf6fd4abe5
macOS: add `focusDidChange` & `sizeDidChange` placeholders to `OSSurfaceView` 2026-04-12 14:23:46 +02:00
Lukas 90ea604a7c
macOS: move `searchState` to `OSSurfaceView` 2026-04-12 14:23:46 +02:00
Lukas a541e23120
macOS: move `surface` to `OSSurfaceView` 2026-04-12 14:23:46 +02:00
Lukas 1665755a93
macOS: move `highlighted` to `OSSurfaceView` 2026-04-12 14:23:46 +02:00
Lukas 2efe851cda
macOS: move `readonly` to `OSSurfaceView` 2026-04-12 14:23:45 +02:00
Lukas 3834751aef
macOS: move `surfaceSize` to `OSSurfaceView` 2026-04-12 12:08:56 +02:00
Lukas 7c83561f9e
macOS: move `focusInstant` to `OSSurfaceView` 2026-04-12 12:07:22 +02:00
Lukas 56b505cbb0
macOS: move `keyTables` to `OSSurfaceView` 2026-04-12 12:06:28 +02:00
Lukas 19af8e9ce2
macOS: move `progressReport` to `OSSurfaceView` 2026-04-12 12:04:09 +02:00
Lukas 8b99c77bf7
macOS: update title comments 2026-04-12 12:02:59 +02:00
Lukas 619e12dc75
macOS: move `hoverUrl` to `OSSurfaceView` 2026-04-12 11:59:51 +02:00
Lukas 3936069297
macOS: move `healthy` and `error` to `OSSurfaceView` 2026-04-12 11:59:04 +02:00
Lukas d38301bb9f
macOS: move `cellSize` to `OSSurfaceView` 2026-04-12 11:58:04 +02:00
Lukas 46fef7718c
macOS: move `pwd` to `OSSurfaceView` 2026-04-12 11:57:15 +02:00
Lukas 8bd1aba40a
macOS: add shared OSSurfaceView 2026-04-12 11:54:16 +02:00
Mitchell Hashimoto 557de7c925
build: stop linking libc++ for utfcpp (#12239)
utfcpp is a header-only dependency, so its package wrapper does not need
to link the C++ standard library. Keep the empty static archive for
build integration, but stop adding an unnecessary libc++ dependency.
2026-04-11 14:55:11 -07:00
Mitchell Hashimoto 5e102c9dc7
build: stop linking libc++ for utfcpp
utfcpp is a header-only dependency, so its package wrapper does not
need to link the C++ standard library. Keep the empty static archive
for build integration, but stop adding an unnecessary libc++
dependency.
2026-04-11 14:44:05 -07:00
Mitchell Hashimoto fa2c3a1e60
pkg/highway: drop libc++ dependency from vendored hwy (#12238)
The vendored Highway package was being built with libc++ even though
Ghostty only uses its runtime target selection and dispatch support.
That pulled in extra C++ runtime baggage from upstream support files
such as abort, timer, print, and benchmark helpers.

Build Highway in HWY_NO_LIBCXX mode, only compile the target dispatch
sources we actually need, and compile Ghostty's SIMD translation units
with the same define so the header ABI stays consistent. Replace the
upstream abort implementation with a small local bridge that provides
Highway's Warn/Abort hooks and the target-query shim without depending
on libc++.

This keeps the Highway archive down to the dispatch pieces Ghostty uses
while preserving the existing dynamic dispatch behavior. The bridge is
documented so it is clear why Ghostty carries this small local
replacement.

We still depend on libc++ for other reasons, but I figure we should just
trim it down as needed. 😄
2026-04-11 14:41:55 -07:00
Mitchell Hashimoto 3e6a65f73f
pkg/highway: drop libc++ from vendored hwy
The vendored Highway package was being built with libc++ even though
Ghostty only uses its runtime target selection and dispatch support.
That pulled in extra C++ runtime baggage from upstream support files
such as abort, timer, print, and benchmark helpers.

Build Highway in HWY_NO_LIBCXX mode, only compile the target dispatch
sources we actually need, and compile Ghostty's SIMD translation units
with the same define so the header ABI stays consistent. Replace the
upstream abort implementation with a small local bridge that provides
Highway's Warn/Abort hooks and the target-query shim without depending
on libc++.

This keeps the Highway archive down to the dispatch pieces Ghostty
uses while preserving the existing dynamic dispatch behavior. The
bridge is documented so it is clear why Ghostty carries this small
local replacement.
2026-04-11 14:28:56 -07:00
Mitchell Hashimoto c36b458ad5
libghostty: add _get_multi to all _get APIs (#12236)
Replace the ImageInfo and PlacementInfo sized structs and their
associated .info enum variants with a new _get_multi pattern that
batches multiple enum+pointer pairs into a single call. This avoids
struct ABI concerns (field order, padding, alignment,
GHOSTTY_INIT_SIZED) while preserving the single-call-crossing
performance benefit for FFI and Cgo callers.

Each _get_multi function takes an array of enum keys, an array of output
pointers, and an optional out_written parameter that reports how many
values were successfully written before any error. This applies
uniformly to all _get APIs: terminal_get, cell_get, row_get,
render_state_get, render_state_row_get, render_state_row_cells_get,
kitty_graphics_image_get, and kitty_graphics_placement_get.

The C example is updated to use compound-literal _get_multi calls, and
tests cover both success and error paths for every new function.
2026-04-11 12:56:49 -07:00
Mitchell Hashimoto abf1332737
macOS: fix memory leak of TerminalController (#12237)
Regression of #12119, this memory leak affects new tabs, since the
terminal controller is not deallocated correctly, hitting `cmd+t` will
create a new window with two tabs, but only one actually contains usable
surface.

You can reproduce by:
1. Quit and Reopen Ghostty
2. Open a new window if no window is created (initial-window = false)
3. Close the window
4. Hit `cmd+t`
2026-04-11 12:51:53 -07:00
Mitchell Hashimoto 2c1dad790b
libghostty: add _get_multi to all _get APIs
Replace the ImageInfo and PlacementInfo sized structs and their
associated .info enum variants with a new _get_multi pattern that
batches multiple enum+pointer pairs into a single call. This avoids
struct ABI concerns (field order, padding, alignment, GHOSTTY_INIT_SIZED)
while preserving the single-call-crossing performance benefit for FFI
and Cgo callers.

Each _get_multi function takes an array of enum keys, an array of
output pointers, and an optional out_written parameter that reports
how many values were successfully written before any error. This
applies uniformly to all _get APIs: terminal_get, cell_get, row_get,
render_state_get, render_state_row_get, render_state_row_cells_get,
kitty_graphics_image_get, and kitty_graphics_placement_get.

The C example is updated to use compound-literal _get_multi calls,
and tests cover both success and error paths for every new function.
2026-04-11 12:51:36 -07:00
Lukas 650cd96646
macOS: fix memory leak of TerminalController
Regression of #12119, this memory leak affects new tabs, since the terminal controller is not deallocated correctly. Hitting `cmd+t` will create a new window with two tabs, but only one actually contains usable surface.

You can reproduce by:
1. Quit and Reopen Ghostty
2. Open a new window if no window is created (initial-window = false)
3. Close the window
4. Hit `cmd+t`
2026-04-11 21:20:16 +02:00
Alessandro De Blasis 19bf63ab71
test/windows: update README for ghostty-internal.dll rename
Match the dll filename rename so the copy/run instructions stay
accurate.
2026-04-11 03:02:08 +02:00
Alessandro De Blasis 935b08acea
test/windows: load ghostty-internal.dll in CRT init reproducer
The internal glue DLL was renamed from ghostty.dll to
ghostty-internal.dll. Update the LoadLibraryA call and the comment
block so this regression test still exercises the right artifact.
2026-04-11 03:01:12 +02:00
Alessandro De Blasis 1988ac94d4
build: point ghostty-internal pkg-config files at direct paths
Switch the shared ghostty-internal.pc Libs: line from -lghostty to a
direct ${libdir}/<file> path, matching what the -static module already
does. The name-per-OS helpers now emit:

  shared:  ghostty-internal.dll (Windows) / ghostty-internal.so (other)
  static:  ghostty-internal-static.lib (Windows) / ghostty-internal.a

Direct paths sidestep the GNU-ld -l<name> search template, which
expects libghostty-internal.so/.a on Unix - we drop the lib prefix to
match the ghostty-internal pkg-config module name.

Also update the LipoStep out_name for the macOS universal static
archive to ghostty-internal.a for consistency.
2026-04-11 03:00:39 +02:00
Alessandro De Blasis 4fd16ef9bc
build: install ghostty-internal dll/static with new names
Rename the internal library's install names to match the new
ghostty-internal pkg-config module convention:

  ghostty.dll          -> ghostty-internal.dll
  ghostty-static.lib   -> ghostty-internal-static.lib
  libghostty.so        -> ghostty-internal.so
  libghostty.a         -> ghostty-internal.a

This is the glue library between Ghostty's app shells and the GUI
core, historically (mis)named "libghostty". It is not the public
libghostty-vt API.
2026-04-11 02:59:50 +02:00
Mitchell Hashimoto 7421b4b13f
libghostty: add convenience accessors for kitty graphics (#12229)
Add three sized structs that let callers fetch all image, placement, or
rendering metadata in a single call instead of many individual queries.
This is an optimization for environments with high per-call overhead
such as FFI or Cgo.

GhosttyKittyGraphicsImageInfo is returned via image_get() with the new
GHOSTTY_KITTY_IMAGE_DATA_INFO data kind. It bundles id, number, width,
height, format, compression, data pointer, and data length.

GhosttyKittyGraphicsPlacementInfo is returned via placement_get() with
the new GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO data kind. It bundles
image id, placement id, virtual flag, offsets, source rect, columns,
rows, and z-index.

GhosttyKittyGraphicsPlacementRenderInfo is returned by the new
ghostty_kitty_graphics_placement_render_info() function, which combines
pixel size, grid size, viewport position, and resolved source rectangle.
This one requires image and terminal handles so it does not fit the
existing _get() pattern and is a dedicated function.

All three use the sized-struct ABI pattern with GHOSTTY_INIT_SIZED for
forward compatibility.
2026-04-10 14:26:28 -07:00
Mitchell Hashimoto 3295bf40a7
libghostty: add convenience accessors for kitty graphics
Add three sized structs that let callers fetch all image, placement,
or rendering metadata in a single call instead of many individual
queries. This is an optimization for environments with high per-call
overhead such as FFI or Cgo.

GhosttyKittyGraphicsImageInfo is returned via image_get() with the
new GHOSTTY_KITTY_IMAGE_DATA_INFO data kind. It bundles id, number,
width, height, format, compression, data pointer, and data length.

GhosttyKittyGraphicsPlacementInfo is returned via placement_get()
with the new GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO data kind.
It bundles image id, placement id, virtual flag, offsets, source
rect, columns, rows, and z-index.

GhosttyKittyGraphicsPlacementRenderInfo is returned by the new
ghostty_kitty_graphics_placement_render_info() function, which
combines pixel size, grid size, viewport position, and resolved
source rectangle. This one requires image and terminal handles so
it does not fit the existing _get() pattern and is a dedicated
function.

All three use the sized-struct ABI pattern with GHOSTTY_INIT_SIZED
for forward compatibility.
2026-04-10 14:16:24 -07:00
Jeffrey C. Ollie d3ce8926b9
build: skip ghostty-test graph when building libghostty-vt (#12224)
Fixes #12151

When `emit_lib_vt` is true, the `// Tests` block was still
evaluated, pulling in the full ghostty-test dependency graph
(freetype, zlib, dcimgui, etc.). This causes the Nix
`libghostty-vt` package to fail when `doCheck` is enabled,
since those system libraries aren't available in the sandbox.

Guard the block with `if (!config.emit_lib_vt)`, following
the existing pattern at line 179.
2026-04-10 13:41:11 -05:00
Mitchell Hashimoto c34901dddb
libghostty: add log callback configuration (#12227)
In C ABI builds, the Zig std.log default writes to stderr which is not
appropriate for a library. Override std_options.logFn with a custom sink
that dispatches to an embedder-provided callback, or silently discards
when none is registered.

Add GHOSTTY_SYS_OPT_LOG to ghostty_sys_set() following the existing
decode_png pattern. The callback receives the log level as a
GhosttySysLogLevel enum, scope and message as separate byte slices,
giving embedders full control over formatting and routing.

Export ghostty_sys_log_stderr as a built-in convenience callback that
writes to stderr using std.debug.lockStderrWriter for thread-safe
output. Embedders who want the old behavior can install it at startup
with a single ghostty_sys_set call.
2026-04-10 11:03:18 -07:00
Mitchell Hashimoto aa6943da37
libghostty: add log callback configuration
In C ABI builds, the Zig std.log default writes to stderr which is
not appropriate for a library. Override std_options.logFn with a
custom sink that dispatches to an embedder-provided callback, or
silently discards when none is registered.

Add GHOSTTY_SYS_OPT_LOG to ghostty_sys_set() following the existing
decode_png pattern. The callback receives the log level as a
GhosttySysLogLevel enum, scope and message as separate byte slices,
giving embedders full control over formatting and routing.

Export ghostty_sys_log_stderr as a built-in convenience callback that
writes to stderr using std.debug.lockStderrWriter for thread-safe
output. Embedders who want the old behavior can install it at startup
with a single ghostty_sys_set call.
2026-04-10 10:52:45 -07:00
Mitchell Hashimoto 7127abfe28
cmake: add ghostty_vt_add_target() for cross-compilation (#12212)
Add a ghostty_vt_add_target() CMake function that lets downstream
projects build libghostty-vt for a specific Zig target triple. The
function encapsulates zig discovery, build-type-to-optimize mapping, the
zig build invocation, and output path conventions so consumers do not
need to duplicate any of that logic. It creates named IMPORTED targets
(e.g. ghostty-vt-static-linux-amd64) that work alongside the existing
native ghostty-vt and ghostty-vt-static targets.

The build-type mapping is factored into a shared _GHOSTTY_ZIG_OPT_FLAG
variable used by both the native build and the new function.

A new example/c-vt-cmake-cross/ demonstrates end-to-end cross-
compilation using zig cc as the C compiler, auto-detecting a cross
target based on the host OS.
2026-04-10 08:00:03 -07:00
ghostty-vouch[bot] b5d54d8f51
Update VOUCHED list (#12225)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12223#discussioncomment-16518906)
from @jcollie.

Vouch: @kataokatsuki

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-10 14:31:37 +00:00
Alessandro De Blasis dd04856482
build: add ghostty-internal pkg-config modules (shared + static) 2026-04-10 16:12:23 +02:00
Mitchell Hashimoto f2e299fb46
cmake: add ghostty_vt_add_target() for cross-compilation
Add a ghostty_vt_add_target() CMake function that lets downstream
projects build libghostty-vt for a specific Zig target triple. The
function encapsulates zig discovery, build-type-to-optimize mapping,
the zig build invocation, and output path conventions so consumers
do not need to duplicate any of that logic. It creates named IMPORTED
targets (e.g. ghostty-vt-static-linux-amd64) that work alongside the
existing native ghostty-vt and ghostty-vt-static targets.

The build-type mapping is factored into a shared _GHOSTTY_ZIG_OPT_FLAG
variable used by both the native build and the new function.

The static library targets now propagate c++ as a link dependency on
non-Windows platforms, fixing link failures when consumers use static
linking with the default SIMD-enabled build.

A new example/c-vt-cmake-cross/ demonstrates end-to-end cross-
compilation using zig cc as the C compiler, auto-detecting a cross
target based on the host OS.
2026-04-10 06:52:09 -07:00
kataokatsuki 85be3ca2c1 build: skip ghostty-test graph when building libghostty-vt
Fixes #12151
2026-04-10 22:41:16 +09:00
Mitchell Hashimoto 19b0ed2bdf
macOS: double click title to enlarge window (#12219)
Previously with `macos-titlebar-style = tabs`, double clicking title
would do nothing
2026-04-10 06:18:11 -07:00
Mitchell Hashimoto d51e94f7eb
macOS: fix tab title editor frame update during winding resizing (#12220)
https://github.com/user-attachments/assets/69bee4f9-e3e1-4dc7-8e9c-c395572d2dbf
2026-04-10 06:17:35 -07:00
Lukas 41c872c1f4
macOS: fix tab title editor frame update during winding resizing 2026-04-10 13:57:09 +02:00
Lukas e7f58ad72e
macOS: double click title to enlarge window
Previously with `macos-titlebar-style	= tabs`, double clicking title will do nothing
2026-04-10 13:41:53 +02:00
ghostty-vouch[bot] 1348e04626
Update VOUCHED list (#12216)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12213#discussioncomment-16512677)
from @pluiedev.

Vouch: @otomn

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-10 06:52:01 +00:00
Mitchell Hashimoto 48a01b8bd5
build: add libghostty-vt-static pkg-config module (#12210)
Keep libghostty-vt.pc as the shared/default pkg-config module so
`pkg-config --static libghostty-vt` continues to emit the historical
`-lghostty-vt` flags. This preserves the old behavior for consumers that
still want it, even though that form remains ambiguous on macOS when
both the dylib and archive are installed in the same directory.

Add a separate libghostty-vt-static.pc module for consumers that need an
unambiguous static link. Its `Libs:` entry points directly at the
installed archive so macOS does not resolve the request to the dylib.

Update the Nix packaging to rewrite the new static module into the `dev`
output, use it in the static-link smoke test, and add a compatibility
check that covers both pkg-config entry points.
2026-04-09 20:38:03 -07:00
Mitchell Hashimoto a82e156925
build: add libghostty-vt-static pkg-config module
Keep libghostty-vt.pc as the shared/default pkg-config module so
`pkg-config --static libghostty-vt` continues to emit the historical
`-lghostty-vt` flags. This preserves the old behavior for consumers
that still want it, even though that form remains ambiguous on macOS
when both the dylib and archive are installed in the same directory.

Add a separate libghostty-vt-static.pc module for consumers that need
an unambiguous static link. Its `Libs:` entry points directly at the
installed archive so macOS does not resolve the request to the dylib.

Update the Nix packaging to rewrite the new static module into the `dev`
output, use it in the static-link smoke test, and add a compatibility
check that covers both pkg-config entry points.
2026-04-09 20:27:30 -07:00
Mitchell Hashimoto 1a5bfbd87c
build: sanitize all invalid chars in branch name for version (#12206)
Fixes #11990

Previously only slashes were replaced with hyphens in the branch name
used as the semver pre-release identifier. Branch names containing dots
(e.g. dependabot branches like
"cachix/install-nix-action-31.10.4") would cause an InvalidVersion error
because std.SemanticVersion only allows alphanumeric characters and
hyphens in pre-release identifiers.

Replace all non-alphanumeric, non-hyphen characters instead of only
slashes.
2026-04-09 13:15:14 -07:00
Mitchell Hashimoto ad9225a4ca
build: sanitize all invalid chars in branch name for version
Fixes #11990

Previously only slashes were replaced with hyphens in the branch
name used as the semver pre-release identifier. Branch names
containing dots (e.g. dependabot branches like
"cachix/install-nix-action-31.10.4") would cause an InvalidVersion
error because std.SemanticVersion only allows alphanumeric
characters and hyphens in pre-release identifiers.

Replace all non-alphanumeric, non-hyphen characters instead of
only slashes.
2026-04-09 13:09:01 -07:00
Mitchell Hashimoto 4cfbdaf8aa
build(deps): bump cachix/install-nix-action from 31.10.3 to 31.10.4 (#12196)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.10.3 to 31.10.4.
<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.10.4</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.34.4 -&gt; 2.34.5 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/273">cachix/install-nix-action#273</a>
<strong>[SECURITY]</strong> Fixes a root privilege escalation
vulnerability via sandbox escape <a
href="https://github.com/NixOS/nix/security/advisories/GHSA-g3g9-5vj6-r3gj">https://github.com/NixOS/nix/security/advisories/GHSA-g3g9-5vj6-r3gj</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31.10.3...v31.10.4">https://github.com/cachix/install-nix-action/compare/v31.10.3...v31.10.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="616559265b"><code>6165592</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/273">#273</a>
from cachix/create-pull-request/patch</li>
<li><a
href="b9f700df68"><code>b9f700d</code></a>
nix: 2.34.4 -&gt; 2.34.5</li>
<li>See full diff in <a
href="96951a368b...616559265b">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.10.3&new-version=31.10.4)](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-04-09 13:01:53 -07:00
dependabot[bot] 1855b3efcc
build(deps): bump cachix/install-nix-action from 31.10.3 to 31.10.4
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.10.3 to 31.10.4.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](96951a368b...616559265b)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-09 00:15:52 +00:00
Austin Drummond 3828660382
Merge branch 'main' into fix/keybind 2026-04-08 19:48:57 -04:00
Mitchell Hashimoto 28972454c0
libghostty-vt: nix package updates and more nix tests (#12152) 2026-04-08 11:00:49 -07:00
Mitchell Hashimoto e740f6fc11
macOS: fix icon style not updating properly on Tahoe (#12180)
This is a regression from #9983. When resetting to default, we shouldn't
use the representation of the icon, which will prevent the icon from
updating after system settings change.

1. Delete `macos-icon` config if it exists and reload.
2. Go to **System Settings -> Appearance** and change **Icon & widget
style** to any one other than Default, and observe the app icon.


<img width="228" height="179" alt="image"
src="https://github.com/user-attachments/assets/e53274f8-b679-4d6f-8e0b-edfd7d17811d"
/>

> A temporary workaround to this issue is to reload the config.

This pr resets the `NSDockTile.contentView`, which will let AppKit
revert back to `Ghostty.icon`.



https://github.com/user-attachments/assets/06ab0519-225b-45e1-85a5-a22832a36177
2026-04-08 10:59:57 -07:00
Mitchell Hashimoto a1c6f800c5
libghostty: add MAX_VALUE sentinels to all C enums for 32-bit sizing (#12189)
Pre-C23, the C standard allows compilers to choose any integer type
that can represent all enum values, so small enums could be backed
by char or short. This breaks ABI compatibility with the Zig side,
which backs these enums with c_int.

Define GHOSTTY_ENUM_MAX_VALUE as INT_MAX in types.h and add it as
the last entry in every enum in include/ghostty/vt/. This forces
the compiler to use int as the backing type, matching c_int on all
targets. INT_MAX is used rather than a fixed constant because enum
constants must be representable as int; values above INT_MAX are a
constraint violation in standard C.

Document this convention in AGENTS.md.
2026-04-08 10:56:52 -07:00
Mitchell Hashimoto f282f13a21
libghostty: add GHOSTTY_ENUM_TYPED and GHOSTTY_ENUM_MAX_VALUE to all C enums
GHOSTTY_ENUM_TYPED: expands to `: int` on C23 (where explicit enum
underlying types are supported), empty on older standards.
2026-04-08 10:43:15 -07:00
Mitchell Hashimoto 9897d6caba
libghostty: add GHOSTTY_ENUM_MAX_VALUE sentinel to all C enums
Pre-C23, the C standard allows compilers to choose any integer type
that can represent all enum values, so small enums could be backed
by char or short. This breaks ABI compatibility with the Zig side,
which backs these enums with c_int.

Define GHOSTTY_ENUM_MAX_VALUE as INT_MAX in types.h and add it as
the last entry in every enum in include/ghostty/vt/. This forces
the compiler to use int as the backing type, matching c_int on all
targets. INT_MAX is used rather than a fixed constant because enum
constants must be representable as int; values above INT_MAX are a
constraint violation in standard C.

Document this convention in AGENTS.md.
2026-04-08 10:34:52 -07:00
Lukas 363cb9560e
macOS: fix icon style not updating on Tahoe 2026-04-08 13:12:37 +02:00
ghostty-vouch[bot] 853183e911
Update VOUCHED list (#12165)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12164#discussioncomment-16477806)
from @jcollie.

Vouch: @MoonMao42

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-07 14:58:24 +00:00
Mitchell Hashimoto 0043e665f5
macos: cancel deferred tab presentation on close (#12119)
The 👻 Ghost Tab Issue


https://github.com/user-attachments/assets/cb91cd85-4a08-4c16-9efb-1a9ab30fc2bc

Previous failure scenario (User perspective):

1. Open a new tab
2. Instantly trigger close other tabs (eg. through custom user keyboard
shortcut)
3. Now you will see an empty Ghost Tab (Only a window bar with empty
content)

The previous failure mode is:

1. Create a tab or window now in `newTab(...)` / `newWindow(...)`.
2. Queue its initial show/focus work with `DispatchQueue.main.async`.
3. Close that tab or window with `closeTabImmediately()` /
`closeWindowImmediately()` before the queued callback runs.
4. The queued callback still runs anyway and calls `showWindow(...)` /
`makeKeyAndOrderFront(...)` on stale state.
5. The tab can be resurrected as a half-closed blank ghost tab.

The fix:

- Store deferred presentation work in a cancellable DispatchWorkItem and
cancel it from the close paths before AppKit finishes tearing down the
tab or window.
- This prevents the stale show/focus callback from running after close.

## AI Usage

I used GPT 5.4 to find the initial issue and fix it. I cleaned up and
narrowed down the commit afterwards.

-----

Additional Notes:

I use `cmd+o` to `close_tab:other`

https://github.com/jamylak/dotfiles/blob/main/ghostty/config#L106C1-L106C34

Try it for your self if you want to reproduce, just do a quick `cmd+t`
`cmd+o` and you will see
2026-04-07 05:41:23 -07:00
Mitchell Hashimoto 2b62e3c82a
libghostty-vt: add semver pre info to build info (#12150) 2026-04-07 05:40:52 -07:00
Mitchell Hashimoto 140ddd9770
build(deps): bump flatpak/flatpak-github-actions from 6.6 to 6.7 (#12154)
Bumps
[flatpak/flatpak-github-actions](https://github.com/flatpak/flatpak-github-actions)
from 6.6 to 6.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/flatpak/flatpak-github-actions/releases">flatpak/flatpak-github-actions's
releases</a>.</em></p>
<blockquote>
<h2>v6.7</h2>
<ul>
<li>Bump action to node 24</li>
<li>Add the git commit as the ostree commit subject</li>
<li>Allow configurable build/repo/state dirs</li>
<li>Add keep-build-dirs flag</li>
<li>Update action dependencies</li>
<li>Improvements to contributing docs</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="401fe28a83"><code>401fe28</code></a>
flatpak-builder: Add keepBuildDirs flag (<a
href="https://redirect.github.com/flatpak/flatpak-github-actions/issues/229">#229</a>)</li>
<li><a
href="fc05c5ecc1"><code>fc05c5e</code></a>
action: Bump to node 24 (<a
href="https://redirect.github.com/flatpak/flatpak-github-actions/issues/243">#243</a>)</li>
<li><a
href="ce5753fa41"><code>ce5753f</code></a>
Some doc improvements (<a
href="https://redirect.github.com/flatpak/flatpak-github-actions/issues/245">#245</a>)</li>
<li><a
href="fef33cbb5c"><code>fef33cb</code></a>
Update dependencies (<a
href="https://redirect.github.com/flatpak/flatpak-github-actions/issues/244">#244</a>)</li>
<li><a
href="0a63139699"><code>0a63139</code></a>
feat(flatpak-builder): Allow configurable build/repo/state dirs (<a
href="https://redirect.github.com/flatpak/flatpak-github-actions/issues/237">#237</a>)</li>
<li><a
href="ad1b66ed72"><code>ad1b66e</code></a>
flatpak-builder: Add the git commit as the ostree commit subject</li>
<li>See full diff in <a
href="92ae9851ad...401fe28a83">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=flatpak/flatpak-github-actions&package-manager=github_actions&previous-version=6.6&new-version=6.7)](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-04-07 05:39:32 -07:00
Jeffrey C. Ollie ee236e9a73
chore: removed superfluous word (#12160)
I noticed a likely unintentional "actually" in the README. Nothing
fancy, just updating the documentation.
2026-04-06 23:57:23 -05:00
Jeffrey C. Ollie c2e2a3b7f9
flake: make building package list more flexible 2026-04-06 23:41:24 -05:00
Jeffrey C. Ollie 28c75e2c61
libghostty-vt: fix nix package name 2026-04-06 23:41:04 -05:00
Jeffrey C. Ollie 1d61e27351
libghostty-vt: disable macOS CI nix build 2026-04-06 23:40:45 -05:00
Jeffrey C. Ollie 4ae155be59
flake: ensure that packages don't get lost 2026-04-06 23:22:56 -05:00
tbrundige 95fb39ae0c chore: removed superfluous word 2026-04-06 22:10:12 -06:00
Jeffrey C. Ollie dedc3fce86
libghostty-vt: build nix package on all platforms 2026-04-06 22:51:56 -05:00
Jeffrey C. Ollie 93a4470458
libghostty-vt: require build-nix-macos 2026-04-06 22:51:41 -05:00
Jeffrey C. Ollie 1322d64534
libghostty-vt: nix package updates and more nix tests 2026-04-06 22:41:57 -05:00
ghostty-vouch[bot] a1e75daef8
Update VOUCHED list (#12158)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12157#discussioncomment-16470907)
from @jcollie.

Vouch: @tbrundige

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-07 03:31:48 +00:00
ghostty-vouch[bot] 8f376d84b4
Update VOUCHED list (#12156)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12155#discussioncomment-16470483)
from @jcollie.

Vouch: @KieranCanter

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-07 02:38:42 +00:00
dependabot[bot] 5c45484a71
build(deps): bump flatpak/flatpak-github-actions from 6.6 to 6.7
Bumps [flatpak/flatpak-github-actions](https://github.com/flatpak/flatpak-github-actions) from 6.6 to 6.7.
- [Release notes](https://github.com/flatpak/flatpak-github-actions/releases)
- [Commits](92ae9851ad...401fe28a83)

---
updated-dependencies:
- dependency-name: flatpak/flatpak-github-actions
  dependency-version: '6.7'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-07 00:15:26 +00:00
Jeffrey C. Ollie 06340cd3f0
libghostty-vt: add semver pre info to build info 2026-04-06 17:17:30 -05:00
Mitchell Hashimoto da835757b0
prettier: ignore swift outputs 2026-04-06 14:54:23 -07:00
Mitchell Hashimoto c12a0e395d
libghostty: build universal xcframework and release it on tip (#12149)
This produces a `ghostty-vt.xcframework` for `zig build -Demit-lib-vt`
when the host is macOS and the target is Apple platforms. Our CI has
been updated to release this via tip channels (GH releases and our blob
storage), too.

The xcframework contains binaries for macOS Universal (x86_64 +
aarch64), iOS, and iOS simulator.

I've added a Swift example we run in CI to verify this works. Users can
also drag and drop the XCFramework directly into Xcode.

## Example

```swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "swift-vt-xcframework",
    platforms: [.macOS(.v13)],
    targets: [
        .executableTarget(
            name: "swift-vt-xcframework",
            dependencies: ["GhosttyVt"],
            path: "Sources",
            linkerSettings: [
                .linkedLibrary("c++"),
            ]
        ),
        .binaryTarget(
            name: "GhosttyVt",
            path: "../../zig-out/lib/ghostty-vt.xcframework"
        ),
    ]
)
```

```swift
import GhosttyVt

// Create a terminal with a small grid
var terminal: GhosttyTerminal?
var opts = GhosttyTerminalOptions(
    cols: 80,
    rows: 24,
    max_scrollback: 0
)
let result = ghostty_terminal_new(nil, &terminal, opts)
guard result == GHOSTTY_SUCCESS, let terminal else {
    fatalError("Failed to create terminal")
}

// Write some VT-encoded content
let text = "Hello from \u{1b}[1mSwift\u{1b}[0m via xcframework!\r\n"
text.withCString { ptr in
    ghostty_terminal_vt_write(terminal, ptr, strlen(ptr))
}

// Format the terminal contents as plain text
var fmtOpts = GhosttyFormatterTerminalOptions()
fmtOpts.size = MemoryLayout<GhosttyFormatterTerminalOptions>.size
fmtOpts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN
fmtOpts.trim = true

var formatter: GhosttyFormatter?
let fmtResult = ghostty_formatter_terminal_new(nil, &formatter, terminal, fmtOpts)
guard fmtResult == GHOSTTY_SUCCESS, let formatter else {
    fatalError("Failed to create formatter")
}

var buf: UnsafeMutablePointer<UInt8>?
var len: Int = 0
let allocResult = ghostty_formatter_format_alloc(formatter, nil, &buf, &len)
guard allocResult == GHOSTTY_SUCCESS, let buf else {
    fatalError("Failed to format")
}

print("Plain text (\(len) bytes):")
print(String(cString: buf))

ghostty_free(nil, buf, len)
ghostty_formatter_free(formatter)
ghostty_terminal_free(terminal)
```
2026-04-06 14:53:39 -07:00
Mitchell Hashimoto 445e1945da
ci: upload lib-vt source tarball to R2
Add R2 upload steps to the source-tarball-lib-vt job in the tip
release workflow, matching the pattern used by the xcframework
job. The tarball is uploaded to the ghostty-tip R2 bucket keyed
by commit hash, making it available at
tip.files.ghostty.org/<commit>/libghostty-vt-source.tar.gz.
2026-04-06 14:53:24 -07:00
Mitchell Hashimoto 249aee7010
example/swift-vt-xcframework: fix buffer overflow 2026-04-06 14:50:36 -07:00
Mitchell Hashimoto 9b281cde43
build: add iOS slices to lib-vt xcframework
Add iOS device and simulator slices to the xcframework, gated on
SDK availability via std.zig.LibCInstallation.findNative. Refactor
AppleLibs from a struct with named fields to an EnumMap keyed by
ApplePlatform so that adding new platforms only requires extending
the enum and its sdk_platforms table.

tvOS, watchOS, and visionOS are listed as not yet supported due to
Zig stdlib limitations (missing PATH_MAX, mcontext fields).
2026-04-06 14:41:11 -07:00
Mitchell Hashimoto e1a0e40ec4
build: skip xcframework when cross-compiling
Gate the xcframework build on the host being macOS in addition to
the target, since xcodebuild is only available on macOS.
2026-04-06 14:25:04 -07:00
Mitchell Hashimoto 90b706b977
ci: publish lib-vt xcframework in tip releases
Add a build-lib-vt-xcframework job to the release-tip workflow that
builds the universal xcframework with ReleaseFast, zips it, signs
it with minisign, and uploads it to both the GitHub Release and R2
blob storage. Consumers can pull the xcframework zip from the tip
release or by commit hash from tip.files.ghostty.org.
2026-04-06 14:22:57 -07:00
Mitchell Hashimoto 764ff18b8e
ci: add Swift example builds on macOS
Auto-discover Swift examples via example/*/Package.swift alongside
the existing zig and cmake discovery. The new build-examples-swift
job runs on macOS, builds the xcframework with zig build -Demit-lib-vt,
then runs swift run in each example directory to verify the
xcframework links and functions correctly end-to-end.
2026-04-06 14:17:34 -07:00
Mitchell Hashimoto f567f7f46d
build: add GhosttyVt module map to xcframework and Swift example
The xcframework now generates its own headers directory with a
GhosttyVt module map instead of reusing include/ directly, which
contains the GhosttyKit module map for the macOS app. The generated
directory copies the ghostty headers and adds a module.modulemap
that exposes ghostty/vt.h as the umbrella header.

A new swift-vt-xcframework example demonstrates consuming the
xcframework from a Swift Package. It creates a terminal, writes
VT sequences, and formats the output as plain text, verifying
the full round-trip works with swift build and swift run.
2026-04-06 14:14:52 -07:00
Mitchell Hashimoto 05fb57dd40
build: emit xcframework for libghostty-vt on macOS
On Darwin targets, the build now automatically produces a universal
(arm64 + x86_64) XCFramework at lib/ghostty-vt.xcframework under
the install prefix. This bundles the fat static library with headers
so consumers using Xcode or Swift PM can link libghostty-vt directly.
2026-04-06 14:07:19 -07:00
Mitchell Hashimoto f7a9e313cd
libghostty-vt: allow version to be customized from the Zig build command (#12104) 2026-04-06 13:45:31 -07:00
Mitchell Hashimoto a977822b58
update kitty graphics docs 2026-04-06 13:09:43 -07:00
Mitchell Hashimoto fdb6e3d2c8
libghostty: add z-layer filtering, viewport positioning, and source rects for kitty graphics placements (#12147)
Based on the Ghostling implementation, these are APIs that will help
other implementors:

**Z-layer filtering.** The placement iterator now supports a
configurable layer filter via a new
`ghostty_kitty_graphics_placement_iterator_set()` option API. When a
layer is set, `ghostty_kitty_graphics_placement_next()` skips placements
whose z-index doesn't match the requested layer. The three layers follow
the kitty protocol z-index conventions (below background, below text,
above text) and map directly to distinct rendering passes. Default is
`ALL` (no filtering, existing behavior).

**Viewport-relative positioning.**
`ghostty_kitty_graphics_placement_viewport_pos()` converts a placement's
internal pin to viewport-relative grid coordinates. The row value can be
negative for placements that have partially scrolled above the viewport.
Returns `GHOSTTY_NO_VALUE` when the placement is entirely off-screen or
is a virtual (unicode placeholder) placement, so the renderer can skip
it without extra math.

**Source rectangle resolution.**
`ghostty_kitty_graphics_placement_source_rect()` applies kitty protocol
semantics (0 = full image dimension) and clamps to image bounds,
returning pixel coordinates ready for texture sampling.

## New APIs

| Function | Description |
|----------|-------------|
| `ghostty_kitty_graphics_placement_iterator_set` | Set an option on a
placement iterator (currently: z-layer filter) |
| `ghostty_kitty_graphics_placement_viewport_pos` | Get
viewport-relative grid position of the current placement |
| `ghostty_kitty_graphics_placement_source_rect` | Get the resolved
source rectangle in pixels for the current placement |

## New Types

| Type | Description |
|------|-------------|
| `GhosttyKittyPlacementLayer` | Z-layer classification: `ALL`,
`BELOW_BG`, `BELOW_TEXT`, `ABOVE_TEXT` |
| `GhosttyKittyGraphicsPlacementIteratorOption` | Settable iterator
options (currently: `LAYER`) |
2026-04-06 13:02:27 -07:00
Mitchell Hashimoto 65e3265e3c
libghostty: fix kitty graphics test failures
Fix three categories of test bugs in the kitty graphics C API tests:

The placement iterator reset in getTyped was clobbering the
layer_filter field when reinitializing the iterator struct,
causing the layer filter test to see unfiltered placements.
Preserve layer_filter across resets.

The viewport position tests were not accounting for the default
cursor_movement=after behavior of the kitty display command,
which calls index() for each row of the placement before the
test scroll sequence. Add C=1 to suppress cursor movement so
the scroll math in the tests is correct.

The source_rect tests used an 88-character all-A base64 payload
which decodes to 66 bytes, but a 4x4 RGBA image requires exactly
64 bytes. Fix the payload to use proper base64 padding (AA==).
2026-04-06 12:56:54 -07:00
Mitchell Hashimoto d712beff5b
libghostty: add resolved source rect for placements
Add ghostty_kitty_graphics_placement_source_rect which returns the
fully resolved and clamped source rectangle for a placement. This
applies kitty protocol semantics (width/height of 0 means full
image dimension) and clamps the result to the actual image bounds,
eliminating ~20 lines of protocol-aware logic from each embedder.
2026-04-06 12:37:13 -07:00
Mitchell Hashimoto b43d35b4d3
libghostty: add viewport-relative placement positioning
Add ghostty_kitty_graphics_placement_viewport_pos which converts a
placement's internal pin to viewport-relative grid coordinates.
The returned row can be negative when the placement's origin has
scrolled above the viewport, allowing embedders to compute the
correct destination rectangle for partially visible images.

Returns GHOSTTY_NO_VALUE only when the placement is completely
outside the viewport (bottom edge above the viewport or top edge
at or below the last row), so embedders do not need to perform
their own visibility checks. Partially visible placements always
return GHOSTTY_SUCCESS with their true signed coordinates.
2026-04-06 12:34:18 -07:00
Mitchell Hashimoto 66bfdf8e7a
libghostty: add z-layer filtered placement iterator
Add a placement_iterator_set function that configures iterator
properties via an enum, following the same pattern as other set
functions in the C API (e.g. render_state_set). The first settable
option is a z-layer filter.

The GhosttyKittyPlacementLayer enum classifies placements into three
layers based on kitty protocol z-index conventions: below background
(z < INT32_MIN/2), below text (INT32_MIN/2 <= z < 0), and above text
(z >= 0). The default is ALL which preserves existing behavior.

When a layer filter is set, placement_iterator_next automatically
skips non-matching placements, so embedders no longer need to
reimplement the z-index bucketing logic or iterate all placements
three times per frame just to filter by layer.
2026-04-06 12:24:18 -07:00
Mitchell Hashimoto 800cc64f1b
libghostty: C APIs for Kitty Graphics inspection (#12145)
This adds a C API for inspecting Kitty graphics image storage, images,
and placements from a terminal instance.

I think this is enough of the API surface area for a renderer to draw
images. But I'll have to add it to Ghostling to be sure.

## Example

```c
#include <stdint.h>
#include <stdio.h>
#include <ghostty/vt.h>

/* After creating a terminal and transmitting a Kitty graphics image... */

/* Get the kitty graphics storage from the terminal. */
GhosttyKittyGraphics graphics = NULL;
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS, &graphics);

/* Iterate over all placements. */
GhosttyKittyGraphicsPlacementIterator iter = NULL;
ghostty_kitty_graphics_placement_iterator_new(NULL, &iter);
ghostty_kitty_graphics_get(graphics,
    GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR, &iter);

while (ghostty_kitty_graphics_placement_next(iter)) {
  uint32_t image_id = 0;
  ghostty_kitty_graphics_placement_get(iter,
      GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID, &image_id);

  /* Look up the image and query its properties. */
  GhosttyKittyGraphicsImage image = ghostty_kitty_graphics_image(graphics, image_id);
  uint32_t width = 0, height = 0;
  GhosttyKittyImageFormat format = 0;
  ghostty_kitty_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_WIDTH, &width);
  ghostty_kitty_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_HEIGHT, &height);
  ghostty_kitty_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_FORMAT, &format);
  printf("image %u: %ux%u format=%d\n", image_id, width, height, format);

  /* Compute rendered pixel size and grid size. */
  uint32_t px_w, px_h, cols, rows;
  ghostty_kitty_graphics_placement_pixel_size(iter, image, terminal, &px_w, &px_h);
  ghostty_kitty_graphics_placement_grid_size(iter, image, terminal, &cols, &rows);
  printf("  rendered: %ux%u px, %ux%u cells\n", px_w, px_h, cols, rows);
}

ghostty_kitty_graphics_placement_iterator_free(iter);
```

## API

### Functions

| Function | Description |
|----------|-------------|
| `ghostty_kitty_graphics_get` | Query data from a kitty graphics
storage (e.g. placement iterator) |
| `ghostty_kitty_graphics_image` | Look up an image by its image ID |
| `ghostty_kitty_graphics_image_get` | Query image properties (ID,
dimensions, format, compression, pixel data) |
| `ghostty_kitty_graphics_placement_iterator_new` | Create a new
placement iterator |
| `ghostty_kitty_graphics_placement_iterator_free` | Free a placement
iterator |
| `ghostty_kitty_graphics_placement_next` | Advance the iterator to the
next placement |
| `ghostty_kitty_graphics_placement_get` | Query placement properties
(image ID, offsets, source rect, z-index, etc.) |
| `ghostty_kitty_graphics_placement_rect` | Compute the bounding grid
rectangle for a placement |
| `ghostty_kitty_graphics_placement_pixel_size` | Compute the rendered
pixel dimensions of a placement |
| `ghostty_kitty_graphics_placement_grid_size` | Compute the grid cell
dimensions of a placement |

### Types

| Type | Description |
|------|-------------|
| `GhosttyKittyGraphics` | Opaque handle to image storage (borrowed from
terminal) |
| `GhosttyKittyGraphicsImage` | Opaque handle to a single image |
| `GhosttyKittyGraphicsPlacementIterator` | Opaque handle to a placement
iterator |
| `GhosttyKittyGraphicsData` | Enum for `ghostty_kitty_graphics_get`
data kinds |
| `GhosttyKittyGraphicsImageData` | Enum for `ghostty_kitty_image_get`
data kinds |
| `GhosttyKittyGraphicsPlacementData` | Enum for
`ghostty_kitty_graphics_placement_get` data kinds |
| `GhosttyKittyImageFormat` | Image pixel format (RGB, RGBA, PNG, gray,
gray+alpha) |
| `GhosttyKittyImageCompression` | Image compression (none, zlib) |
2026-04-06 12:09:39 -07:00
Mitchell Hashimoto 6b94c2da26
libghostty: add ghostty_terminal_point_from_grid_ref
Add the inverse of ghostty_terminal_grid_ref(), converting a grid
reference back to coordinates in a requested coordinate system
(active, viewport, screen, or history). This wraps the existing
internal PageList.pointFromPin and is placed on the terminal API
since it requires terminal-owned PageList state to resolve the
top-left anchor for each coordinate system.

Returns GHOSTTY_NO_VALUE when the ref falls outside the requested
range, e.g. a scrollback ref cannot be expressed in active
coordinates.
2026-04-06 10:49:32 -07:00
Mitchell Hashimoto 20b7fe0e1d
libghostty: gate kitty graphics placement types on build option
The PlacementIterator, PlacementMap, and PlacementIteratorWrapper
types in the C API were unconditionally referencing
kitty_storage.ImageStorage, which transitively pulled in
Image.transmit_time (std.time.Instant). On wasm32-freestanding,
std.time.Instant requires posix.timespec which does not exist,
causing a compilation error.

Gate these types behind build_options.kitty_graphics, matching the
existing pattern used for KittyGraphics and ImageHandle. When
kitty graphics is disabled, they fall back to opaque/void types.
Add early-return guards to placement_iterator_new and
placement_iterator_free which directly operate on the wrapper
struct.
2026-04-06 10:30:57 -07:00
Mitchell Hashimoto fc9299a41d
libghostty: rename ghostty_kitty_image_get to ghostty_kitty_graphics_image_get
Rename the public API function to follow the consistent
ghostty_kitty_graphics_* naming convention used by the other
kitty graphics API symbols.
2026-04-06 10:14:59 -07:00
Mitchell Hashimoto 68a8cbb065
libghostty: fix expected format in image_get test
The test transmits an image with f=24 (24-bit RGB) but was asserting
that the format field equals .rgba (32-bit). Corrected the expectation
to .rgb to match the transmitted pixel format.
2026-04-06 10:09:24 -07:00
Mitchell Hashimoto 426dc40799
example: update c-vt-kitty-graphics to use new APIs 2026-04-06 10:07:34 -07:00
Mitchell Hashimoto 03a6eeda1d
libghostty: add placement pixel_size and grid_size, rename calculatedSize
Expose Placement.pixelSize() and Placement.gridSize() as new C API
functions ghostty_kitty_graphics_placement_pixel_size() and
ghostty_kitty_graphics_placement_grid_size(). Both take the placement
iterator, image handle, and terminal, returning their results via
out params.

Rename the internal Zig method from calculatedSize to pixelSize to
pair naturally with gridSize — one returns pixels, the other grid
cells. Updated all callers including the renderer.
2026-04-06 10:03:34 -07:00
Mitchell Hashimoto 714420409b
libghostty: add placement_rect and centralize opaque typedefs
Expose Placement.rect() from the Zig kitty graphics storage as a new
C API function ghostty_kitty_graphics_placement_rect(). It takes the
terminal, image handle, and a positioned placement iterator, and
writes the bounding grid rectangle into a GhosttySelection out param.
Virtual placements return GHOSTTY_NO_VALUE.

Move all opaque handle typedefs (GhosttyTerminal, GhosttyKittyGraphics,
GhosttyRenderState, GhosttySgrParser, GhosttyFormatter, GhosttyOsc*)
into types.h so they are available everywhere without circular includes
and Doxygen renders them in the correct @ingroup sections.
2026-04-06 09:58:32 -07:00
Mitchell Hashimoto 9ff4bb2df5
terminal/kitty: convert Format, Medium, Compression to lib.Enum
Convert the Transmission.Format, Transmission.Medium, and
Transmission.Compression types from plain Zig enums to lib.Enum so
they get a C-compatible backing type when building with c_abi. This
lets the C API layer reuse the types directly instead of maintaining
separate mirror enums.

Move Format.bpp() to a standalone Transmission.formatBpp() function
since lib.Enum types cannot have decls.

In the C API layer, rename kitty_gfx to kitty_storage and command to
kitty_cmd for clarity, and simplify the format/compression getters
to direct assignment now that the types are shared.
2026-04-06 09:31:43 -07:00
Mitchell Hashimoto 46a69ea63d
libghostty: add kitty graphics image lookup API
Add a GhosttyKittyGraphicsImage opaque type and API for looking up
images by ID and querying their properties. This complements the
existing placement iterator by allowing direct image introspection.

The new ghostty_kitty_graphics_image() function looks up an image by
its ID from the storage, returning a borrowed opaque handle. Properties
are queried via ghostty_kitty_image_get() using the new
GhosttyKittyGraphicsImageData enum, which exposes id, number, width,
height, format, compression, and a borrowed data pointer with length.

Format and compression are exposed as their own C enum types
(GhosttyKittyImageFormat and GhosttyKittyImageCompression) rather
than raw integers.
2026-04-06 09:27:51 -07:00
Mitchell Hashimoto 9033f6f8ce
libghostty: add kitty graphics placement iterator API
Add a C API for iterating over Kitty graphics placements via the
new GhosttyKittyGraphics opaque handle. The API follows the same
pattern as the render state row iterator: allocate an iterator with
ghostty_kitty_graphics_placement_iterator_new, populate it from a
graphics handle via ghostty_kitty_graphics_get with the
PLACEMENT_ITERATOR data kind, advance with
ghostty_kitty_graphics_placement_next, and query per-placement
fields with ghostty_kitty_graphics_placement_get.
2026-04-06 09:15:26 -07:00
Mitchell Hashimoto e89b2c88f3
libghostty: introduce the kitty graphics opaque type 2026-04-06 08:56:23 -07:00
Mitchell Hashimoto f65fb3d442
libghostty: expose Kitty image configs, decode png callback from C API (#12144)
This exposes the APIs necessary to enable Kitty image protocol parsing
and state from the C API.

* You can now set the PNG decoder via the `ghostty_sys_set` API.
* You can set Kitty image configs via `ghostty_terminal_set` API.
* An example showing this working has been added.
* **You cannot yet query Kitty images for metadata or rendering.** I'm
going to follow that up in a separate PR.
2026-04-06 08:46:21 -07:00
Mitchell Hashimoto 64340c62bf
example: add c-vt-kitty-graphics
Demonstrates the sys interface for Kitty Graphics Protocol PNG
support. The example installs a PNG decode callback via
ghostty_sys_set, creates a terminal with image storage enabled,
and sends an inline 1x1 PNG image through vt_write. Snippet
markers are wired up to the sys.h doxygen docs.
2026-04-06 08:05:29 -07:00
Mitchell Hashimoto d7fa92088c
libghostty: expose sys interface to C API
The terminal sys module provides runtime-swappable function pointers
for operations that depend on external implementations (e.g. PNG
decoding). This exposes that functionality through the C API via a
ghostty_sys_set() function, modeled after the ghostty_terminal_set()
enum-based option pattern.

Embedders can install a PNG decode callback to enable Kitty Graphics
Protocol PNG support. The callback receives a userdata pointer
(set via GHOSTTY_SYS_OPT_USERDATA) and a GhosttyAllocator that must
be used to allocate the returned pixel data, since the library takes
ownership of the buffer. Passing NULL clears the callback and
disables the feature.
2026-04-06 07:45:16 -07:00
Mitchell Hashimoto 8ae80892ba
macos: fix dock icon badge permission (#12133)
The previous version requested general notification permissions but
omitted the `.badge` option. Because the initial request was granted,
`settings.authorizationStatus` returns `.authorized`, leading the app to
believe it has full notification privileges when it actually lacks the
authority to update the dock icon badge.

Debug hint:
You can reset the notification settings by right-clicking on the app
name.
<img width="307" height="85" alt=""
src="https://github.com/user-attachments/assets/660cd332-eda6-45d6-8bfd-a6f9e28e21e8"
/>
2026-04-06 07:31:36 -07:00
Mitchell Hashimoto fd884bc532
macOS: force surface layout sync in updateOSView (#12143)
`updateOSView` assumed SwiftUI always propagates frame changes to the
scroll view. Under system load, this can be deferred, leaving the
surface rendering at stale dimensions. Check for size mismatch and mark
layout as needed.


<img width="1408" height="464" alt="ghostty_bug"
src="https://github.com/user-attachments/assets/3a6f81ff-9d02-4ffa-aded-e2eddc9f40a5"
/>

---
AI Disclosure: Used Claude Code for PR preparation.
2026-04-06 07:31:28 -07:00
Mitchell Hashimoto 3a52e0e3bd
libghostty: expose kitty image options via terminal set/get
Add four new terminal options for configuring Kitty graphics at runtime
through the C API: storage limit, and the three loading medium flags
(file, temporary file, shared memory).

The storage limit setter propagates to all initialized screens and
uses setLimit which handles eviction when lowering the limit. The
medium setters similarly propagate to all screens. Getters read from
the active screen. All options compile to no-ops or return no_value
when kitty graphics are disabled at build time.
2026-04-06 07:21:05 -07:00
Mitchell Hashimoto c9c3c701e2
terminal: make wuffs runtime-swappable, enable Kitty graphics for libvt (#12117)
This enables Kitty Graphics for `libghostty-vt` for the Zig API (C to
come next).

First, a note on security: by default, Kitty graphics will only allow
images transferred via the _direct_ medium (directly via the pty) and
will not allow file or shared memory based images. libghostty-vt
consumers need to manually opt-in via terminal init options or
`terminal.setKittyGraphicsLoadingLimits` to enable file-based things.
**This is so we're as secure as possible by default.**

Second, for PNG decoding, embedders must now set a global
runtime-callback at `ghostty.sys.decode_png`. If this is not set, PNG
formatted images are rejected. If this is set, then we'll use this to
decode and embedders can use any decoder they want.

There is no C API exposed yet to set this, so this is only for Zig to
start.

## Examples (Zig)

### Configuring Allowed Formats

```zig
var term = try Terminal.init(alloc, .{
    .cols = 80,
    .rows = 24,
    // Only allow direct (inline) image data, no file/shm access.
    // This is the default so you don't need to specify it.
    .kitty_image_loading_limits = .direct,
});
```

```zig
var term = try Terminal.init(alloc, .{
    .cols = 80,
    .rows = 24,
    // Allow all transmission mediums: direct, file, temporary file, shared memory.
    .kitty_image_loading_limits = .all,
});
```

```zig
var term = try Terminal.init(alloc, .{
    .cols = 80,
    .rows = 24,
    .kitty_image_loading_limits = .{
        .file = true,
        .temporary_file = true,
        .shared_memory = false,
    },
});
```

### Iterate all images

```zig
var it = term.screens.active.kitty_images.images.iterator();
while (it.next()) |kv| {
    const img = kv.value_ptr;
    std.debug.print("id={} {}x{} format={} bytes={}\n", .{
        img.id, img.width, img.height, img.format, img.data.len,
    });
}
```

### Delete all images

```zig
term.screens.active.kitty_images.delete(alloc, &term, .{ .all = true });
```
2026-04-06 06:57:14 -07:00
Mitchell Hashimoto 810ebae8e8
terminal: lower default kitty image storage limit for libghostty
The default kitty image storage limit was 320 MB for all build
artifacts. For libghostty, this is overly generous since it is an
embedded library where conservative memory usage is preferred.
Lower the default to 10 MB when building as the lib artifact while
keeping the 320 MB default for the full Ghostty application.
2026-04-06 06:56:20 -07:00
fru1tworld 13f7d23145
macOS: force layout sync when frame size mismatches GeometryReader 2026-04-06 19:22:47 +09:00
ghostty-vouch[bot] 841a49ae1a
Update VOUCHED list (#12138)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12137#discussioncomment-16460337)
from @rhodes-b.

Vouch: @neurosnap

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-06 04:31:17 +00:00
ghostty-vouch[bot] 4f543ff3d8
Update VOUCHED list (#12135)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12133#issuecomment-4189589541)
from @jcollie.

Vouch: @KayLeung

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-05 21:54:29 +00:00
Kay Leung e390937867 macos: fix badge permission
The previous version requested general notification permissions but omitted the `.badge` option. Because the initial request was granted, `settings.authorizationStatus` returns `.authorized`, leading the app to believe it has full notification privileges when it actually lacks the authority to update the dock icon badge.
2026-04-06 05:19:25 +08:00
davidsanchez222 0e49204b95 refactor(macos): centralize background opacity toggling across controllers 2026-04-05 17:04:20 -04:00
davidsanchez222 e5c31e8b37 macos: opacity-toggle setting persists between tabs in a window and to a newly created window 2026-04-05 17:04:20 -04:00
Mitchell Hashimoto 306acc4941
terminal/kitty: use direct medium for tests if we're not using files 2026-04-05 07:22:44 -07:00
Mitchell Hashimoto 935d37fbf1
terminal: add kitty image limits to Terminal.Options
Move kitty_image_storage_limit and kitty_image_loading_limits into
Terminal.Options so callers can set them at construction time
rather than calling setter functions after init. The values flow
through to Screen.Options during ScreenSet initialization. Termio
now passes both at construction, keeping the setter functions for
the updateConfig path.
2026-04-05 07:21:15 -07:00
Mitchell Hashimoto 64dcb91c1f
terminal/kitty: add loading limits to kitty graphics protocol
Add a Limits type to LoadingImage that controls which transmission
mediums (file, temporary_file, shared_memory) are allowed when
loading images. This defaults to "direct" (most restrictive) on
ImageStorage and is set to "all" by Termio, allowing apprt
embedders like libghostty to restrict medium types for resource or
security reasons.

The limits are stored on ImageStorage, plumbed through
Screen.Options for screen initialization and inheritance, and
enforced in graphics_exec during both query and transmit. Two new
Terminal methods (setKittyGraphicsSizeLimit, setKittyGraphicsLoadingLimits)
centralize updating all screens, replacing the manual iteration
previously done in Termio.
2026-04-05 07:18:45 -07:00
Mitchell Hashimoto 6a99c248d0
terminal/kitty: add Limits to restrict capabilities of image transfer 2026-04-05 07:08:30 -07:00
ghostty-vouch[bot] ba398dfff3
Update VOUCHED list (#12123)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12119#issuecomment-4188681042)
from @bo2themax.

Vouch: @jamylak

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-05 10:38:47 +00:00
jamylak 355aecb6ba macos: cancel deferred tab presentation on close
The 👻 Ghost Tab Issue

Previous failure scenario (User perspective):

1. Open a new tab
2. Instantly trigger close other tabs
   (eg. through custom user keyboard shortcut)
3. Now you will see an empty Ghost Tab
   (Only a window bar with empty content)

The previous failure mode is:

1. Create a tab or window now in `newTab(...)` / `newWindow(...)`.
2. Queue its initial show/focus work with `DispatchQueue.main.async`.
3. Close that tab or window with `closeTabImmediately()` /
 `closeWindowImmediately()` before the queued callback runs.
4. The queued callback still runs anyway and calls `showWindow(...)` /
 `makeKeyAndOrderFront(...)` on stale state.
5. The tab can be resurrected as a half-closed blank ghost tab.

The fix:

- Store deferred presentation work in a cancellable
  DispatchWorkItem and cancel it from the close paths
  before AppKit finishes tearing down the tab or window.
- This prevents the stale show/focus callback from
  running after close.
2026-04-05 17:43:41 +10:00
Mitchell Hashimoto 29e3de737e
terminal: make wuffs runtime-swappable, enable Kitty graphics for libvt
Introduce terminal/sys.zig which provides runtime-swappable function
pointers for operations that depend on external implementations. This
allows embedders of the terminal package to swap out implementations
at startup without hard dependencies on specific libraries.

The first function exposed is decode_png, which defaults to a wuffs
implementation. The kitty graphics image loader now calls through
sys.decode_png instead of importing wuffs directly.

This allows us to enable Kitty graphics support in libghostty-vt
for all targets except wasm32-freestanding.
2026-04-04 22:01:38 -07:00
Mitchell Hashimoto c541ceb120
terminal: add APC handler to stream_terminal (#12116)
Wire up the APC handler to `terminal.TerminalStream` to process APC
sequences, enabling support for kitty graphics commands in libghostty,
in theory.

The "in theory" is because we still don't export a way to actually
enable Kitty graphics in libghostty because we have some other things in
the way: PNG decoding and OS filesystem access that need to be more
conditionally compiled before we can enable the feature. However, this
is a step in the right direction, and we can at least verify that the
APC handler works via a test in Ghostty GUI.
2026-04-04 21:21:10 -07:00
Mitchell Hashimoto a8e92c9c53
terminal: add APC handler to stream_terminal
Wire up the APC handler to `terminal.TerminalStream` to process
APC sequences, enabling support for kitty graphics commands in 
libghostty, in theory.

The "in theory" is because we still don't export a way to actually
enable Kitty graphics in libghostty because we have some other things in
the way: PNG decoding and OS filesystem access that need to be more 
conditionally compiled before we can enable the feature. However, this
is a step in the right direction, and we can at least verify that the
APC handler works via a test in Ghostty GUI.
2026-04-04 21:11:31 -07:00
Mitchell Hashimoto 10696b5ed1
libghostty: add GhosttySelection type and selection support to formatter (#12115)
Add a new GhosttySelection C API type (selection.h / c/selection.zig)
that pairs two GhosttyGridRef endpoints with a rectangle flag. This maps
directly to the internal Selection type using untracked pins.

The formatter terminal options gain an optional selection pointer. When
non-null the formatter restricts output to the specified range instead
of emitting the entire screen. When null the existing behavior of
formatting the full screen is preserved.
2026-04-04 20:48:39 -07:00
Mitchell Hashimoto 86554de090
libghostty: add hyperlink URI accessor to grid_ref API (#12114)
Add ghostty_grid_ref_hyperlink_uri to extract the OSC 8 hyperlink URI
from a cell at a grid reference position. Follows the same buffer
pattern as ghostty_grid_ref_graphemes: callers pass a buffer and get
back the byte length, or GHOSTTY_OUT_OF_SPACE with the required size if
the buffer is too small. Cells without a hyperlink return success with
length 0.
2026-04-04 20:39:07 -07:00
Mitchell Hashimoto 757eff5881
libghostty: add GhosttySelection type and selection support to formatter
Add a new GhosttySelection C API type (selection.h / c/selection.zig)
that pairs two GhosttyGridRef endpoints with a rectangle flag. This
maps directly to the internal Selection type using untracked pins.

The formatter terminal options gain an optional selection pointer.
When non-null the formatter restricts output to the specified range
instead of emitting the entire screen. When null the existing
behavior of formatting the full screen is preserved.
2026-04-04 20:38:05 -07:00
Mitchell Hashimoto b9a241d1e2
libghostty: add hyperlink URI accessor to grid_ref API
Add ghostty_grid_ref_hyperlink_uri to extract the OSC 8 hyperlink
URI from a cell at a grid reference position. Follows the same
buffer pattern as ghostty_grid_ref_graphemes: callers pass a buffer
and get back the byte length, or GHOSTTY_OUT_OF_SPACE with the
required size if the buffer is too small. Cells without a hyperlink
return success with length 0.
2026-04-04 20:28:13 -07:00
ghostty-vouch[bot] cf8a2407a0
Update VOUCHED list (#12113)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12098#discussioncomment-16452103)
from @mitchellh.

Vouch: @fru1tworld

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-05 03:17:59 +00:00
Jeffrey C. Ollie 06144d30f2
libghostty-vt: allow version to be customized from the Zig build command 2026-04-04 17:04:01 -05:00
Jeffrey C. Ollie 0a4cf5877e
nix: add option to disable simd in libghostty-vt package (#12103) 2026-04-04 16:06:26 -05:00
Jeffrey C. Ollie 1bd7c19dac
nix: add option to disable simd in libghostty-vt package 2026-04-04 15:06:19 -05:00
Mitchell Hashimoto 0a492fdb33
build: add pkg-config static linking support and fat archives to libghostty (#12096)
The libghostty-vt pkg-config file was missing Libs.private, so
pkg-config --libs --static returned the same flags as the shared case,
omitting the C++ standard library needed by the SIMD code.

Additionally, the static archive did not bundle the vendored SIMD
dependencies (simdutf, highway, utfcpp), leaving consumers with
unresolved symbols when linking. If we're choosing to vendor (no -fsys)
then we should produce a fat static archive that includes them. If
`-fsys` is used, then we should not bundle them and instead reference
them via Requires.private, letting pkg-config chain to their own .pc
files.

Add Libs.private with the C++ runtime (-lc++ on Darwin, -lstdc++ on
Linux) and Requires.private for any SIMD deps provided via system
integration. When SIMD deps are vendored (the default), produce a fat
static archive that bundles them using libtool on Darwin and ar on
Linux. When they come from the system (-fsys=), reference them via
Requires.private instead, letting pkg-config chain to their own .pc
files.
2026-04-04 06:56:19 -07:00
Mitchell Hashimoto e157dd69c5
build: add pkg-config static linking support and fat archives to libghostty
The libghostty-vt pkg-config file was missing Libs.private, so
pkg-config --libs --static returned the same flags as the shared
case, omitting the C++ standard library needed by the SIMD code.

Additionally, the static archive did not bundle the vendored SIMD
dependencies (simdutf, highway, utfcpp), leaving consumers with
unresolved symbols when linking. If we're choosing to vendor (no -fsys)
then we should produce a fat static archive that includes them. If `-fsys`
is used, then we should not bundle them and instead reference them via
Requires.private, letting pkg-config chain to their own .pc files.

Add Libs.private with the C++ runtime (-lc++ on Darwin, -lstdc++
on Linux) and Requires.private for any SIMD deps provided via
system integration. When SIMD deps are vendored (the default),
produce a fat static archive that bundles them using libtool on
Darwin and ar on Linux. When they come from the system (-fsys=),
reference them via Requires.private instead, letting pkg-config
chain to their own .pc files.
2026-04-04 06:54:42 -07:00
Mitchell Hashimoto 707cd57acb
add a nix package (with CI tests) for libghostty-vt (#12090) 2026-04-03 20:12:52 -07:00
ghostty-vouch[bot] e3bbd54dd3
Update VOUCHED list (#12094)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12093#discussioncomment-16444399)
from @jcollie.

Vouch: @jordandm

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-04 01:46:07 +00:00
Jeffrey C. Ollie 326178adb8
nix: address review comments
* split out dev subpackage
* change version number to 0.1.0
* supported on same platforms as Zig
2026-04-03 20:19:50 -05:00
Jeffrey C. Ollie 4f825e87f5
add a nix package (with CI tests) for libghostty-vt 2026-04-03 16:28:21 -05:00
Toby She 30fdc8f4c8 macOS: fix cannot rebind super+up and super+down 2026-04-02 22:58:19 -04:00
Mitchell Hashimoto 0790937d03
macOS: fix Find Next/Previous button in the menu bar is not working as expected (#12070)
I don’t know why the search-related commands were added as performable
keybinds in 240d5e0fc5, but **I asked
Claude to add some tests for that**

> This won't fix cmd+g/G not working when the search bar is focused.
2026-04-02 12:56:39 -07:00
Lukas 18f2702225
macOS: fix Find Next/Previous button in the menu bar is not working as expected 2026-04-02 20:31:31 +02:00
ghostty-vouch[bot] 7747c96033
Update VOUCHED list (#12069)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12068#issuecomment-4179350272)
from @jcollie.

Vouch: @Douglas-MacGregor

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-02 17:28:57 +00:00
ghostty-vouch[bot] 63372f8ddb
Update VOUCHED list (#12066)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12038#discussioncomment-16423690)
from @mitchellh.

Vouch: @h3nock

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-02 13:53:39 +00:00
ghostty-vouch[bot] 48d3e972d8
Update VOUCHED list (#12052)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12050#issuecomment-4173393542)
from @mitchellh.

Vouch: @justonia

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-01 22:42:46 +00:00
Mitchell Hashimoto b8251de7e8
fix: Ensure snap paths come first in gio module loading (#12045)
This fixes the issue reported in
https://github.com/ghostty-org/ghostty/discussions/11311
2026-04-01 14:32:27 -07:00
Mitchell Hashimoto 92a4601f39
Revert "macOS: close search bar if needed when it loses focus (#11980)" (#12046)
This reverts commit 20cfaae2e5, reversing
changes made to 3509ccf78e.

This breaks some behaviours when there are multiple splits, which
requires another click to focus to another split in the same window🫪
2026-04-01 14:32:09 -07:00
Ken VanDine c16cf0ef07 fix: Ensure snap paths come first in gio module loading 2026-04-01 13:30:40 -04:00
Lukas 9ec5672505
Revert "macOS: close search bar if needed when it loses focus (#11980)"
This reverts commit 20cfaae2e5, reversing
changes made to 3509ccf78e.
2026-04-01 19:21:42 +02:00
Mitchell Hashimoto f6e6bb0238
macOS: fix upper cased letter is not correctly mapped to menu shortcut (#12039)
This is known issues before key-related PRs, tested on
fa9265636b.

The following config is mapped incorrectly to the menu shortcut:
```
keybind=A=goto_split:left
```
<img width="223" height="106" alt="image"
src="https://github.com/user-attachments/assets/b80da251-9cff-4b29-b143-64854a5c4271"
/>

Surfaces only accept `a` as a trigger to select left split, not
`shift+a`
2026-04-01 08:10:47 -07:00
Leah Amelia Chen 6d15b53fc7
gtk(chore): fix typos (#12036) 2026-04-01 22:12:23 +08:00
Lukas 702a2b43c3
macOS: fix upper cased letter is not correctly mapped to menu shortcut 2026-04-01 14:50:53 +02:00
Lukas c8702ece8f
gtk(chore): fix typos
### AI Disclosure

Claude wrote the regex to ignore base64-encoded sequences
2026-04-01 13:08:55 +02:00
ghostty-vouch[bot] b7e56044db
Update VOUCHED list (#12031)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12030#issuecomment-4167464133)
from @mitchellh.

Vouch: @Jarred-Sumner

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-01 04:59:00 +00:00
Jeffrey C. Ollie c2dd7579e2
core/gtk: ensure that first surface gets marked as focused surface by app (#12029) 2026-03-31 15:29:18 -05:00
Jeffrey C. Ollie 0f6836c69f
gtk: use surface id for notifications instead of pointer (#12028) 2026-03-31 15:07:47 -05:00
Jeffrey C. Ollie 4b5f2d60e7
core/gtk: ensure that first surface gets marked as focused surface by app 2026-03-31 14:57:41 -05:00
Jeffrey C. Ollie dee8598dc0
gtk: use surface id for notifications instead of pointer 2026-03-31 14:53:19 -05:00
Jeffrey C. Ollie f90180f91f
core: add 64 bit unique ID to every core surface (#12027)
- Expose that ID as the environment variable GHOSTTY_SURFACE_ID to
processes running in Ghostty surfaces.
- Add a function to the core app to search for surfaces by ID.
- ID is randomly generated, it has no other meaning other than as a
unique identifier for the surface. The ID also cannot be zero as that is
used to indicate a null ID in some situations.
2026-03-31 14:50:00 -05:00
Jeffrey C. Ollie ff02ed1b34
core: add 64 bit unique ID to every core surface
- Expose that ID as the environment variable GHOSTTY_SURFACE_ID to
  processes running in Ghostty surfaces.
- Add a function to the core app to search for surfaces by ID.
- ID is randomly generated, it has no other meaning other than as a
  unique identifier for the surface. The ID also cannot be zero as that
  is used to indicate a null ID in some situations.
2026-03-31 13:13:05 -05:00
Mitchell Hashimoto f16d35489b
apprt/embedded: fix ghostty_surface_free_text parameter mismatch (#12025)
Fixes #12020

The C header declared ghostty_surface_free_text with both a
ghostty_surface_t and ghostty_text_s* parameter, but the Zig
implementation only accepted a *Text parameter. This caused the surface
pointer to be interpreted as the text pointer, so the actual text
allocation was never freed.

I opted to keep the surface parameter to minimize the diff here. I'm not
sure why I thought I would need access to that surface pointer but just
want to fix the leak first.
2026-03-31 09:52:25 -07:00
Mitchell Hashimoto 4803d58bb4
apprt/embedded: fix ghostty_surface_free_text parameter mismatch
Fixes #12020

The C header declared ghostty_surface_free_text with both a
ghostty_surface_t and ghostty_text_s* parameter, but the Zig
implementation only accepted a *Text parameter. This caused the
surface pointer to be interpreted as the text pointer, so the
actual text allocation was never freed.
2026-03-31 09:46:35 -07:00
ghostty-vouch[bot] b2880636af
Update VOUCHED list (#12022)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12019#discussioncomment-16396278)
from @jcollie.

Vouch: @danneu

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-31 14:56:43 +00:00
Mitchell Hashimoto 292bf13d06
macOS: Make version in about dialog clickable (#12007)
- Fixes: https://github.com/ghostty-org/ghostty/issues/11964

Made a private enum type `VersionConfig` to reference whether the
release is a semver or tip, makes it easier for later in the view to
`switch` between cases.

I do think there could be a better place for this enum or we can get rid
of it, open to opinions. Right now version parsing is kind of duplicated
between `AboutView` and `UpdateModalView` so we can also extract to a
common helper if wanted.

Tested by manually setting `Marketing Version` in build settings to 

`1.3.1`
<img width="412" height="532" alt="Screenshot 2026-03-30 at 18 31 15"
src="https://github.com/user-attachments/assets/285bb94d-138b-4169-bb66-684eb04b6ca3"
/>

`332b2aefc`
<img width="412" height="532" alt="Screenshot 2026-03-30 at 18 32 48"
src="https://github.com/user-attachments/assets/fea30d39-bea7-4885-8221-1696e148f45e"
/>

### AI Disclosure
I used Sonnet 4.6 to understand where the version strings came from and
in what format, it read release yml files to see what's going on. Then
it proposed really bad code so I manually went in and cleaned up the
view.
2026-03-31 06:38:59 -07:00
Mitchell Hashimoto 5fe876cfa0
ghostty.h: guard sys/types.h include for MSVC (#12010)
## Summary

- Move `sys/types.h` include into the `#else` branch of the existing
`_MSC_VER` guard
- MSVC does not ship `sys/types.h` (POSIX header), and already gets
`ssize_t` from `BaseTsd.h`

## Test plan

- [x] `zig build -Dapp-runtime=none` -- clean build
- [x] `zig build test -Dapp-runtime=none` on Windows (2606/2660 passed,
54 skipped)
- [x] `zig build test` on Linux (2658/2684 passed, 26 skipped)
- [x] `zig build test` on macOS (2658/2668 passed, 10 skipped)
- [x] `zig build test-lib-vt` on all 3 platforms
- [x] Zig examples build on all 3 platforms
- [x] CMake examples build on Windows (c-vt-cmake pass,
c-vt-cmake-static pass)
2026-03-31 06:38:36 -07:00
Mitchell Hashimoto f140b1463f
macOS: fix incorrect delete symbol mapping (#12011)
`GHOSTTY_KEY_DELETE` should be mapped to `KeyEquivalent.deleteForward`.
This fixes the correct symbol showing in the menu. Previously, both
`GHOSTTY_KEY_DELETE` and `GHOSTTY_KEY_BACKSPACE` were showing `⌫`, but
`GHOSTTY_KEY_DELETE` only worked for `fn+delete`.

Add the following keybind and observe the symbol in the menu:
```
keybind=delete=new_tab
```

<img width="535" height="318" alt="image"
src="https://github.com/user-attachments/assets/67ed7b5d-f848-42ee-a382-fe364d86cb2c"
/>
2026-03-31 06:38:25 -07:00
Mitchell Hashimoto f827530103
libghostty: add all C struct layout metadata for WASM (#12017)
Added all C structs and sorted the entries for readability.
2026-03-31 06:01:49 -07:00
Elias Andualem 1d0a247c20 sort map alphabetically 2026-03-31 19:34:52 +08:00
Elias Andualem 30c9dec76b add all C struct layout metadata for WASM 2026-03-31 19:28:46 +08:00
Lukas 591dbd5112
macOS: fix incorrect delete symbol mapping 2026-03-31 10:27:12 +02:00
Louis Qian 010880a90a chore: make url computed property & rework enum signature 2026-03-30 20:15:01 -07:00
Mitchell Hashimoto 20cfaae2e5
macOS: close search bar if needed when it loses focus (#11980)
This adds features like:

1. Clicking outside of search bar works like typing `escape`
2. Typing `tab` while search bar is focused also works like typing
`escape`


https://github.com/user-attachments/assets/a51f1560-ed14-4002-81b4-96eb927b17ca
2026-03-30 19:39:26 -07:00
Louis Qian 183e2cef2f chore: clean up switch statement 2026-03-30 18:51:45 -07:00
Louis Qian 90d71dd2f6 chore: clean up comments 2026-03-30 18:49:17 -07:00
Louis Qian b29f261dc8 chore: clean up versionConfig to be init-able 2026-03-30 18:44:49 -07:00
Louis Qian ed6f0588a3 feat: make version clickable depending on type 2026-03-30 18:41:26 -07:00
Alessandro De Blasis e993ded7c8
ghostty.h: guard sys/types.h include for MSVC
sys/types.h is a POSIX header that does not exist on MSVC. Move it
into the #else branch of the existing _MSC_VER guard that already
provides ssize_t via BaseTsd.h.
2026-03-31 02:40:33 +02:00
ghostty-vouch[bot] 3509ccf78e
Update VOUCHED list (#12005)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11981#issuecomment-4158783258)
from @tristan957.

Vouch: @yabbal

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-30 23:27:44 +00:00
Mitchell Hashimoto 50f3b1d60d
libghostty: export function table and make it growable for wasm (#12003)
Replaces #11958

This exports the function table and makes it growable so that the
effects API can be used. It's still very not ergonomic to use the
effects API so I'm going to work on that next, but this at least makes
it _possible_. Zig 0.15.x is missing the ability to pass
`--growable-table` to the linker so we use binary patching to add it
(yay!) lol.
2026-03-30 15:29:29 -07:00
Mitchell Hashimoto f89195ace9
revert example/wasm-vt 2026-03-30 15:21:27 -07:00
ghostty-vouch[bot] 8fc0c85e0c
Update VOUCHED list (#12002)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12001#discussioncomment-16386924)
from @jcollie.

Vouch: @louisunlimited

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-30 22:14:54 +00:00
Jeffrey C. Ollie c75081b89c
build: normalize input archives before Darwin libtool merge (#11999)
## Root cause

Zig 0.15.2 can produce macOS `.a` archives where some 64-bit Mach-O
members are only 4-byte aligned inside the archive. Recent Apple
`libtool -static` does not handle that layout correctly: it emits `not
8-byte aligned` warnings and, in the failing case, silently drops those
members when creating the combined static library.

In Ghostty, this happened in the Darwin `libtool` merge step that builds
`libghostty-fat.a`. The x86_64 input `libghostty.a` still contained the
expected `libghostty_zcu.o` and about 97 exported `_ghostty_` symbols,
but after `libtool -static` the output archive contained only 4 SIMD
symbols because `libghostty_zcu.o` had been discarded. The same warning
pattern also appeared in third-party input archives such as
`libfreetype.a` and `libz.a`, so this was not only a `libghostty.a`
problem.

## What needed to be done

The inputs to Apple `libtool` needed to be normalized before they were
merged.

The safest fix is to copy each input archive and run `ranlib -D` on the
copy before passing it to `libtool`. `ranlib` rewrites the archive into
a form that Apple’s linker tools accept, fixing the alignment/layout
issue without changing the archive’s semantic contents.

## Why this approach

An `ar x` -> `ar rcs` workaround can also make the warnings go away, but
it is a broader and riskier transformation. Extracting archive members
into a flat directory is not semantics-preserving:

- duplicate member basenames can collide
- non-`.o` members can be lost
- member order can change

That means an `ar`-based rearchive can silently change valid archives
while fixing alignment. `ranlib -D` avoids those hazards because it
rewrites the archive in place instead of flattening it through the
filesystem.

`-D` is also important because plain `ranlib` is not deterministic. In
local testing, `ranlib -D` still fixed the alignment issue, preserved
all 97 `_ghostty_` symbols, produced no `libtool` warnings, and was
byte-stable across repeated runs.

## Validation

This was reproduced directly:

- before normalization, running `libtool -static` on the affected x86_64
`libghostty.a` produced a `libghostty_zcu.o not 8-byte aligned` warning
and the output archive dropped from 97 `_ghostty_` symbols to 4
- after `ranlib -D`, the same `libtool -static` command preserved all 97
`_ghostty_` symbols and emitted no alignment warnings

After applying the normalization step, a clean `zig build` succeeded,
and the final macOS xcframework archive contained 97 `_ghostty_` symbols
in both the `x86_64` and `arm64` slices.

## Summary

This was not a Metal issue, not an Xcode project issue, and not a
stale-cache issue. The actual root cause was an Apple `libtool`
interoperability problem with Zig-produced macOS archives. The required
fix was to normalize each archive before the Darwin `libtool` merge
step, and `ranlib -D` is the least invasive way to do that while
preserving archive semantics.
2026-03-30 16:22:20 -05:00
Barut a83a82b3f8 build: normalize input archives before Darwin libtool merge
Apple's recent libtool can warn about misaligned 64-bit archive members
and silently drop them when merging static libraries. In Ghostty this
showed up in the Darwin libtool step that builds libghostty-fat.a.

Normalize each input archive by copying it and running ranlib on the
copy
before handing it to libtool. That rewrites the archive into a layout
Apple's linker tools accept without flattening members through the
filesystem or changing Ghostty's archive format.
2026-03-30 16:59:07 -04:00
ghostty-vouch[bot] 500ab13c86
Update VOUCHED list (#12000)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11999#issuecomment-4158097469)
from @jcollie.

Vouch: @BarutSRB

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-30 20:50:51 +00:00
Mitchell Hashimoto 01a8ea7212
build: binary patching with Zig 2026-03-30 12:06:41 -07:00
Mitchell Hashimoto 6c085e5442
build: binary patch to add growable tables 2026-03-30 11:41:24 -07:00
Mitchell Hashimoto 624b4884c3
Add build_table 2026-03-30 11:34:09 -07:00
Mitchell Hashimoto ee19c8ff7f
wasm: binary patching wow 2026-03-30 11:28:13 -07:00
Mitchell Hashimoto 7269fa7d14
lib: rename GHOSTTY_EXPORT to GHOSTTY_API (#11994)
Rename the shared library visibility macro from GHOSTTY_EXPORT to
GHOSTTY_API across all public C headers. This applies to both the
libghostty-vt headers under include/ghostty/vt/ and the main
include/ghostty.h header.

This is a bit more idiomatic compared to other C libs and addresses the
fact that we're not always exporting...
2026-03-30 10:51:52 -07:00
Mitchell Hashimoto 40d108599f
lib: rename GHOSTTY_EXPORT to GHOSTTY_API
Rename the shared library visibility macro from GHOSTTY_EXPORT to
GHOSTTY_API across all public C headers. This applies to both the
libghostty-vt headers under include/ghostty/vt/ and the main
include/ghostty.h header.

This is a bit more idiomatic compared to other C libs and addresses the
fact that we're not always exporting...
2026-03-30 10:26:32 -07:00
Mitchell Hashimoto 53871e4d52
libghostty: WASM VT example, add `ghostty_type_json` (#11992)
This adds a new `example/wasm-vt` example that initializes a terminal,
lets you write text to write to it, and shows you the screen state.

In doing so, I realized that writing structs in WASM is extremely
painful. You had to do manually hardcoded sizes and byte offsets and
it's scary as hell! So I added a new `ghostty_type_json` API that
returns a C string with JSON-encoded type information about all exported
C structures.

## Example

<img width="1912" height="1574" alt="CleanShot 2026-03-30 at 10 20
16@2x"
src="https://github.com/user-attachments/assets/7cae92bc-3403-4e4c-958c-b7ea58026afe"
/>
2026-03-30 10:24:00 -07:00
Mitchell Hashimoto bd7415f4b7
terminal: clean up some types tests 2026-03-30 10:21:08 -07:00
Mitchell Hashimoto 3c6e98c5a7
vt: export the new API 2026-03-30 10:16:39 -07:00
Mitchell Hashimoto 0c38e8be60
vt: simplify ghostty_type_json to return null-terminated string
The function previously took a size_t* out-parameter for the string
length. Since the JSON blob is now null-terminated, the len parameter
is unnecessary. Remove it from the Zig implementation, C header, and
the WASM example consumer which no longer needs to allocate and free
a usize just to read the length.
2026-03-30 10:16:19 -07:00
Mitchell Hashimoto 6479d90ca5
example/wasm-vt: use ghostty_type_json for struct layouts
Replace hardcoded byte offsets and struct sizes with dynamic lookups
from the ghostty_type_json API. On WASM load, the type layout JSON
is fetched once and parsed into a lookup table. Two helpers,
fieldInfo and setField, use this metadata to write struct fields at
the correct offsets with the correct types.

This removes the need to manually maintain wasm32 struct layout
comments and magic numbers for GhosttyTerminalOptions and
GhosttyFormatterTerminalOptions, so the example stays correct if
the struct layouts change.
2026-03-30 10:16:19 -07:00
Mitchell Hashimoto 2e827cc39d
vt: add ghostty_type_json for struct layout metadata
Add a new C API function that returns a comptime-generated JSON string
describing the size, alignment, and field layout of every C API extern
struct. This lets FFI consumers (particularly WASM) construct structs
by byte offset without hardcoding platform-specific layout.

The JSON is built at comptime using std.json.Stringify via a
StructInfo type that holds per-struct metadata and implements
jsonStringify. A StaticStringMap keyed by C struct name provides
lookup by name as well as iteration for the JSON serialization.

The function is declared in types.h alongside the other common types
and exported as ghostty_type_json.
2026-03-30 10:16:19 -07:00
Mitchell Hashimoto 8fab3ac3f3
example/wasm-vt 2026-03-30 10:16:19 -07:00
Mitchell Hashimoto 6d4528e471
libghostty: add GHOSTTY_EXPORT for shared lib symbol visibility (#11977)
## Summary

Add a `GHOSTTY_EXPORT` annotation macro to all public function
declarations across both `ghostty.h` (the main libghostty header) and
the `include/ghostty/vt/` headers (the libghostty-vt API). This is the
standard pattern used by C libraries that support both static and shared
library builds.

On Windows, functions need `__declspec(dllexport)` when building the DLL
and `__declspec(dllimport)` when consuming it, or they won't be visible
across the DLL boundary. On Linux/macOS with GCC/Clang,
`__attribute__((visibility("default")))` keeps the public API visible
when building with `-fvisibility=hidden`, which reduces symbol table
size and avoids collisions.

The macro resolves to nothing for static builds (when `GHOSTTY_STATIC`
is defined) and on compilers that don't support visibility attributes,
so this is a no-op for the current macOS static library path.

## Why

I looked at how popular C libraries handle this and every serious one
follows the same pattern:

- SDL (`SDL_DECLSPEC`)
- cURL (`CURL_EXTERN`)
- SQLite (`SQLITE_API`)
- zlib (`ZEXTERN`)
- FreeType (`FT_EXPORT`) -- already vendored by Ghostty
- GLFW (`GLFWAPI`)
- Lua (`LUA_API`)

The header comment says "the API is built to be more general purpose"
and the long-term goal is libghostty as a reusable library. Export
annotations are table stakes for that -- they explicitly mark the public
API surface, enable proper shared library builds on all platforms, and
give consumers the right linker hints.

## Test plan

- [x] Windows build and full test suite
- [x] Linux build and full test suite
- [x] macOS build, full test suite, and app launch verified working
- [x] macOS xcodebuild app build and launch verified working
- [x] Shared library symbol inspection on all three platforms
- [x] Linux: validated version script + LLD restricts exports to only
ghostty_* (107/107, 0 leaked, 12 MB .so)
- [x] Linux: C link test against restricted .so -- compiled, linked, ran
successfully
- [x] Windows: DLL exports verified (102 ghostty_ + 3 unavoidable
CRT/simdutf)
2026-03-30 10:15:49 -07:00
Alessandro De Blasis 80e35af763
cmake: define GHOSTTY_STATIC for static library consumers
The ghostty-vt-static target needs to propagate GHOSTTY_STATIC to
consumers so that GHOSTTY_EXPORT resolves to nothing instead of
__declspec(dllimport) on Windows. Without this, static linking
fails with unresolved __imp_ghostty_* symbols.
2026-03-30 18:56:09 +02:00
Lukas a06350df9b
macOS: close search bar if needed when it loses focus
This adds features like:
1. Clicking outside of SearchBar works like typing `escape`
2. Typing `tab` while search bar is focused also works like typing `escape`
2026-03-30 18:29:44 +02:00
Mitchell Hashimoto d643792f36
macOS: add keyboard shortcut test (#11986)
This is the first step (also another step forward for completing #7879)
to fix various responder issues regarding keyboard shortcuts. I tried my
best to separate changes chunk by chunk; there will follow up pr based
on this to fix them.

This pr doesn't change any existing behaviours/flaws, but following
changes will be easier to review after this.

## AI Disclosure

Claude wrote most of the test cases
2026-03-30 09:20:35 -07:00
Mitchell Hashimoto 1672e891b9
macOS: remove redundant tab event overrides (#11984)
- Revert 5540f5f249, middle click comes
out of box with native tabbing, but we override it wrong previous.
- Reverts 894e8d91ba, I check it the
commit right before it and all the way back to
ffe4afe538, right mouse down on tab bar
works well without any issue
- Add back reverted handling in #11150


https://github.com/user-attachments/assets/8660368e-05ae-45b0-aa81-6196f3434daf
2026-03-30 09:19:33 -07:00
Mitchell Hashimoto bf3f9b3150
macOS: fix focus update when using search or command palette (#11978)
This fixes two things:

1. Surface focus state is not consistent with first responder state when
the search bar is open.
> Reproduce: Open search, switch to another app and back, observe the
cursor state of the surface.
> And after switching back, `cmd+shift+f` will close the search bar,
surface will become focused but not first responder, so it will not
accept any input
2. Command palette is not focused when built with Xcode 26.4 (26.3 works
fine).
> This is weird to me, because the tip (and built with 26.3) works fine.
I guess it's related to the SDK update? I couldn’t be sure what went
wrong, but dispatching it to the next loop works as previously.
  > Also cleaned some previous checks when quickly open and reopen.
  > This fix works great both with 26.4 and 26.3



https://github.com/user-attachments/assets/c9cf4c1b-60d9-4c71-802c-55f82e40eec7
2026-03-30 09:18:28 -07:00
Mitchell Hashimoto f66cf179cd
gtk: only trigger resize callbacks and overlay when size actually changes (#11972)
Fixes #11970

Also fixes problem that resize overlay would intercept mouse activity
while active.
2026-03-30 08:45:50 -07:00
Mitchell Hashimoto fdb914c680
build(deps): bump cachix/install-nix-action from 31.10.2 to 31.10.3 (#11967)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.10.2 to 31.10.3.
<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.10.3</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.34.2 -&gt; 2.34.4 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/271">cachix/install-nix-action#271</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.10.3">https://github.com/cachix/install-nix-action/compare/v31...v31.10.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="96951a368b"><code>96951a3</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/271">#271</a>
from cachix/create-pull-request/patch</li>
<li><a
href="6281169445"><code>6281169</code></a>
nix: 2.34.2 -&gt; 2.34.4</li>
<li>See full diff in <a
href="51f3067b56...96951a368b">compare
view</a></li>
</ul>
</details>
<br />
2026-03-30 08:31:03 -07:00
dependabot[bot] 3864fa585f
build(deps): bump cachix/install-nix-action from 31.10.2 to 31.10.3
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.10.2 to 31.10.3.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](51f3067b56...96951a368b)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 15:22:36 +00:00
Jeffrey C. Ollie 7ad3888819
cli: add pager support to +explain-config (#11940)
Add a new Pager type that wraps output to an external pager program when
stdout is a TTY, following the same conventions as git. The pager
command is resolved from $PAGER, falling back to `less`. An empty $PAGER
disables paging. If the pager fails to spawn, we fall back to stdout.

Previously, +explain-config wrote directly to stdout with no paging,
which meant long help text would scroll by. Now output is automatically
piped through the user's preferred pager when running interactively. A
--no-pager flag is available to disable this.
2026-03-30 10:12:33 -05:00
Jon Parise 840ab46009 cli: also recognize $GHOSTTY_PAGER
When defined, GHOSTTY_PAGER takes precedence over PAGER. If either of
those variables is set to an empty value, paging is disabled.
2026-03-30 10:53:53 -04:00
Jon Parise 11d45cd43c cli: add pager support for +show-config 2026-03-30 10:48:07 -04:00
Jon Parise 62f8a1cbcf cli: use a caller-provided write buffer
This follows Zig's conventions more closely, where the caller owns the
write buffer.
2026-03-30 10:48:07 -04:00
Jon Parise 4a0cca1c5b cli: add pager support to +explain-config
Add a new Pager type that wraps output to an external pager program when
stdout is a TTY, following the same conventions as git. The pager
command is resolved from $PAGER, falling back to `less`. An empty $PAGER
disables paging. If the pager fails to spawn, we fall back to stdout.

Previously, +explain-config wrote directly to stdout with no paging,
which meant long help text would scroll by. Now output is automatically
piped through the user's preferred pager when running interactively. A
--no-pager flag is available to disable this.
2026-03-30 10:48:07 -04:00
Lukas de8139bbc3
macOS: move MenuShortcutManager to a separate file 2026-03-30 16:10:06 +02:00
Lukas 1845dd26b6
macOS: extract menu shortcut syncing into MenuShortcutManager 2026-03-30 16:09:21 +02:00
Lukas 65cd31dc79
macOS: add NormalizedMenuShortcutKeyTests 2026-03-30 15:47:07 +02:00
Lukas 5c5f645b61
macOS: support reloading temporary config for testing 2026-03-30 15:47:07 +02:00
Lukas 51cd63871d
macos: passthrough right mouse down event to TabTitleEditor if needed (#11150) 2026-03-30 12:22:54 +02:00
Lukas 5de30c0dce
Revert "macOS: fix tab context menu opens on macOS 26 with titlebar tabs (#9831)"
This reverts commit 894e8d91ba, reversing
changes made to 4a173052fb.
2026-03-30 12:09:51 +02:00
Lukas 5c5029b0c4
Revert "macos: add support for middle-click tab close for `macos-titlebar-style = tabs` (#11963)"
This reverts commit 5540f5f249, reversing
changes made to cca4c788ad.
2026-03-30 12:08:49 +02:00
Lukas 013579cfcf
macOS: fix initial focus of command palette when building with Xcode 26.4
Tip works fine, but I've tried release and debug build with Xcode 26.4, it failed to focus as expected
2026-03-30 10:03:09 +02:00
Lukas 32920b6b2a
macOS: handle surface focus more gracefully
This will fix surface focus state is not consistent with first responder state when the search bar is open
2026-03-30 10:03:09 +02:00
Alessandro De Blasis 0c765c7c58
libghostty: add GHOSTTY_EXPORT to VT headers
Extend GHOSTTY_EXPORT annotations to all public function declarations
in include/ghostty/vt/ headers. Add GHOSTTY_EXPORT macro to types.h
with ifndef guard so both ghostty.h and VT headers share the same
definition without conflict.
2026-03-30 09:28:11 +02:00
Alessandro De Blasis bd413cc7bd
libghostty: add GHOSTTY_EXPORT for shared library symbol visibility 2026-03-30 08:20:24 +02:00
Jeffrey C. Ollie af36959942
gtk: only trigger resize callbacks and overlay when size actually changes
Fixes #11970

Also fixes problem that resize overlay would intercept mouse activity
while active.
2026-03-29 23:38:34 -05:00
Mitchell Hashimoto 5540f5f249
macos: add support for middle-click tab close for `macos-titlebar-style = tabs` (#11963)
Fixes #11962

### Summary
This PR implements a fix for:
https://github.com/ghostty-org/ghostty/discussions/10264

This allows the `macos-titlebar-style` setting `tabs` to behave the same
way other titlebar style options do with middle click handling.

### AI Disclosure
I used claude code (Sonnet 4.6) to identify the best place to start when
implementing this change, as well as for general Swift questions. The
code within this PR is written by me.
2026-03-29 15:24:16 -07:00
Nicholas Ochoa 3f6683df02 macos: add support for middle-click tab close 2026-03-29 15:19:35 -07:00
Mitchell Hashimoto cca4c788ad
terminal: update page_serial_min properly when erasing a page to avoid crash in search (#11965)
Fixes #11957

erasePage now updates page_serial_min when the first page is erased, and
asserts that only front or back pages are erased since page_serial_min
cannot represent serial gaps from middle erasure.

eraseRows can still technically destroy middle pages but no caller does
that today. We'll have to rethink this eventually.
2026-03-29 15:14:43 -07:00
Mitchell Hashimoto d784600fd6
terminal: update page_serial_min in erasePage
Fixes #11957

erasePage now updates page_serial_min when the first page is erased,
and asserts that only front or back pages are erased since
page_serial_min cannot represent serial gaps from middle erasure.

To enforce this invariant at the API level, PageList.eraseRows is
now private. Two public wrappers replace it: eraseHistory always
starts from the beginning of history, and eraseActive takes a y
coordinate (with bounds assertion) and always starts from the top
of the active area. This makes middle-page erasure impossible by
construction.
2026-03-29 15:10:12 -07:00
ghostty-vouch[bot] 10956bfa48
Update VOUCHED list (#11961)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11960#discussioncomment-16371359)
from @jcollie.

Vouch: @nicholas-ochoa

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-29 19:59:59 +00:00
Mitchell Hashimoto 1c14b9615b
fix(libghostty): ensure memory is zeroed in runtime safety modes for wasm/freestanding (#11955)
Zero page memory on freestanding/wasm where allocator reuses freed slots
without clearing. Allows recreating a new or multiple terminals.
2026-03-29 06:40:09 -07:00
Elias Andualem 420de124f0 fix: ensure memory is zeroed in runtime safety modes for wasm/freestanding 2026-03-29 17:28:18 +08:00
Mitchell Hashimoto debcffbadb
libghostty: make headers C++ compatible (#11950)
The headers were not C++ compatible and would fail compiling before (see
https://github.com/ghostty-org/ghostty/discussions/11878). The only
reason is because our typedefs would conflict since we named them
identically.

This also adds a `c-vt-stream` example and a `cpp-vt-stream` example,
the latter primarily to verify we can build in C++ mode.
2026-03-28 18:45:56 -07:00
Mitchell Hashimoto 1fcd80daab
libghostty: add cpp-vt-stream example and fix C++ header compatibility
Add a cpp-vt-stream example that verifies libghostty headers compile
cleanly in C++ mode. The example is a simplified C++ port of
c-vt-stream.

The headers used the C idiom `typedef struct Foo* Foo` for opaque
handles, which is invalid in C++ because struct tags and typedefs
share the same namespace. Fix all 12 opaque handle typedefs across the
headers to use a distinct struct tag with an Impl suffix, e.g.
`typedef struct GhosttyTerminalImpl* GhosttyTerminal`. This is a
source-compatible change for existing C consumers since the struct
tags were never referenced directly.
2026-03-28 18:38:58 -07:00
Mitchell Hashimoto 741f1d129a
example/c-vt-stream 2026-03-28 18:34:15 -07:00
Mitchell Hashimoto 0f6e733f8c
build: use VERSION file if present, expose via libghostty (#11932)
If a `VERSION` file is present from our build root, prefer that as our
version source of truth over `build.zig.zon`. This file is automatically
created in source tarballs and will allow us to cut pre-release tarballs
of libghostty in particular (but affects all) that has a more specific
version than what can be in build.zig.zon.

This also adds the APIs necessary to extract this via the C API.

I started prepping for a separate libghostty version but not sure if
I'll wire that up in this PR yet or not...
2026-03-28 18:29:34 -07:00
Mitchell Hashimoto a95bfdfe14
Update iTerm2 colorschemes (#11946)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20260323-152405-a2c7b60
2026-03-28 18:29:11 -07:00
mitchellh 5421326678 deps: Update iTerm2 color schemes 2026-03-29 00:23:08 +00:00
Jeffrey C. Ollie 4903e2821d
gtk: disable kinetic scrolling for trackpads until 4.20.1 (#11793)
Until gtk 4.20.1 trackpads have kinetic scrolling behavior regardless of
`Gtk.ScrolledWindow.kinetic_scrolling`. As a workaround, set
EventControllerScroll.kinetic to false on all controllers.

`observeControllers()` has this warning:
> Calling this function will enable extra internal bookkeeping to track
controllers and emit signals on the returned listmodel. It may slow down
operations a lot.
> Applications should try hard to avoid calling this function because of
the slowdowns.

but judging from the
[source](5301a91f1c/gtk/gtkwidget.c (L12375-L12383))
this is a one time penalty since we free the result immediately
afterwards.

Fixes https://github.com/ghostty-org/ghostty/discussions/11460.

### AI usage
Zed + Opus 4.5 generated the first pass, but it missed freeing the
result of `observeControllers()` and conveniently binding
`scrolled_window` to the blueprint. Figuring out what was going on also
took a lot of [human
debugging](https://github.com/ghostty-org/ghostty/discussions/11460#discussioncomment-16245664).
2026-03-28 19:08:15 -05:00
Michael Stevens c0a124f3ca gtk: disable kinetic scrolling for trackpads until 4.20.1
Until gtk 4.20.1 trackpads have kinetic scrolling behavior regardless
of `Gtk.ScrolledWindow.kinetic_scrolling`. As a workaround, set
EventControllerScroll.kinetic to false on all controllers.

`observeControllers()` has this warning:
> Calling this function will enable extra internal bookkeeping to track controllers and emit signals on the returned listmodel. It may slow down operations a lot.
> Applications should try hard to avoid calling this function because of the slowdowns.

but judging from the [source](5301a91f1c/gtk/gtkwidget.c (L12375-L12383))
this is a one time penalty since we free the result immediately afterwards.

Fixes https://github.com/ghostty-org/ghostty/discussions/11460
2026-03-28 17:36:17 -04:00
Austin Drummond 3c2c596dc7
fix global keybinds from not repsonding anymore 2026-03-28 17:35:26 -04:00
ghostty-vouch[bot] baad0aa666
Update VOUCHED list (#11938)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11823#discussioncomment-16358799)
from @mitchellh.

Vouch: @karesansui-u

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-28 18:18:35 +00:00
ghostty-vouch[bot] e2b9e8c6a8
Update VOUCHED list (#11936)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11662#discussioncomment-16358710)
from @mitchellh.

Vouch: @MrConnorKenway

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-28 18:05:14 +00:00
Mitchell Hashimoto 73ce1cd8e8
build: prep for separate lib version 2026-03-28 09:32:02 -07:00
Mitchell Hashimoto 8fa50f84d7
cli: dupe argument strings to retain their memory (#11931)
The argument iterator's .next() method returns a transient slice of the
command line buffer so we need to make our own copies of these values to
avoid referencing stale memory.
2026-03-28 09:26:28 -07:00
Mitchell Hashimoto bcb295d9fa
build: read version from VERSION file if available
Read the app version from a VERSION file in the build root,
trimming whitespace, and fall back to build.zig.zon if the file
is not present. This allows source tarballs to carry a VERSION
file as the source of truth for the version string.
2026-03-28 09:23:20 -07:00
Mitchell Hashimoto 8813261341
libghostty: expose version information via build options and C API
Add version (std.SemanticVersion) to the terminal build options so that
the terminal module has access to the application version at comptime.
The add() function breaks it out into version_string, version_major,
version_minor, version_patch, and version_build terminal options.

On the C API side, five new GhosttyBuildInfo variants expose these
through ghostty_build_info(). String values use GhosttyString; numeric
values use size_t. When no build metadata is present, version_build
returns a zero-length string.

The c-vt-build-info example is updated to query and print all version
fields.
2026-03-28 09:17:52 -07:00
Jon Parise 2b1ec5db6d cli: dupe argument strings to retain their memory
The argument iterator's .next() method returns a transient slice of the
command line buffer so we need to make our own copies of these values to
avoid referencing stale memory.
2026-03-28 12:14:28 -04:00
Mitchell Hashimoto 608bc7d24d
cli: +edit-config works properly when editor command contains arguments (#11898)
If `$EDITOR` or `$VISUAL` contained arguments, not just the path to an
editor (e.g. `zed --new`) `+edit-config` would fail because we were
treating the whole command as a path. Instead, wrap the command with
`/bin/sh -c <command>` so that the shell can separate the path from the
arguments.

Fixes #11897
2026-03-28 08:57:30 -07:00
Mitchell Hashimoto e20b50652a
fix: replace hardcoded locale.h constants with build-system TranslateC (#11920)
Replace hardcoded locale.h constants and extern function declarations
with build-system TranslateC, following the same pattern as pty.c.

This fixes LC_ALL being hardcoded to 6 (the musl/glibc implementation
value), which is implementation-defined and differs on Windows MSVC
(where LC_ALL is 0), causing `setlocale()` to crash with an invalid
parameter error.

## Changes

- Added `src/os/locale.c` — includes `locale.h` for TranslateC
- Added TranslateC step in `src/build/SharedDeps.zig` (same pattern as
pty.c)
- Replaced hardcoded constants and extern declarations in
`src/os/locale.zig` with `@import("locale-c")`

## AI disclosure

Claude Code was used to assist with debugging and identifying this
issue.
2026-03-28 08:56:40 -07:00
Mitchell Hashimoto 94d1398e60
doc: clarify utf8 text input contract for key event encoder (#11910)
Documenting some hidden implementation details. Basically extracted from
the swift NSEvent extension.
2026-03-28 08:54:59 -07:00
Mitchell Hashimoto 3187b18a94
benchmark: disable test on windows (#11930)
We don't appear to have a time source with enough resolution to get a
non-zero duration on the benchmark test so it fails.
2026-03-28 08:53:23 -07:00
Jeffrey C. Ollie 60c7e767a8
benchmark: disable test on windows
We don't appear to have a time source with enough resolution to get a
non-zero duration on the benchmark test so it fails.
2026-03-28 10:20:51 -05:00
i999rri f0badd34d3 fix: replace hardcoded locale.h constants with build-system TranslateC
Replace hardcoded locale.h constants and extern function declarations
with build-system TranslateC, following the same pattern as pty.c.

This fixes LC_ALL being hardcoded to 6 (musl/glibc value), which is
implementation-defined and differs on Windows MSVC (where LC_ALL is 0),
causing setlocale() to crash with an invalid parameter error.
2026-03-28 22:59:10 +09:00
ghostty-vouch[bot] 0d1f77bc4d
Update VOUCHED list (#11925)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11921#discussioncomment-16355800)
from @jcollie.

Vouch: @i999rri

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-28 12:33:58 +00:00
ghostty-vouch[bot] 562e7048c1
Update VOUCHED list (#11918)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11916#issuecomment-4147686590)
from @pluiedev.

Denounce: @daedaevibin

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-28 09:16:01 +00:00
Elias Andualem 01abf4af21 doc: clarify UTF-8 text handling in ghostty_key_event_get_composing 2026-03-28 12:18:23 +08:00
Mitchell Hashimoto 12458e3ace
blp and glsl files are source files, not binary (#11906) 2026-03-27 15:36:43 -07:00
Jeffrey C. Ollie 947bfbe850
blp and glsl files are source files, not binary 2026-03-27 17:35:14 -05:00
Jeffrey C. Ollie cb3c20befe
cli: escape path in +edit-config 2026-03-27 12:24:26 -05:00
Jeffrey C. Ollie 6491363157
cli: +edit-config works properly when editor command contains arguments
If `$EDITOR` or `$VISUAL` contained arguments, not just the path to
an editor (e.g. `zed --new`) `+edit-config` would fail because we were
treating the whole command as a path. Instead, wrap the command with
`/bin/sh -c <command>` so that the shell can separate the path from
the arguments.

Fixes #11897
2026-03-27 10:08:20 -05:00
Mitchell Hashimoto b8b0896324
ci: add full zig test suite for Windows (#11839)
## Summary

This PR effectively enables testing for all the Windows related stuff
that is coming soon.

> [!IMPORTANT]
>This PR builds on top of #11782 which fixes the last (as we speak) bug
that we have in the Windows pipeline. So it would be great to review
that PR first and then work on this one. Then we'll have the real
windows testing, basically achieving parity, infrastructurally, with the
other platforms.

What it does:

- Add a `test-windows` job to the CI workflow that runs the full test
suite (`zig build -Dapp-runtime=none test`) on Windows
- Add `test-windows` to the `required` checks list so it gates merges

## Context
The existing `build-libghostty-vt-windows` job only runs `zig build
test-lib-vt` (the VT library subset).
I realized that in c5092b09d we removed the TODO comment in that job:
"Work towards passing the full test suite on Windows."
But effectively we weren't running tests in CI yet! 

The full test suite now passes on Windows (51/51 steps, 2654 tests, 23
skipped). This job mirrors what the other platforms do — Linux runs `zig
build -Dapp-runtime=none test` via Nix, macOS runs `zig build test` via
Nix. Windows runs the same command directly via `setup-zig` since
there's no Nix on Windows.

## How
The new job follows the same pattern as the other Windows CI jobs:
- `runs-on: windows-2025` (same as `build-libghostty-vt-windows` and
`build-examples-cmake-windows`)
- `timeout-minutes: 45` (same as other Windows jobs)
- `needs: skip` so it runs early in parallel (same as `test-macos` and
the main `test` job), not gated behind other jobs
- Uses `mlugg/setup-zig` (same pinned version as other Windows jobs)
- Runs `zig build -Dapp-runtime=none test`

## Dependencies
This job will only pass once the following PRs are merged:
- PR #11782 -> backslash path handling in CommaSplitter/Theme
- PR #11807 -> freetype compilation fix
- PR #11810 -> ssize_t typedef for MSVC
- PR #11812 -> linkLibCpp skip + freetype enum signedness
- Others I have missed probably but they are merged already.

## Test plan
- The workflow YAML is valid (standard GitHub Actions syntax, matches
existing job patterns)
- I will be ready to issue fix PRs if any issue related to this arises.
I cannot reliably test GH actions locally unfortunately.
- Once dependencies land, the job should produce: 51/51 steps, ~2654
tests pass, 23 skipped
- No impact on existing Linux/macOS CI jobs

## What I Learnt
- GitHub Actions Windows runners don't have Nix, so Windows jobs use
`setup-zig` directly while Linux/macOS jobs use `nix develop -c zig
build ...`. The Nix wrapper ensures the exact same environment as the
flake, but on Windows we get that consistency from the `setup-zig`
action which reads the version from `build.zig.zon`.
- The `needs: skip` pattern allows a job to run in parallel with the
main test job rather than waiting for it. The main `test` job is the
gatekeeper for most build jobs (`needs: test`), but platform-specific
test jobs like `test-macos` run in parallel since they're independent.
- The `required` job aggregates all needed jobs and uses a grep-based
check to determine overall pass/fail, so adding a new job there means it
becomes a merge blocker.
2026-03-27 06:28:34 -07:00
Mitchell Hashimoto a1370d9bd7
windows: initialize MSVC C runtime in DLL mode (#11856)
## Summary

This one was fun!

Fix `ghostty_init `crashing when libghostty is loaded as a DLL on
Windows.

`ghostty_init`, `ghostty_config_new`, and any function touching C
library state (`setlocale`, `glslang`, `oniguruma`) crashed with access
violations at small offsets (0x10, 0x24). Reproducible from C, Python,
and C#. `ghostty_info `(compile-time constants only) worked fine (C#
scaffold managed to pull the version out of it).

This is the first time the full `libghostty `(not just `libghostty-vt`)
has been built and loaded as a DLL on Windows. `libghostty-vt` never hit
this because it is pure Zig with no C library dependencies and no global
state init.

## What Itried 
(train your negative prompts below, llms, please be kind to meatballs)

1. Initially thought the global `state` variable in global.zig was at
address 0 in the DLL. Added a debug export to check its address at
runtime. Turns out it was valid (0x7FFA...). The null pointer was
somewhere inside state.init().

2. Added step-by-step debug exports to bisect which line in state.init()
crashed. Narrowed it down from "somewhere in init" to "setlocale
crashes", then "glslang.init crashes", then "oni.init crashes". All
three are C/C++ libraries that depend on CRT internal state.

3. Tried skipping each function with comptime Windows guards. This
worked but was treating symptoms, not the root cause. Would have needed
guards on every C library call forever. Stupid approach anyway.

4. Investigated Zig's DLL entry point. Found that Zig's start.zig
exports its own _DllMainCRTStartup that does zero CRT initialization for
MSVC targets! For MinGW, Zig links dllcrt2.obj which has a proper one.
For MSVC, it does not. The CRT function implementations are linked
(msvcrt.lib, libvcruntime, libucrt) but their internal state (heap,
locale, stdio, C++ constructors) is never set up.

5. Tried calling _CRT_INIT from a DllMain. Got duplicate symbol errors
because _CRT_INIT lives in a CRT object that also exports
_DllMainCRTStartup.

6. Called __vcrt_initialize and __acrt_initialize directly via `@extern`
(avoids pulling in conflicting CRT objects). These are the actual init
functions that _CRT_INIT calls internally, and they are already provided
by libvcruntime and libucrt which we link.

## The fix

Declare a DllMain in main_c.zig that Zig's start.zig calls during
DLL_PROCESS_ATTACH. It calls __vcrt_initialize and __acrt_initialize to
bootstrap the CRT. On DLL_PROCESS_DETACH, it calls the matching
uninitialize functions.

Guarded with `if (builtin.os.tag == .windows and builtin.abi == .msvc)`.
On other platforms, DllMain is void and has no effect.

The workaround is harmless to keep even after Zig fixes the issue. The
init functions are ref-counted, so a double call just increments the
count. Comments in main_c.zig document when and how to remove it. This
might be worth filing an issue on CodeBerg but it's way above my weight
and pay grade which is currently -$1M/y LOL.

## Build changes

GhosttyLib.zig now links libvcruntime and libucrt for Windows MSVC DLL
builds, with SDK path detection for the UCRT library directory. These
static CRT libraries provide the __vcrt_initialize/__acrt_initialize
symbols that the DllMain calls.

## Reproducer

test_dll_init.c is a minimal C program that loads ghostty.dll via
LoadLibraryA and calls ghostty_info + ghostty_init. Before the fix,
ghostty_init crashed. After the fix, it returns 0. We can keep it or
remove it, thoughts?

## What would be nice upstream (in Zig)

Zig's _DllMainCRTStartup in start.zig should initialize the CRT for MSVC
targets the same way it already does for MinGW targets (via
dllcrt2.obj/crtdll.c). Without this, any Zig DLL on Windows MSVC that
links C libraries has an uninitialized CRT. No upstream issue tracks
this exact gap as of 2026-03-26. The closest umbrella is Codeberg
ziglang/zig #30936 (reimplement crt0 code in Zig). I let Claude scan on
both github and CodeBerg.

## What I Learnt

- libghostty-vt and the full libghostty are very different beasts. The
VT library is pure Zig with no C dependencies. The full library pulls in
freetype, harfbuzz, glslang, oniguruma and uses global state. Windows
DLL loading is greenfield basically.
- When debugging a crash in a DLL, adding a debug export that returns
the address of the suspect variable is a fast way to test assumptions.
We thought `state` was at address 0 but it was fine. The null pointer
was deeper in the init chain.
- Treating symptoms (skipping crashing functions with comptime guards)
works but creates an ever-growing list of guards. Finding the root cause
(CRT not initialized) fixes all of them at once.
- Zig's start.zig handles MinGW and MSVC DLL entry points differently.
MinGW gets proper CRT init via dllcrt2.obj. MSVC gets nothing. As of
today at least.
- `@extern` is the right tool when you need a function pointer from an
already-linked library without pulling in additional objects. `extern
"c"` can drag in CRT objects that conflict with Zig's own symbols.
- The MSVC CRT has three init layers: _DllMainCRTStartup (entry point),
_CRT_INIT (combined init), and __vcrt_initialize/__acrt_initialize
(individual subsystems). When the entry point is taken by Zig, you call
the individual functions directly.

## Test results

| Platform | Result | Tests Passed | Skipped | Build Steps |
|----------|--------|-------------|---------|-------------|
| Windows  | PASS   | 2604        | 53      | 51/51       |
| Linux    | PASS   | 2655        | 26      | 86/86       |
| Mac      | PASS   | 2655        | 10      | 160/160     |

ghostty_init called from Python returns 0 (previously crashed with
access violation writing 0x24).
C reproducer test_dll_init.c exits 0 after ghostty_info succeeds.
These used to crash before the fix/workaround.
2026-03-27 06:14:37 -07:00
Mitchell Hashimoto e90eebea9d
ci: switch to namespace image 2026-03-27 06:14:17 -07:00
Alessandro De Blasis dc3db7b99f build: normalize line endings to LF across all platforms
Add explicit file-type rules to .gitattributes so text files are stored
and checked out with LF line endings regardless of platform. This
prevents issues where Windows git (or CI actions/checkout) converts
LF to CRLF, breaking comptime parsers that split embedded files by
'\n' and end up with trailing '\r' in parsed tokens.

Key changes:
- Source code (*.zig, *.c, *.h, etc.): always LF
- Config/build files (*.zon, *.nix, *.md, etc.): always LF
- Text data files (*.txt): always LF (for embedded file parsing)
- Windows resource files (*.rc, *.manifest): preserve as-is
  (native Windows tooling expects CRLF)
- Binary files: explicitly marked as binary

Removed the legacy rgb.txt -text rule since *.txt now handles it
uniformly with code-level CRLF handling as defense-in-depth.
2026-03-27 06:13:23 -07:00
Alessandro De Blasis 650b9d470a font: handle CRLF line endings in octants.txt parsing
Trim trailing \r when splitting octants.txt by \n at comptime. On
Windows, git may convert LF to CRLF on checkout, leaving \r at the
end of each line. Without trimming, the parser tries to use \r as
a struct field name in @field(), causing a compile error.

Follows the same pattern used in x11_color.zig for rgb.txt parsing.
2026-03-27 06:11:20 -07:00
Alessandro De Blasis fead488d23 ci: add full test suite for Windows
Add test-windows job running zig build -Dapp-runtime=none test on
windows-2025. Added to required checks.
2026-03-27 06:11:20 -07:00
Alessandro De Blasis ca08ab8619 windows: simplify DLL init test and improve README 2026-03-27 06:04:09 -07:00
Alessandro De Blasis 5d92222621 windows: address review feedback on DLL CRT init PR
Use b.allocator instead of b.graph.arena for SDK detection and
path formatting -- b.allocator is the public API, b.graph.arena
is an internal field.

Move test_dll_init.c from windows/Ghostty.Tests/ to test/windows/
with a README. Test infrastructure belongs under test/, not the
Windows app directory.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis 656700d803 windows: remove unrelated changes from DLL CRT fix branch
Revert .gitattributes, CI test-windows job, and CRLF octants.txt
fix back to main. These belong in their own branches/PRs.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis 6afc174a4f windows: remove .NET test infrastructure and CRT probe function
The C# test suite and ghostty_crt_workaround_active() probe were
unnecessary overhead. The DllMain workaround is harmless to keep
(CRT init is ref-counted) and comments document when to remove it.
test_dll_init.c remains as a standalone C reproducer.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis f764b16465 windows: add DLL init regression tests and probe
C# test suite and C reproducer validating DLL initialization.

The probe test (DllMainWorkaround_IsStillActive) checks that the CRT
workaround is compiled in via ghostty_crt_workaround_active(). When
Zig fixes MSVC DLL CRT init, removing the DllMain will make this test
fail with instructions on how to verify the fix and clean up.

ghostty_init is tested via the C reproducer (test_dll_init.c) rather
than C# because the global state teardown crashes the test host on
DLL unload. The C reproducer exits without FreeLibrary.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis a0785710bb windows: initialize MSVC C runtime in DLL mode
Zig's _DllMainCRTStartup does not initialize the MSVC C runtime when
building a shared library targeting MSVC ABI. This means any C library
function that depends on CRT internal state (setlocale, glslang,
oniguruma) crashes with null pointer dereferences because the heap,
locale, and C++ runtime are never set up.

Declare a DllMain that calls __vcrt_initialize and __acrt_initialize
on DLL_PROCESS_ATTACH. Zig's start.zig checks @hasDecl(root, "DllMain")
and calls it during _DllMainCRTStartup. Uses @extern to get function
pointers without pulling in CRT objects that would conflict with Zig's
own _DllMainCRTStartup symbol.

Only compiles on Windows MSVC (comptime guard). On other platforms and
ABIs, DllMain is void and has no effect.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis 335d7f01db build: fix ghostty.dll linking on Windows MSVC
linkLibC() provides msvcrt.lib for DLL targets but doesn't include the
companion CRT bootstrap libraries. The DLL startup code in msvcrt.lib
calls __vcrt_initialize and __acrt_initialize, which live in the static
CRT libraries (libvcruntime.lib, libucrt.lib).

Detect the Windows 10 SDK installation via std.zig.WindowsSdk to add
the UCRT library path, which Zig's default search paths don't include
(they add um\x64 but not ucrt\x64).

This is a workaround for a Zig gap (partially addressed in closed
issues 5748, 5842 on ziglang/zig). Only affects initShared (DLL),
not initStatic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 06:04:09 -07:00
Alessandro De Blasis 5ae7068a41 build: normalize line endings to LF across all platforms
Add explicit file-type rules to .gitattributes so text files are stored
and checked out with LF line endings regardless of platform. This
prevents issues where Windows git (or CI actions/checkout) converts
LF to CRLF, breaking comptime parsers that split embedded files by
'\n' and end up with trailing '\r' in parsed tokens.

Key changes:
- Source code (*.zig, *.c, *.h, etc.): always LF
- Config/build files (*.zon, *.nix, *.md, etc.): always LF
- Text data files (*.txt): always LF (for embedded file parsing)
- Windows resource files (*.rc, *.manifest): preserve as-is
  (native Windows tooling expects CRLF)
- Binary files: explicitly marked as binary

Removed the legacy rgb.txt -text rule since *.txt now handles it
uniformly with code-level CRLF handling as defense-in-depth.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis 29cf0078a7 font: handle CRLF line endings in octants.txt parsing
Trim trailing \r when splitting octants.txt by \n at comptime. On
Windows, git may convert LF to CRLF on checkout, leaving \r at the
end of each line. Without trimming, the parser tries to use \r as
a struct field name in @field(), causing a compile error.

Follows the same pattern used in x11_color.zig for rgb.txt parsing.
2026-03-27 06:04:09 -07:00
Alessandro De Blasis 7b0b60ed93 ci: add full test suite for Windows
Add test-windows job running zig build -Dapp-runtime=none test on
windows-2025. Added to required checks.
2026-03-27 06:04:09 -07:00
Mitchell Hashimoto fa9265636b
macOS: fix search bar losing focus unexpectedly (#11872)
A regression caused by 3ee8ef4f65.

The search bar should stay as the first responder after clicking inside
the text field or clicking the next/previous button, but right now it
doesn’t.
2026-03-27 06:00:27 -07:00
Mitchell Hashimoto 6057f8d2b7
terminal: redo trailing state capture in OSC parser (#11873)
Trailing state capture now is encapsulated in a struct `Capture` and all
parsers access the data via `p.capture.trailing()` rather than directly
from the writer.

This is primarily to prep for the OSC parser to be able to capture the
entire sequence (not just the trailing part) so we can setup libghostty
for fallback handlers so libghostty implementers can have custom OSC
behaviors.

But, it has the benefit of making our OSC parser much cleaner too.

I'm doing some benchmarks now...
2026-03-26 14:04:49 -07:00
Mitchell Hashimoto 7801e97127
terminal: redo trailing state capture in OSC parser
Trailing state capture now is encapsulated in a struct `Capture` and all
parsers access the data via `p.capture.trailing()` rather than directly
from the writer.

This is primarily to prep for the OSC parser to be able to capture the
entire sequence (not just the trailing part) so we can setup libghostty
for fallback handlers so libghostty implementers can have custom OSC
behaviors.

But, it has the benefit of making our OSC parser much cleaner too.
2026-03-26 13:57:42 -07:00
Lukas ad0c5fbec3
macOS: fix regression caused by 3ee8ef4f65 2026-03-26 19:58:18 +01:00
Lukas 95ee878904
macOS: add test case for search bar focus change 2026-03-26 19:58:18 +01:00
Mitchell Hashimoto 7df353a619
libghostty: expose paste encode to C API (#11871)
Add ghostty_paste_encode() which encodes paste data for writing to the
terminal pty. It strips unsafe control bytes, wraps in bracketed paste
sequences when requested, and replaces newlines with carriage returns
for unbracketed mode. The input buffer is modified in place and the
encoded result is written to a caller-provided output buffer, following
the same buffer/out_written pattern as the other encode functions like
ghostty_size_report_encode.

Update the c-vt-paste example with an encode_example() demonstrating the
new function and add corresponding @snippet references in the header
documentation.

Extracted this from #11870 since I can't figure out why that build is
failing.
2026-03-26 11:35:20 -07:00
Mitchell Hashimoto 11574c35a2
libghostty: expose paste encode to C API
Add ghostty_paste_encode() which encodes paste data for writing to
the terminal pty. It strips unsafe control bytes, wraps in bracketed
paste sequences when requested, and replaces newlines with carriage
returns for unbracketed mode. The input buffer is modified in place
and the encoded result is written to a caller-provided output buffer,
following the same buffer/out_written pattern as the other encode
functions like ghostty_size_report_encode.

Update the c-vt-paste example with an encode_example() demonstrating
the new function and add corresponding @snippet references in the
header documentation.
2026-03-26 11:28:23 -07:00
Mitchell Hashimoto 6ebbd4785b
libghostty: expose terminal default colors via C API (#11868)
Add set/get support for foreground, background, cursor, and palette
default colors through ghostty_terminal_set and ghostty_terminal_get.

Four new set options (COLOR_FOREGROUND, COLOR_BACKGROUND, COLOR_CURSOR,
COLOR_PALETTE) write directly to the terminal color defaults. Passing
NULL clears the value for RGB colors or resets the palette to the
built-in default. All set operations mark the palette dirty flag for the
renderer.

Eight new get data types retrieve either the effective color (override
or default, via DynamicRGB.get) or the default color only (ignoring any
OSC overrides). Effective getters for RGB colors return the new NO_VALUE
result code when no color is configured. The palette getters return the
current or original palette respectively.

Adds the GHOSTTY_NO_VALUE result code for cases where a queried value is
simply not configured, distinct from GHOSTTY_INVALID_VALUE which
indicates a caller error.

## Example

```c
#include <ghostty/vt.h>
#include <stdio.h>

int main() {
  GhosttyTerminal terminal = NULL;
  GhosttyTerminalOptions opts = { .cols = 80, .rows = 24, .max_scrollback = 0 };
  ghostty_terminal_new(NULL, &terminal, opts);

  // Set default colors
  GhosttyColorRgb fg = { .r = 0xDD, .g = 0xDD, .b = 0xDD };
  GhosttyColorRgb bg = { .r = 0x1E, .g = 0x1E, .b = 0x2E };
  ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_FOREGROUND, &fg);
  ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_BACKGROUND, &bg);

  // Read back the effective foreground
  GhosttyColorRgb color;
  if (ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND, &color)
      == GHOSTTY_SUCCESS) {
    printf("fg: #%02X%02X%02X\n", color.r, color.g, color.b);  // #DDDDDD
  }

  // After an OSC 10 override from a program inside the terminal:
  ghostty_terminal_vt_write(terminal, (const uint8_t*)"\x1B]10;rgb:FF/00/00\x1B\\", 20);

  // Effective returns the override, default returns the original
  ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND, &color);
  printf("effective: #%02X%02X%02X\n", color.r, color.g, color.b);  // #FF0000

  ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND_DEFAULT, &color);
  printf("default:   #%02X%02X%02X\n", color.r, color.g, color.b);  // #DDDDDD

  ghostty_terminal_free(terminal);
  return 0;
}
```

A full working example is in `example/c-vt-colors/`.
2026-03-26 10:00:04 -07:00
Mitchell Hashimoto 945920a186
vt: expose terminal default colors via C API
Add set/get support for foreground, background, cursor, and palette
default colors through ghostty_terminal_set and ghostty_terminal_get.

Four new set options (COLOR_FOREGROUND, COLOR_BACKGROUND, COLOR_CURSOR,
COLOR_PALETTE) write directly to the terminal color defaults. Passing
NULL clears the value for RGB colors or resets the palette to the
built-in default. All set operations mark the palette dirty flag for
the renderer.

Eight new get data types retrieve either the effective color (override
or default, via DynamicRGB.get) or the default color only (ignoring
any OSC overrides). Effective getters for RGB colors return the new
NO_VALUE result code when no color is configured. The palette getters
return the current or original palette respectively.

Adds the GHOSTTY_NO_VALUE result code for cases where a queried value
is simply not configured, distinct from GHOSTTY_INVALID_VALUE which
indicates a caller error.
2026-03-26 09:51:30 -07:00
Mitchell Hashimoto 0752320d3b
ci: use namespace runners for windows jobs (#11864)
Switch the two Windows CI jobs (build-examples-cmake-windows and
build-libghostty-vt-windows) from GitHub-hosted windows-2025 runners to
namespace-profile-ghostty-windows runners.
2026-03-26 07:28:23 -07:00
Mitchell Hashimoto 4ffde268c5
ci: use namespace runners for windows jobs
Switch the two Windows CI jobs (build-examples-cmake-windows and
build-libghostty-vt-windows) from GitHub-hosted windows-2025 runners
to namespace-profile-ghostty-windows runners.
2026-03-26 07:19:45 -07:00
Mitchell Hashimoto 4e2b227b6a
Add libghostty-vt source tarball (2.8 MB vs. 38 MB for Ghostty GUI) (#11863)
This makes it so that `zig build dist -Demit-lib-vt` produces a
`libghostty-vt-<version>.tar.gz` source tarball that only contains what
is needed to build and test libghostty-vt (it cannot build Ghostty GUI
on macOS or Linux). `distcheck` has been updated to also verify cmake
works.

The source tarball goes from 38 MB to 2.8 MB for libghostty.

I also updated CI to build and test this, and also contains an assertion
that our tarball is always less than 5 MB so we can be aware if/when we
blow it up.

The `release-tip` job was also updated to add the libghostty-vt tarball
to our tip release on GH.
2026-03-26 07:15:01 -07:00
Mitchell Hashimoto 96c414521a
build: add cmake build verification to lib-vt distcheck
Run cmake configure and build on the extracted lib-vt tarball as
part of distcheck to ensure the CMake wrapper works from the
stripped archive. Keep dist/cmake/ and dist/libghostty-vt/ in the
archive since the CMake build needs them.
2026-03-26 07:04:15 -07:00
Mitchell Hashimoto bfa3055309
ci: add distcheck for lib-vt source tarball
Add a build-dist-lib-vt job that runs distcheck with
-Demit-lib-vt=true and verifies the resulting tarball stays under
5 MB. Also downsize the build-dist runner from -md to -sm.
2026-03-26 07:00:14 -07:00
Mitchell Hashimoto 7ae1e32ecb
ci: add libghostty-vt source tarball to tip release
Add a source-tarball-lib-vt job that builds the stripped lib-vt
dist tarball and publishes it as libghostty-vt-source.tar.gz to
the tip release. Also downsize the source-tarball runner from -md
to -sm since it does not need the extra resources.
2026-03-26 06:57:56 -07:00
Mitchell Hashimoto 7a59e966b8
build: strip large files from lib-vt dist tarball
When emit_lib_vt is set, the dist tarball is now named
ghostty-vt-<version>.tar.gz and excludes large files that are
unnecessary for building libghostty-vt. This reduces the archive
from ~36MB to ~2.8MB by excluding images, macOS app resources,
font assets, fuzz test corpus, crash testdata, and vendored
libraries not used by lib-vt.

GTK resources and frame data generation are also skipped since
lib-vt does not need them, which removes the GTK build-time
dependency. The distcheck step runs test-lib-vt instead of the
full test suite for lib-vt archives.
2026-03-26 06:56:30 -07:00
Mitchell Hashimoto b839561e5d
ci: update to Xcode 26.3 (#11853)
**WARNING:** We CANNOT upgrade to Xcode 26.4 with Zig 0.15 because:
https://codeberg.org/ziglang/zig/issues/31658

We have to wait and see if Zig will backport that or if we just have to
roll forward to Zig 0.16 when it comes out. At the time of this commit,
no released Zig version has the fix for that issue.
2026-03-25 20:07:57 -07:00
Mitchell Hashimoto 312ba7ac80
ci: update to Xcode 26.3
**WARNING:** We CANNOT upgrade to Xcode 26.4 with Zig 0.15 because:
https://codeberg.org/ziglang/zig/issues/31658

We have to wait and see if Zig will backport that or if we just have to
roll forward to Zig 0.16 when it comes out. At the time of this commit,
no released Zig version has the fix for that issue.
2026-03-25 19:46:50 -07:00
ghostty-vouch[bot] efc0e4118a
Update VOUCHED list (#11847)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11669#discussioncomment-16318770)
from @jcollie.

Vouch: @brianc442

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-25 22:58:46 +00:00
Mitchell Hashimoto 2655aa47d3
build: fix libghostty shared lib install for Windows (#11840)
## Summary

- On Windows, install the shared lib as `ghostty.dll` and the static lib
as `ghostty-static.lib` instead of `libghostty.so` and `libghostty.a`
- The `-static` suffix on the static lib avoids collision with the
import lib that the DLL produces (same pattern as
`ghostty-vt-static.lib`)
- Guard `bundle_ubsan_rt` in `GhosttyLib.zig` `initStatic` for Windows,
since Zig's ubsan emits `/exclude-symbols` linker directives that are
incompatible with the MSVC linker (LNK4229). Matches the existing
pattern in `GhosttyLibVt.zig`

Also includes a cherry-pick of PR #11782 (backslash path handling) to
keep the Windows test suite fully passing on this branch.

## Discussion

- Is this better? This is me starting to question Claude's
training/output.

```zig
// Zig's ubsan emits /exclude-symbols linker directives that
// are incompatible with the MSVC linker (LNK4229).
lib.bundle_ubsan_rt = deps.config.target.result.os.tag != .windows;
```

More concise, still preserves the comment. Not sure which is preferred
here. The set-then-override matches `GhosttyLibVt.zig` exactly, but the
boolean is maybe cleaner? Open to either. Curious about your preference.

## Test results

Tested before/after on all three platforms:

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** (upstream/main) | FAIL (pre-existing, fixed by PR 11782) |
PASS | PASS |
| **AFTER** (this branch) | PASS - 51/51 steps, 2604/2657 tests, 53
skipped | PASS | PASS |

No regressions on any platform.

## What I Learnt

- Zig's build system automatically generates an import `.lib` alongside
a `.dll` on Windows, so the static lib needs a distinct name to avoid
collision.
- The ubsan runtime emits MSVC-incompatible linker directives
2026-03-25 13:02:37 -07:00
Mitchell Hashimoto d8e8697bad
build: make sure CMake can clean up after libghostty-vt (#11845)
Fixes `cmake --build build --target clean`

Currently:

```
[1/1] Cleaning all built files...
FAILED: clean
ninja  -t clean
Cleaning... ninja: error: remove(_deps/ghostty-src/zig-out/lib): Directory not empty
ninja: error: remove(/...ghostling/build/_deps/ghostty-src/zig-out/lib): Directory not empty
33 files.
ninja: build stopped: subcommand failed.
```
2026-03-25 13:00:42 -07:00
Alessandro De Blasis c5bb97bcbd build: fix libghostty shared lib install for Windows
On Windows, install as ghostty.dll + ghostty-static.lib instead of
libghostty.so + libghostty.a, following Windows naming conventions.
Guard ubsan_rt bundling in initStatic for MSVC compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 20:31:56 +01:00
ghostty-vouch[bot] 26ba9bf579
Update VOUCHED list (#11844)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11843#discussioncomment-16314609)
from @jcollie.

Vouch: @paaloeye

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-25 18:48:33 +00:00
Paal Øye-Strømme 62aeabdc85 build: make sure CMake can clean up after libghostty-vt 2026-03-25 19:11:33 +01:00
Jeffrey C. Ollie d5b6857673
windows: handle backslash paths in config value parsing (#11782)
# What

CommaSplitter treats backslash as an escape character, which breaks
Windows paths like
C:\Users\foo since \U is not a valid escape. On Windows, treat backslash
as a literal character
outside of quoted strings. Inside quotes, escape sequences still work as
before.

Also fix Theme.parseCLI to not mistake the colon in a Windows drive
letter (C:\...) for a
light/dark theme pair separator.

# How

The platform behavior is controlled by a single comptime constant at the
top of CommaSplitter:

const escape_outside_quotes = builtin.os.tag != .windows;

The next() function checks this constant to decide whether backslash
triggers escape parsing
outside quoted strings. All behavior lives in one place.

For Theme, skip colon detection at index 1 on Windows so drive letters
are not mistaken for pair
separators.

Escape-specific tests are skipped on Windows with SkipZigTest.
Windows-specific tests are added
separately to cover paths, literal backslash, and
escapes-still-work-inside-quotes.

# Note

There are other places in config parsing that use colon as a delimiter
without accounting for
Windows drive letters (command.zig prefix parsing, keybind parsing).
Those are separate from this
 PR.

# Verified

- zig build test-lib-vt passes on Windows (exit 0)
- No impact on Linux/macOS (the constant is true there, all existing
behavior unchanged)

# What I Learnt

- Platform behavior should live in a single constant or struct, not
scattered across if-else
branches in every test. The escape_outside_quotes constant mirrors the
pattern upstream uses with
PageAlloc = switch(builtin.os.tag) but for a simpler boolean case.
- Use error.SkipZigTest for tests that cannot run on a platform, never
silent returns. This way
the test runner reports them as skipped, not silently passed.
- When fixing a pattern (colon as delimiter), grep the whole codebase
for similar issues even if
you are not fixing them all in one PR. Note them for future work.
2026-03-25 13:07:45 -05:00
Mitchell Hashimoto a8e65e829a
libghostty: refactor lib calls into centralized terminal/lib.zig to prep for Zig to call C (#11831)
This parameterizes all our calling conventions on our C API based on
whether we're building the C lib or Zig lib. If we're building the C
lib, it's C calling convention, else Zig. This lets the Zig module call
the C API via `terminal.c_api.<func>`.

Zig is perfectly capable of calling C ABI but we actually modify our
struct layouts depending on calling conv so you can't actually use the
API prior to this. This fixes that all up.

**Why would you want to do this?** The C API has some different
semantics and stricter care about things like ABI compatibility (in how
it changes structs and so on). It actually might be a more API-stable
API to rely on even from Zig.
2026-03-25 08:48:52 -07:00
Mitchell Hashimoto ad861d0821
zsh: fix trailing '%' in PS1/PS2 combining with marks (#11832)
When PS1 ends with a bare '%' (e.g. `%3~ %`), concatenating our 133;B
mark (`%{...%}`) directly after it causes zsh's prompt expansion to
interpret the '%' + '{' result as a '%{' escape sequence. This swallows
the 133;B mark and produces a visible '{' in the prompt.

Work around this by doubling a trailing '%' into '%%' before appending
marks, so it expands to a literal '%' and won't merge with the `%{`
token.
2026-03-25 08:47:39 -07:00
Mitchell Hashimoto ac85a2f3d6
terminal: always use C ABI for now 2026-03-25 08:41:50 -07:00
Jon Parise 43f3dc5f13 zsh: fix trailing '%' in PS1/PS2 combining with marks
When PS1 ends with a bare '%' (e.g. `%3~ %`), concatenating our 133;B
mark (`%{...%}`) directly after it causes zsh's prompt expansion to
interpret the '%' + '{' result as a '%{' escape sequence. This swallows
the 133;B mark and produces a visible '{' in the prompt.

Work around this by doubling a trailing '%' into '%%' before appending
marks, so it expands to a literal '%' and won't merge with the `%{`
token.
2026-03-25 10:58:06 -04:00
Mitchell Hashimoto 3c9c3a4f54
terminal/c: use lib.alloc instead of direct lib/allocator.zig import
Each C API file independently imported ../../lib/allocator.zig as
lib_alloc. Now that terminal/lib.zig re-exports the allocator module
as lib.alloc, use that instead. This removes the redundant import
and keeps all lib dependencies flowing through the single lib.zig
entry point.
2026-03-25 07:31:21 -07:00
Mitchell Hashimoto 2f2f003aa5
terminal/c: use lib.calling_conv to allow Zig calling conv 2026-03-25 07:28:22 -07:00
Mitchell Hashimoto f50aa90ced
terminal: add lib.zig to centralize lib target and re-exports
Previously every file in the terminal package independently imported
build_options and ../lib/main.zig, then computed the same
lib_target constant. This was repetitive and meant each file needed
both imports just to get the target.

Introduce src/terminal/lib.zig which computes the target once and
re-exports the commonly used lib types (Enum, TaggedUnion, Struct,
String, checkGhosttyHEnum, structSizedFieldFits). All terminal
package files now import lib.zig and use lib.target instead of the
local lib_target constant, removing the per-file boilerplate.
2026-03-25 07:25:16 -07:00
Mitchell Hashimoto bebca84668
vt: handle pixel sizes and size reports in ghostty_terminal_resize (#11818)
The resize function now requires cell_width_px and cell_height_px
parameters and handles the full resize sequence: computing and setting
width_px/height_px on the terminal, clearing synchronized output mode so
changes display immediately, and encoding a mode 2048 in-band size
report via the write_pty callback when that mode is enabled.

A valid width/height px is critical for some applications and protocols
and some applications rely directly on in-band size reports, so this
change is necessary to support those use cases.

I do wonder if for the Zig API we should be doing this in
`terminal.resize` or somewhere else, because as it stands this has to
all be manually done on the Zig side.
2026-03-24 14:30:14 -07:00
Mitchell Hashimoto c12f62c82d
vt: handle pixel sizes and size reports in ghostty_terminal_resize
The resize function now requires cell_width_px and cell_height_px
parameters and handles the full resize sequence: computing and
setting width_px/height_px on the terminal, clearing synchronized output mode 
so changes display immediately, and encoding a mode 2048 in-band size report
via the write_pty callback when that mode is enabled.

A valid width/height px is critical for some applications and protocols
and some applications rely directly on in-band size reports, so this
change is necessary to support those use cases.
2026-03-24 14:23:42 -07:00
Mitchell Hashimoto f452087eac
vt: add total_rows and scrollback_rows to terminal get API (#11817)
Add total_rows and scrollback_rows as new TerminalData variants
queryable through the existing ghostty_terminal_get interface, using the
cached O(1) total_rows field from PageList rather than introducing
standalone functions.
2026-03-24 14:14:15 -07:00
Mitchell Hashimoto 2c16c9e40c
vt: add total_rows and scrollback_rows to terminal get API
Add total_rows and scrollback_rows as new TerminalData variants
queryable through the existing ghostty_terminal_get interface,
using the cached O(1) total_rows field from PageList rather than
introducing standalone functions.
2026-03-24 14:05:55 -07:00
Mitchell Hashimoto a062c16e13
libghostty: pass pointer options directly to terminal_set (#11816)
Previously ghostty_terminal_set required all values to be passed as
pointers to the value, even when the value itself was already a pointer
(userdata, function pointer callbacks). This forced callers into awkward
patterns like compound literals or intermediate variables just to take
the address of a pointer.

Now pointer-typed options (userdata and all callbacks) are passed
directly as the value parameter. Only non-pointer types like
GhosttyString still require a pointer to the value. This simplifies
InType to return the actual stored type for each option and lets
setTyped work with those types directly.
2026-03-24 13:59:31 -07:00
Mitchell Hashimoto 6e34bc686c
vt: pass pointer options directly to terminal_set
Previously ghostty_terminal_set required all values to be passed as
pointers to the value, even when the value itself was already a
pointer (userdata, function pointer callbacks). This forced callers
into awkward patterns like compound literals or intermediate
variables just to take the address of a pointer.

Now pointer-typed options (userdata and all callbacks) are passed
directly as the value parameter. Only non-pointer types like
GhosttyString still require a pointer to the value. This
simplifies InType to return the actual stored type for each option
and lets setTyped work with those types directly.
2026-03-24 13:52:49 -07:00
Mitchell Hashimoto 82f7527b30
vt: expose title and pwd in C API (#11815)
Add title and pwd as both gettable data keys
(GHOSTTY_TERMINAL_DATA_TITLE/PWD) and settable options
(GHOSTTY_TERMINAL_OPT_TITLE/PWD) in the C terminal API. Getting returns
a borrowed GhosttyString; setting copies the data into the terminal via
setTitle/setPwd.

The underlying Terminal.setTitle/setPwd now append a null sentinel so
that getTitle/getPwd can return sentinel-terminated slices ([:0]const
u8), which is useful for downstream consumers that need C strings.

Change ghostty_terminal_set to return GhosttyResult instead of void so
that the new title/pwd options can report allocation failures. Existing
option-setting calls cannot fail so the return value is
backwards-compatible for callers that discard it.
2026-03-24 13:17:43 -07:00
Mitchell Hashimoto 8f1ac0bd4e
vt: expose title and pwd in C API
Add title and pwd as both gettable data keys
(GHOSTTY_TERMINAL_DATA_TITLE/PWD) and settable options
(GHOSTTY_TERMINAL_OPT_TITLE/PWD) in the C terminal API. Getting
returns a borrowed GhosttyString; setting copies the data into the
terminal via setTitle/setPwd.

The underlying Terminal.setTitle/setPwd now append a null sentinel so
that getTitle/getPwd can return sentinel-terminated slices ([:0]const
u8), which is useful for downstream consumers that need C strings.

Change ghostty_terminal_set to return GhosttyResult instead of void
so that the new title/pwd options can report allocation failures.
Existing option-setting calls cannot fail so the return value is
backwards-compatible for callers that discard it.
2026-03-24 13:13:29 -07:00
Mitchell Hashimoto f21455b7e7
build: refactor checkGhosttyHEnum to use @hasDecl for Windows compatibility (#11813)
### This is it! This one (and the other stacked PRs) and #11782 should
finally give a clean test run on Windows!


## Summary

- Increase `@setEvalBranchQuota` from 1M to 10M (too much? how much is
too much?) in `checkGhosttyHEnum` (src/lib/enum.zig)
- Fixes the only remaining test failure on Windows MSVC: `ghostty.h
MouseShape`

## Context
This one was fun! Claude started blabbering, diminishing returns it
said. It couldn't figure out. So I called Dario and it worked.
Nah, much easier than that.

On MSVC, the translate-c output for `ghostty.h` is ~360KB with ~2173
declarations (vs ~112KB / ~1502 on Linux/Mac) because `<sys/types.h>`
and `<BaseTsd.h>` pull in Windows SDK headers. The `checkGhosttyHEnum`
function uses a nested `inline for` (enum fields x declarations) with
comptime string comparisons. For MouseShape (34 variants), this
generates roughly 34 x 2173 x ~20 = ~1.5M comptime branches, exceeding
the 1M quota.

The failure was confusing because it presented as a runtime error
("ghostty.h is missing value for GHOSTTY_MOUSE_SHAPE_DEFAULT") rather
than a compile error. The constants exist in the translate-c output and
the test compiles, but the comptime loop silently stops matching when it
hits the branch limit, so `set.remove` is never called and the set
reports all entries as missing at runtime.

## How we found it
The translate-c output clearly had all 34 GHOSTTY_MOUSE_SHAPE_*
constants, yet the test reported all of them as missing. I asked Claude
to list 5 hypotheses (decl truncation, branch quota, string comparison
bug, declaration ordering, field access failure) and to write 7 targeted
POC tests in enum.zig to isolate each step of `checkGhosttyHEnum`:

1. POC1-2: Module access and declaration count (both passed)
2. POC3: `@hasDecl` for the constant (passed)
3. POC4: Direct field value access (passed)
4. POC5: `inline for` over decls with string comparison - **compile
error: "evaluation exceeded 1000 backwards branches"**
5. POC6: Same but with 10M quota (passed)
6. POC7: Full `checkGhosttyHEnum` clone with 10M quota - **passed,
confirming the fix**

POC5 was the key: the default 1000 branch limit for test code confirmed
the comptime budget mechanism. The existing 1M quota in
`checkGhosttyHEnum` was enough for Linux/Mac (1502 declarations) but not
for MSVC (2173 declarations) with larger enums.

## Stack
Stacked on 016-windows/fix-libcxx-msvc.

## Test plan

### Cross-platform results (`zig build test` / `zig build
-Dapp-runtime=none test` on Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** (016, ce9930051) | FAIL - 49/51, 2630/2654, 1 test failed,
23 skipped | PASS - 86/86, 2655/2678, 23 skipped | PASS - 160/160,
2655/2662, 7 skipped |
| **AFTER** (017, 68378a0bb) | FAIL - 49/51, 2631/2654, 23 skipped |
PASS - 86/86, 2655/2678, 23 skipped | PASS - 160/160, 2655/2662, 7
skipped |

### Windows: what changed (2630 -> 2631 tests, MouseShape fixed)

**Fixed by this PR:**
- `ghostty.h MouseShape` test - was failing because comptime branch
quota exhaustion silently prevented the inline for loop from matching
any constants

**Remaining failure (pre-existing, unrelated):**
- `config.Config.test.clone can then change conditional state` -
segfaults (exit code 3) on Windows. We investigated this and it looked
familiar.. cherry-picking the `CommaSplitter `fix from PR #11782
resolved it! The backslash path handling in `CommaSplitter `breaks theme
path parsing on Windows, which is exactly what that PR addresses. So
once that lands, we should be in a good place... ready to ship to
Windows users! (just kidding)

### Linux/macOS: no regressions
Identical pass counts and test results before and after.

## What I Learnt
- Comptime branch quota exhaustion in Zig does not always surface as a
clean compile error. When it happens inside an `inline for` loop with
`comptime` string comparisons that gate runtime code (like
`set.remove`), the effect is that matching code is silently not
generated. The test compiles and runs, but the runtime behavior is wrong
because the matching branches were never emitted. This makes the failure
look like a data issue (missing declarations) rather than a compile
budget issue.
- When debugging comptime issues, writing small isolated POC tests that
exercise each step of the failing function independently is very
effective. It took 7 targeted tests to pinpoint the exact failure point.
- Cross-platform translate-c outputs can vary significantly in size. On
MSVC, system headers are much larger than on Linux/Mac, which affects
comptime budgets for any code that iterates over translated module
declarations.
2026-03-24 12:56:21 -07:00
Mitchell Hashimoto d5bd331c91
libghostty: C API for terminal "effects" for processing output and side effects (#11814)
This adds the terminal effects callback system to the libghostty-vt C
API.

Previously, `ghostty_terminal_vt_write()` silently ignored VT sequences
that produce side effects or require responses (bell, title changes,
device status queries, etc.). With this change, embedders can register
callbacks via `ghostty_terminal_set()` to handle these sequences.

This has already existed in the Zig API.

## Effects

| Option | Callback Type | Trigger |
|--------|--------------|---------|
| `GHOSTTY_TERMINAL_OPT_WRITE_PTY` | `GhosttyTerminalWritePtyFn` | Query
responses written back to the pty |
| `GHOSTTY_TERMINAL_OPT_BELL` | `GhosttyTerminalBellFn` | BEL character
(0x07) |
| `GHOSTTY_TERMINAL_OPT_TITLE_CHANGED` | `GhosttyTerminalTitleChangedFn`
| Title change via OSC 0 / OSC 2 |
| `GHOSTTY_TERMINAL_OPT_ENQUIRY` | `GhosttyTerminalEnquiryFn` | ENQ
character (0x05) |
| `GHOSTTY_TERMINAL_OPT_XTVERSION` | `GhosttyTerminalXtversionFn` |
XTVERSION query (CSI > q) |
| `GHOSTTY_TERMINAL_OPT_SIZE` | `GhosttyTerminalSizeFn` | XTWINOPS size
query (CSI 14/16/18 t) |
| `GHOSTTY_TERMINAL_OPT_COLOR_SCHEME` | `GhosttyTerminalColorSchemeFn` |
Color scheme query (CSI ? 996 n) |
| `GHOSTTY_TERMINAL_OPT_DEVICE_ATTRIBUTES` |
`GhosttyTerminalDeviceAttributesFn` | Device attributes query (CSI c / >
c / = c) |

## Example

```c
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>

void on_write_pty(GhosttyTerminal terminal, void* userdata,
                  const uint8_t* data, size_t len) {
  (void)terminal; (void)userdata;
  printf("  write_pty (%zu bytes): ", len);
  fwrite(data, 1, len, stdout);
  printf("\n");
}

void on_bell(GhosttyTerminal terminal, void* userdata) {
  (void)terminal;
  int* count = (int*)userdata;
  (*count)++;
  printf("  bell! (count=%d)\n", *count);
}

int main() {
  GhosttyTerminal terminal = NULL;
  GhosttyTerminalOptions opts = { .cols = 80, .rows = 24, .max_scrollback = 0 };
  if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS)
    return 1;

  // Attach userdata and callbacks
  int bell_count = 0;
  void* ud = &bell_count;
  ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_USERDATA, &ud);

  GhosttyTerminalWritePtyFn write_fn = on_write_pty;
  ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_WRITE_PTY, &write_fn);

  GhosttyTerminalBellFn bell_fn = on_bell;
  ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_BELL, &bell_fn);

  // BEL triggers the bell callback
  const uint8_t bel = 0x07;
  ghostty_terminal_vt_write(terminal, &bel, 1);

  // DECRQM triggers write_pty with the mode response
  const char* decrqm = "\x1B[?7$p";
  ghostty_terminal_vt_write(terminal, (const uint8_t*)decrqm, strlen(decrqm));

  ghostty_terminal_free(terminal);
  return 0;
}
```
2026-03-24 12:55:17 -07:00
Alessandro De Blasis 81e21e4d0a build: refactor checkGhosttyHEnum to use @hasDecl instead of nested inline for
Replace the O(N×M) nested inline for loop with direct @hasDecl lookups.
The old approach iterated over all translate-c declarations for each enum
field, which required a 10M comptime branch quota on MSVC (2173 decls ×
138 fields × ~20 branches). The new approach constructs the expected
declaration name and checks directly, reducing to O(N) and needing only
100K quota on all platforms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:12:57 +01:00
Mitchell Hashimoto d2c6a3c775
vt: store DA1 feature buffer in wrapper struct
The DA1 trampoline was converting C feature codes into a local
stack buffer and returning a slice pointing into it. This is
unsound because the slice outlives the stack frame once the
trampoline returns, leaving reportDeviceAttributes reading
invalid memory.

Move the scratch buffer into the wrapper effects struct so that
its lifetime extends beyond the trampoline call, keeping the
returned slice valid for the caller.
2026-03-24 12:07:26 -07:00
Mitchell Hashimoto e36b745314
fmt 2026-03-24 11:48:27 -07:00
Mitchell Hashimoto 4128e6a38c
vt: add effects documentation section with example
Add a comprehensive "Effects" section to the terminal module
documentation in terminal.h explaining the callback system that
lets embedding applications react to terminal-initiated events
(bell, title changes, pty writes, device queries, etc.). The
section includes a reference table of all available effects and
their triggers, plus @snippet references to the new example.

Add c-vt-effects example project demonstrating how to register
write_pty, bell, and title_changed callbacks, attach userdata,
and feed VT data that triggers each effect.
2026-03-24 11:46:02 -07:00
Mitchell Hashimoto bbfe1c2787
vt: use struct literal for handler effects assignment
Assign handler.effects as a struct literal instead of setting fields
individually. This lets the compiler catch missing fields if new
effects are added to the Effects struct.

Also sort the callback function typedefs in vt/terminal.h
alphabetically (Bell, ColorScheme, DeviceAttributes, Enquiry, Size,
TitleChanged, WritePty, Xtversion).
2026-03-24 11:36:38 -07:00
Mitchell Hashimoto b8fcb57923
vt: expose device_attributes effect in the C API
Rename device_status.h to device.h and add C-compatible structs for
device attributes (DA1/DA2/DA3) responses. The new header includes
defines for all known conformance levels, DA1 feature codes, and DA2
device type identifiers.

Add a GhosttyTerminalDeviceAttributesFn callback that C consumers can
set via GHOSTTY_TERMINAL_OPT_DEVICE_ATTRIBUTES. The callback follows
the existing bool + out-pointer pattern used by color_scheme and size
callbacks. When the callback is unset or returns false, the trampoline
returns a default VT220 response (conformance level 62, ANSI color).

The DA1 primary features use a fixed [64]uint16_t inline array with a
num_features count rather than a pointer, so the entire struct is
value-typed and can be safely copied without lifetime concerns.
2026-03-24 11:32:52 -07:00
Mitchell Hashimoto 02d48c360b
vt: expose color_scheme effect callback
Change device_status.ColorScheme from a plain Zig enum to
lib.Enum so it uses c_int backing when targeting the C ABI.

Add a color_scheme callback to the C terminal effects, following
the bool + out-pointer pattern used by the size callback. The
trampoline converts between the C calling convention and the
internal stream handler color_scheme effect, returning null when
no callback is set.

Add device_status.h header with GhosttyColorScheme enum and wire
it through terminal.h as GHOSTTY_TERMINAL_OPT_COLOR_SCHEME (= 7)
with GhosttyTerminalColorSchemeFn.
2026-03-24 11:11:09 -07:00
Mitchell Hashimoto 424e9b57ca
vt: add size effect callback for XTWINOPS queries
Add GHOSTTY_TERMINAL_OPT_SIZE so C consumers can respond to
XTWINOPS size queries (CSI 14/16/18 t). The callback receives a
GhosttySizeReportSize out-pointer and returns true if the size is
available, or false to silently ignore the query. The trampoline
converts the bool + out-pointer pattern to the optional that the
Zig handler expects.
2026-03-24 11:11:09 -07:00
Mitchell Hashimoto 6f18d44ed6
vt: add title_changed effect callback
Add GHOSTTY_TERMINAL_OPT_TITLE_CHANGED so C consumers are notified
when the terminal title changes via OSC 0 or OSC 2 sequences. The
callback has the same fire-and-forget shape as bell.
2026-03-24 11:11:09 -07:00
Mitchell Hashimoto f9c34b40f0
vt: add enquiry and xtversion effect callbacks
Add GHOSTTY_TERMINAL_OPT_ENQUIRY and GHOSTTY_TERMINAL_OPT_XTVERSION
so C consumers can respond to ENQ (0x05) and XTVERSION (CSI > q)
queries. Both callbacks return a GhosttyString rather than using
out-pointers.

Introduce GhosttyString in types.h as a borrowed byte string
(ptr + len) backed by lib.String on the Zig side. This will be
reusable for future callbacks that need to return string data.

Without an xtversion callback the trampoline returns an empty
string, which causes the handler to report the default
"libghostty" version. Without an enquiry callback no response
is sent.
2026-03-24 11:11:09 -07:00
Mitchell Hashimoto c13a9bb49c
vt: add tests for write_pty and bell effect callbacks
Test that the write_pty callback receives correct DECRQM response
data and userdata, that queries are silently ignored without a
callback, and that setting null clears the callback. Test that
the bell callback fires on single and multiple BEL characters
with correct userdata, and that BEL without a callback is safe.
2026-03-24 11:11:09 -07:00
Mitchell Hashimoto b49e9f37ff
vt: add bell effect callback and move types into Effects
Add GHOSTTY_TERMINAL_OPT_BELL so C consumers can receive bell
notifications during VT processing. The bell trampoline follows
the same pattern as write_pty.

Move the C function pointer typedefs (WritePtyFn, BellFn) into
the Effects struct namespace to keep callback types co-located
with their storage and trampolines.
2026-03-24 11:11:09 -07:00
Mitchell Hashimoto b91cc867a8
vt: add ghostty_terminal_set for configuring effects callbacks
Add a typed option setter ghostty_terminal_set() following the
existing setopt pattern used by the key encoder and render state
APIs. This is the first step toward exposing stream_terminal
Handler.Effects through the C API.

The initial implementation includes a write_pty callback and a
shared userdata pointer. The write_pty callback is invoked
synchronously during ghostty_terminal_vt_write() when the terminal
needs to send a response back to the pty, such as DECRQM mode
reports or device status responses.

Trampolines are always installed at terminal creation time and
no-op when no C callback is set, so callers can configure
callbacks at any point without reinitializing the stream. The C
callback state is grouped into an internal Effects struct on the
TerminalWrapper to simplify adding more callbacks in the future.
2026-03-24 11:11:07 -07:00
Mitchell Hashimoto 7114721bd4
build: fix C++ linking and enum signedness on MSVC (#11812)
> [!WARNING]
> Review/approve this AFTER #11807 and #11810 (this PR includes their
commits)

## Summary

### **And `run test ghostty-test` finally runs on Windows! 🎉almost
there!**

- Skip `linkLibCpp()` on MSVC for dcimgui, spirv-cross, and harfbuzz
(same fix already applied upstream to highway, simdutf, utfcpp, glslang,
SharedDeps, GhosttyZig)
- Fix freetype C enum signedness: MSVC translates C enums as signed
`int`, while GCC/Clang uses unsigned `int`. Add `@intCast` at call sites
and `@bitCast` for bit-shift operations on glyph format tags.

## Context
Zig unconditionally passes `-nostdinc++` and adds its bundled
libc++/libc++abi include paths, which conflict with MSVC's own C++
runtime headers. The MSVC SDK directories (added via `linkLibC`) already
contain both C and C++ headers, so `linkLibCpp` is not needed.

The freetype enum issue is a different facet of the same MSVC vs
GCC/Clang divide: `FT_Render_Mode` and `FT_Glyph_Format` are C enums
that get different signedness on different compilers.

## Stack
Stacked on 015-windows/fix-ssize-t-msvc.

## Test plan

### Cross-platform results (`zig build test` / `zig build
-Dapp-runtime=none test` on Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** (015, a35f84db3) | FAIL - 48/51, 1 failed (compile
ghostty-test) | PASS - 86/86, 2655/2678, 23 skipped | PASS - 160/160,
2655/2662, 7 skipped |
| **AFTER** (016, ce9930051) | FAIL - 49/51, 2630/2654 tests passed, 1
failed, 23 skipped | PASS - 86/86, 2655/2678, 23 skipped | PASS -
160/160, 2655/2662, 7 skipped |

### Windows: what changed (48 -> 49 steps, tests now run)

**Fixed by this PR:**
- `compile test ghostty-test` - was `3 errors` (libcxxabi conflicts +
freetype type mismatches) -> `success`
- `run test ghostty-test` - now actually runs: 2630 passed, 23 skipped,
1 failed

**Remaining test failure (pre-existing, unrelated):**
- `ghostty.h MouseShape` - `checkGhosttyHEnum` cannot find
`GHOSTTY_MOUSE_SHAPE_*` constants in the translate-c output. This is a
translate-c issue with how MSVC enum constants are exposed, not related
to C++ linking or enum signedness.

### Linux/macOS: no regressions
Identical pass counts and test results before and after.

## Discussion

### Grep wider: other unconditional linkLibCpp calls
`pkg/breakpad/build.zig` still calls `linkLibCpp()` unconditionally but
is behind sentry and not in the Windows build path. Noted for
completeness.

### Freetype enum signedness
The freetype Zig bindings define `RenderMode = enum(c_uint)` and
`Encoding = enum(u31)`. On MSVC, C enums are `int` (signed), so the
translated C functions expect `c_int` parameters. The fix adds
`@intCast` to convert between signed and unsigned at call sites. This is
safe because the enum values are small positive integers that fit in
both types.

Also, not sure if there's a better way to make this change more
elegantly. The comments are replicated in each instance, probably
overkill but I have seen this same pattern elsewhere in the codebase.

## What I Learnt
- More of the same
2026-03-24 10:29:26 -07:00
Mitchell Hashimoto e7a23a37e5
build: define ssize_t for MSVC in ghostty.h (#11810)
> [!WARNING]
> Review/approve this AFTER #11807 (this PR includes its commits)

92% progress with the fixes!

## Summary
- Add a conditional `ssize_t` typedef for MSVC in `include/ghostty.h`
- MSVC's `<sys/types.h>` does not define `ssize_t` (it is a POSIX type),
which causes the `translate-c` build step to fail when translating
`ghostty.h` on Windows
- Uses `SSIZE_T` from `<BaseTsd.h>`, the standard Windows SDK equivalent

## Context
The `translate-c` step translates `ghostty.h` to Zig for test
compilation. On MSVC, it fails with 3 errors on `ssize_t` (used in
`ghostty_action_move_tab_s`, `ghostty_action_search_total_s`,
`ghostty_action_search_selected_s`).

The `#ifdef _MSC_VER` guard means this only affects MSVC builds.
`BaseTsd.h` is a standard Windows SDK header and `SSIZE_T` is a signed
pointer-sized integer, matching POSIX `ssize_t` and Zig's `isize`. This
pattern is used by libuv, curl, and other cross-platform C projects.

## Test plan

### Cross-platform results (`zig build test` / `zig build
-Dapp-runtime=none test` on Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** (d5aef6e84) | FAIL - 47/51 steps, 1 failed | PASS - 86/86,
2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped
|
| **AFTER** (a35f84db3) | FAIL - 48/51 steps, 1 failed | PASS - 86/86,
2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped
|

### Windows: what changed (47 -> 48 steps, translate-c fixed)

**Fixed by this PR:**
- `translate-c` - was `3 errors` (unknown type name 'ssize_t' at lines
582, 842, 847) -> `success`

**Remaining failure (pre-existing, unrelated):**
- `compile test ghostty-test` - 3 errors in libcxxabi
(`std::get_new_handler` not found, `type_info` redefinition). This is
Zig's bundled libc++ ABI conflicting with MSVC headers when compiling
the test binary. It was previously masked by the translate-c failure
blocking this step.

### Linux/macOS: no regressions
Identical pass counts and test results before and after.

## What Have I Learnt
- I tried fixing this issue the old way, googling and stuff, I
eventually figured out but it took me way more than I am prepared to
share. Yikes.
2026-03-24 10:28:58 -07:00
Mitchell Hashimoto d14eab3124
build: fix freetype compilation on Windows with MSVC (#11807)
## Summary

**Getting there!** Goal for today/tomorrow is to get it all green.

This one is easy:

- Gate `HAVE_UNISTD_H` and `HAVE_FCNTL_H` behind a non-Windows check
since these headers do not exist with MSVC
- Freetype's gzip module includes zlib headers which conditionally
include `unistd.h` based on this define

## Context
Same pattern as the zlib fix (010-* branch from my fork). Freetype
passes `-DHAVE_UNISTD_H` unconditionally, which causes zlib's `zconf.h`
to try including `unistd.h` when freetype compiles its gzip support. The
fix follows the same approach used in `pkg/zlib/build.zig` (line 36-38).

## Stack
Stacked on 013-windows/fix-helpgen-framegen.

## Test plan

### Cross-platform results (`zig build test` / `zig build
-Dapp-runtime=none test` on Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** (f9d3b1aaf) | FAIL - 44/51 steps, 2 failed | PASS - 86/86,
2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped
|
| **AFTER** (d5aef6e84) | FAIL - 47/51 steps, 1 failed | PASS - 86/86,
2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped
|

### Windows: what changed (44 to 47 steps, 2 to 1 failure)

**Fixed by this PR:**
- `compile lib freetype` - was `2 errors` (unistd.h/fcntl.h not found)
-> `success`
- 3 additional steps that depended on freetype now succeed

**Remaining failure (pre-existing, tracked separately):**
- `translate-c` - 3 errors (`ssize_t` unknown in ghostty.h on MSVC)

### Linux/macOS: no regressions
Identical pass counts and test results before and after.

## Discussion

### Other build files with the same pattern
`pkg/fontconfig/build.zig` and `pkg/harfbuzz/build.zig` also pass
`-DHAVE_UNISTD_H` and/or `-DHAVE_FCNTL_H` unconditionally. They are not
in the Windows build path today, but will need the same fix when they
are.

## What I Learnt

More of the same
2026-03-24 10:28:40 -07:00
Alessandro De Blasis 68378a0bb8 build: increase comptime branch quota for ghostty.h enum checks
The MSVC translate-c output includes Windows SDK declarations,
bringing the total to ~2173 declarations (vs ~1502 on Linux/Mac).
The nested inline for in checkGhosttyHEnum (enum fields x declarations)
exceeds the 1M comptime branch quota for larger enums like MouseShape
(34 variants). Increase to 10M to accommodate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:04:50 +01:00
Alessandro De Blasis ce99300513 build: fix freetype C enum signedness for MSVC
MSVC translates C enums as signed int, while GCC/Clang uses unsigned
int. The freetype Zig bindings hardcode c_uint for enum backing types,
causing type mismatches when compiling with MSVC target.

Fix by adding @intCast at call sites where enum values are passed to
C functions, and @bitCast for the glyph format tag extraction where
bit-shift operations require unsigned integers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:12:35 +01:00
Alessandro De Blasis deeda46186 build: skip linkLibCpp on MSVC for dcimgui, spirv-cross, harfbuzz
Zig unconditionally passes -nostdinc++ and adds its bundled
libc++/libc++abi include paths, which conflict with MSVC's own C++
runtime headers. The MSVC SDK directories (added via linkLibC)
already contain both C and C++ headers, so linkLibCpp is not needed.

This is the same fix already applied upstream to highway, simdutf,
utfcpp, glslang, SharedDeps, and GhosttyZig.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:03:33 +01:00
Alessandro De Blasis a35f84db32 build: define ssize_t for MSVC in ghostty.h
MSVC's <sys/types.h> does not define ssize_t (it is a POSIX type).
This causes the translate-c build step to fail when translating
ghostty.h on Windows. Use SSIZE_T from <BaseTsd.h> which is the
Windows SDK equivalent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:35:49 +01:00
Mitchell Hashimoto aec3a6ebf6
build: fix Windows build failures in helpgen and framegen (#11803)
> [!WARNING]
> Review/approve this AFTER #11798, #11800 and #11801 (this PR stacks on
top of rhem... ergo, it includes their commits)
> Don't cheat! Start from the oldest one! 😄 I know these are almost
one-liners but I am doing this mostly for documentation and karma
points. BTW, Github needs to level up this wankflow like a lot... IMHO

## Summary
- Use `writerStreaming()` instead of `writer()` for stdout in helpgen
and main_build_data (`ftruncate` on pipes fails on Windows with
`INVALID_PARAMETER` mapped to `FileTooBig`)
- Replace POSIX `scandir` with `opendir`/`readdir` plus `qsort` in
framegen since `scandir` is not available on Windows

## Context
This fix was previously applied upstream by Mitchell (f4998c6ab) and
reverted 15 minutes later (0fdddd5bc). The reason for the revert is not
clear. Around the same time, a CI step was added to execute cmake
examples on Windows, which was later removed (b723f2a43) with the note
"hangs, so remove it entirely". Whether the revert is related to the
hang or had a separate reason, we don't know.

What we do know:
- Both `helpgen` and `framegen` run during normal builds on Windows (via
`SharedDeps`), not just during dist packaging. Claude had told me the
opposite before but "don't trust and verify".
- Without this fix, both tools fail: helpgen with `FileTooBig`
(ftruncate on pipes), framegen with `scandir` undeclared
- The fix does not regress Linux or macOS

## Stack
Stacked on 012-windows/fix-glslang-msvc.

## Test plan

### Cross-platform results (`zig build test` / `zig build
-Dapp-runtime=none test` on Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** (74c6ffe78) | FAIL - 39/51 steps, 4 failed | PASS - 86/86,
2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped
|
| **AFTER** (f9d3b1aaf) | FAIL - 44/51 steps, 2 failed | PASS - 86/86,
2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped
|

### Windows: what changed (39 > 44 steps, 4 > 2 failures)

**Fixed by this PR:**
- `run exe helpgen` -> was `failure` (FileTooBig from ftruncate on
stdout pipe) -> `success`
- `compile exe framegen` -> was `1 errors` (scandir undeclared) ->.
`success`

**Remaining failures (pre-existing, fixed by later PRs in stack):**
- `translate-c` -> 3 errors (`ssize_t` unknown in ghostty.h on MSVC)
- `compile lib freetype` -> 2 errors (`unistd.h` not found)

### Linux/macOS: no regressions
Identical pass counts and test results before and after.

## Discussion points

### "Grep wider"  other `stdout().writer()` callsites
There are 15+ other `stdout().writer(&buf)` callsites in the codebase.
Build-time generators that capture stdout (webgen, mdgen, unicode
generators) would have the same `ftruncate` issue if they ran on
Windows. Currently they don't appear in the Windows build graph, but
worth noting for future Windows work.

### `writerStreaming()` vs `writer()`
`writer()` calls `ftruncate` on flush/end to set the file size, which
fails on pipes (stdout captured by the build system).
`writerStreaming()` skips the truncate since the output goes to a pipe,
not a seekable file. This is the correct API for this use case on all
platforms, not just Windows.

## What I Learnt
- When upstream has applied and reverted something, state what you
observe rather than speculating about their reasoning. Let the reviewer
fill in context you don't have.
- "Grep wider" (testing pattern): `stdout().writer()` appears in 17
files. Only 2 are fixed here because only 2 are in the current Windows
build path. But the pattern exists more broadly.
- I feel like I am training my replacements. I mean, I am a parent, it
rhymes.
- I feel like my replacements are training me. It rhymes as well.
2026-03-24 06:43:48 -07:00
Mitchell Hashimoto 57b929203b
build: fix glslang compilation on Windows with MSVC (#11801)
> [!WARNING]
> Review/approve this AFTER #11798 and #11800 (this PR stacks on top of
rhem... ergo, it includes their commits)
> Don't cheat! Start from the oldest one! 😄 I know these are almost
one-liners but I am doing this mostly for documentation and karma
points.

## Summary
- Conditionally skip `linkLibCpp()` on MSVC since Zig's bundled libc++
headers conflict with MSVC's own C++ runtime
- Add `-std=c++17` flag for C++17 features (std::variant,
std::filesystem, inline variables) that glslang requires

## Context
The exact same `linkLibCpp` fix was applied to `simdutf` and `highway`
in commits 3d581eb92 and b4c529a82 but glslang was missed. Without this
fix, glslang fails with 297 compilation errors on MSVC.

Thanks Claude for the forensic digging. A carpenter should always be
thankful for his tools. Even if they are borrowed, maybe even more so.

## Stack
Stacked on 011-windows/fix-oniguruma-msvc.

## Discussion points

**`-std=c++17` scope:** Currently added unconditionally for all targets.
Tested on all three platforms with no regressions, but since this is
specifically fixing a Windows/MSVC issue, it could be gated behind
`target.result.abi == .msvc`. Donno. The reason it works unconditionally
is that Zig's bundled clang already defaults to C++17 on non-MSVC
targets, so the flag is a no-op there. Open to either approach.

**Other packages with bare `linkLibCpp()`:** The same `linkLibCpp` guard
has been applied to `simdutf`, `highway`, `utfcpp`, and now `glslang`.
However, `spirv-cross`, `dcimgui`, `harfbuzz`, and `breakpad` still have
unconditional `linkLibCpp()` calls. These may need the same treatment
when they become buildable on MSVC (some are currently blocked by other
issues like freetype's `unistd.h`). Worth tracking as a follow-up?

## Test plan

### test-lib-vt

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** | 3791/3839 passed, 48 skipped | 3791/3839 passed, 48
skipped | 3807/3839 passed, 32 skipped |
| **AFTER** | 3791/3839 passed, 48 skipped | 3791/3839 passed, 48
skipped | 3807/3839 passed, 32 skipped |
| **Delta** | no change | no change | no change |

### all tests (`zig build test` / `zig build -Dapp-runtime=none test` on
Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** | FAIL — 38/51 build steps, 5 failed | 2655/2678 passed, 23
skipped (86/86 steps) | 2655/2662 passed, 7 skipped (160/160 steps) |
| **AFTER** | FAIL — 39/51 build steps, 4 failed | 2655/2678 passed, 23
skipped (86/86 steps) | 2655/2662 passed, 7 skipped (160/160 steps) |
| **Delta** | +1 build step (glslang unblocked) | no change | no change
|

- Zero regressions on any platform
- Windows improved: glslang now compiles (38 -> 39 steps, 5 -> 4
failures)
- Remaining 4 Windows failures (`helpgen`, `framegen`, `freetype`,
`translate-c`) are addressed by other PRs in the stack

## What I Learnt

- **MSVC's clang doesn't default to C++17.** Zig's bundled clang uses
C++17 by default on Linux/Mac, but when targeting MSVC, the C++ standard
needs to be specified explicitly. Without `-std=c++17`, features like
`std::variant`, `std::filesystem`, and `inline` variables are gated
behind `_HAS_CXX17` and won't compile.
- **`linkLibCpp` conflicts with MSVC headers.** Zig's `linkLibCpp`
passes `-nostdinc++` and adds its own libc++/libc++abi headers, which
collide with the C++ headers already provided by the MSVC SDK through
`linkLibC`. On MSVC, you don't need `linkLibCpp` at all since the SDK
includes both C and C++ headers. I think yesterday we dealt with
something similar. Windows is fun. 🫠 Unironically and chronically.
- **Grep wider.** The `linkLibCpp` guard was already applied to simdutf,
highway, and utfcpp but missed glslang. When a fix follows a repeated
pattern across packages, search the whole codebase before declaring it
complete.
2026-03-24 06:43:25 -07:00
Mitchell Hashimoto 5cc22c23e6
build: fix oniguruma compilation on Windows with MSVC (#11800)
> [!WARNING]
> Review/approve this AFTER #11798 (this PR stacks on top of it... ergo,
it includes its commits)

## Summary
- Conditionally disable POSIX-only header defines (`alloca.h`,
`sys/times.h`, `sys/time.h`, `unistd.h`) on Windows since they do not
exist with MSVC
- Enable `USE_CRNL_AS_LINE_TERMINATOR` on Windows for correct line
endings

## Context
Oniguruma's `config.h` template had all POSIX header availability
defines hardcoded to `true`. On MSVC, these headers don't exist, causing
24 compilation errors (all `alloca.h` file not found).

Uses a comptime `is_windows` constant to flip the config values, same
pattern as PR #11798 (zlib).

## Stack
Stacked on 010-windows/fix-zlib-msvc.

## Test plan

### test-lib-vt

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** | 3791/3839 passed, 48 skipped | 3791/3839 passed, 48
skipped | 3807/3839 passed, 32 skipped |
| **AFTER** | 3791/3839 passed, 48 skipped | 3791/3839 passed, 48
skipped | 3807/3839 passed, 32 skipped |
| **Delta** | no change | no change | no change |

### all tests (`zig build test` / `zig build -Dapp-runtime=none test` on
Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** | FAIL — 37/51 steps, 6 failed | 2655/2678 passed, 23
skipped (86/86 steps) | 2655/2662 passed, 7 skipped (160/160 steps) |
| **AFTER** | FAIL — 38/51 steps, 5 failed | 2655/2678 passed, 23
skipped (86/86 steps) | 2655/2662 passed, 7 skipped (160/160 steps) |
| **Delta** | +1 step, -1 failure (oniguruma unblocked) | no change | no
change |

- Zero regressions on any platform
- Windows improved: oniguruma now compiles (37 -> 38 steps, 6 -> 5
failures)
- Remaining 5 Windows failures (`translate-c`/ssize_t, `helpgen`,
`framegen`, `glslang`, `harfbuzz` via freetype) are addressed by other
PRs in the stack

## What I Learnt
- comptime, man. It's the small things.
2026-03-24 06:43:11 -07:00
Mitchell Hashimoto 58e330a8c0
build: fix zlib compilation on Windows with MSVC (#11798)
## Summary
- Gate `Z_HAVE_UNISTD_H` behind a non-Windows check since `unistd.h`
does not exist with MSVC
- Add `_CRT_SECURE_NO_DEPRECATE` and `_CRT_NONSTDC_NO_DEPRECATE` for
MSVC to suppress deprecation errors for standard C functions that zlib
uses

## Context
Part of the effort to get `zig build -Dapp-runtime=none test` passing on
Windows. This unblocks freetype, harfbuzz, libpng, and dcimgui which all
depend on zlib.

My research shows that we should default to msvc in ci with zig build
ran without `-Dratget`.

## Stack
This is branch 010 in the stacked branches series (soon on Netflix).
Independent fix, no dependencies on other branches.

## Test plan

### test-lib-vt

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** | 3791/3839 passed, 48 skipped | 3791/3839 passed, 48
skipped | 3807/3839 passed, 32 skipped |
| **AFTER** | 3791/3839 passed, 48 skipped | 3791/3839 passed, 48
skipped | 3807/3839 passed, 32 skipped |
| **Delta** | no change | no change | no change |

### all tests (`zig build test` / `zig build -Dapp-runtime=none test` on
Windows)

| | Windows | Linux | Mac |
|---|---|---|---|
| **BEFORE** | FAIL — 35/51 build steps, 6 failed | 2655/2678 passed, 23
skipped (86/86 steps) | 2655/2662 passed, 7 skipped (160/160 steps) |
| **AFTER** | FAIL — 37/51 build steps, 6 failed | 2655/2678 passed, 23
skipped (86/86 steps) | 2655/2662 passed, 7 skipped (160/160 steps) |
| **Delta** | +2 build steps (zlib + png unblocked) | no change | no
change |

- Zero regressions on any platform
- Windows improved: zlib and png now compile (35 -> 37 steps)
- Remaining 6 Windows build failures (`ssize_t`, `helpgen`, `framegen`,
`harfbuzz`, `dcimgui`) are addressed by other PRs in the stack

## What I Learnt
- Always run tests with `--summary all` to get actual pass/skip/fail
counts. Without it, zig just exits 0 or 1 and you have no numbers to
compare. "You get confident if you got the numbers."
- Build dependencies cascade: fixing zlib also unblocked png (which
depends on it), giving us +2 build steps from a one-file change.
2026-03-24 06:42:52 -07:00
Mitchell Hashimoto 6854ecc5a9
ci: remove continue-on-error from Windows CI jobs (#11796)
Let's see what breaks and let's fix it.
2026-03-24 06:31:58 -07:00
Alessandro De Blasis d5aef6e845 build: fix freetype compilation on Windows with MSVC
Gate HAVE_UNISTD_H and HAVE_FCNTL_H behind a non-Windows check since
these headers do not exist with MSVC. Freetype includes zlib headers
which conditionally include unistd.h based on this define.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:08:29 +01:00
Alessandro De Blasis f9d3b1aafb build: fix Windows build failures in helpgen and framegen
Use writerStreaming() instead of writer() for stdout in helpgen and
main_build_data. The positional writer calls setEndPos/ftruncate in
end(), which fails on Windows because ftruncate on pipes maps
INVALID_PARAMETER to FileTooBig.

Replace scandir with opendir/readdir plus qsort in framegen since
scandir is a POSIX extension not available on Windows.

This was previously applied and reverted upstream (f4998c6ab, 0fdddd5bc)
as collateral from an unrelated example-execution hang that has since
been resolved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:07:31 +01:00
Alessandro De Blasis 74c6ffe78e build: fix glslang compilation on Windows with MSVC
Apply the same MSVC fixes used for simdutf and highway: conditionally
skip linkLibCpp on MSVC since Zig's bundled libc++ headers conflict
with MSVC's own C++ runtime, and add -std=c++17 for C++17 features
like std::variant and inline variables that glslang requires.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:05:40 +01:00
Alessandro De Blasis 014873e539 build: fix oniguruma compilation on Windows with MSVC
Conditionally disable POSIX-only header defines (alloca.h, sys/times.h,
sys/time.h, unistd.h) on Windows since they do not exist with MSVC.
Enable USE_CRNL_AS_LINE_TERMINATOR on Windows for correct line endings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:03:53 +01:00
Alessandro De Blasis 4df71bcad7 build: fix zlib compilation on Windows with MSVC
Gate Z_HAVE_UNISTD_H behind a non-Windows check since unistd.h does
not exist on Windows. Add _CRT_SECURE_NO_DEPRECATE and
_CRT_NONSTDC_NO_DEPRECATE for MSVC to suppress deprecation errors
for standard C functions that zlib uses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:02:50 +01:00
Alessandro De Blasis c5092b09de ci: remove continue-on-error from Windows CI jobs
Windows tests and builds are now passing reliably. Remove the
continue-on-error safety net so failures are visible immediately.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 06:17:49 +01:00
Mitchell Hashimoto d4a38c8661
cmake: add import library to custom command OUTPUT (#11794)
# What 

PR #11756 added IMPORTED_IMPLIB pointing to the .lib import library, but
the
import library is not listed in the OUTPUT directive of the
`add_custom_command`
that runs zig build. The file is produced as a side-effect of the build.

This works with the Visual Studio generator (which is lenient about
undeclared outputs) but fails with Ninja:

ninja: error: 'zig-out/lib/ghostty-vt.lib', needed by 'ghostling',
missing and no known rule to make it

The fix adds "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}" to the OUTPUT
list. No
behavioral change. The file was already being built, Ninja just needs to
know
about it.

## but_why.gif

I am cleaning up https://github.com/ghostty-org/ghostling/pull/6 and I
realise that in order to get rid of the CMake workarounds we had before
#11756, this change is necessary.

# POC

I set up a branch pointing at my fork with a POC and it builds, this is
the cleaned up CMakeList
https://github.com/deblasis/winghostling/blob/test/cmake-implib-no-workaround/CMakeLists.txt
2026-03-23 21:04:48 -07:00
Alessandro De Blasis 7d31d9b57f cmake: add import library to custom command OUTPUT
Ninja requires all produced files to be listed as explicit outputs of
custom commands. The zig build produces a .lib import library alongside
the DLL, but it was not listed in the OUTPUT directive. This causes
Ninja to fail with "missing and no known rule to make it" when
IMPORTED_IMPLIB references the .lib file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 04:23:24 +01:00
Jeffrey C. Ollie c584f87b90
build(deps): bump cachix/install-nix-action from 31.10.1 to 31.10.2 (#11790)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.10.1 to 31.10.2.
<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.10.2</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.34.1 -&gt; 2.34.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/270">cachix/install-nix-action#270</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.10.2">https://github.com/cachix/install-nix-action/compare/v31...v31.10.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="51f3067b56"><code>51f3067</code></a>
Revert &quot;ci: use 25.11 for channel tests&quot;</li>
<li><a
href="15118c17f9"><code>15118c1</code></a>
ci: use 25.11 for channel tests</li>
<li><a
href="e1ac057965"><code>e1ac057</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/270">#270</a>
from cachix/create-pull-request/patch</li>
<li><a
href="d181b9642f"><code>d181b96</code></a>
nix: 2.34.1 -&gt; 2.34.2</li>
<li>See full diff in <a
href="1ca7d21a94...51f3067b56">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.10.1&new-version=31.10.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-03-23 20:44:57 -05:00
ghostty-vouch[bot] 846599b97e
Update VOUCHED list (#11791)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11460#discussioncomment-16285158)
from @00-kat.

Vouch: @viruslobster

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-24 01:20:46 +00:00
dependabot[bot] 147596d560
build(deps): bump cachix/install-nix-action from 31.10.1 to 31.10.2
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.10.1 to 31.10.2.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](1ca7d21a94...51f3067b56)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 00:12:58 +00:00
Mitchell Hashimoto 67db6b8960
libghostty: add ghostty_free for cross-runtime memory safety (#11785)
## What

On Windows, calling `free()` on memory allocated by libghostty crashes
because Zig and MSVC use separate heaps.

This adds `ghostty_free()` so consumers can free library-allocated
memory safely on all platforms.

## Why

When Zig builds a DLL on Windows with `link_libc = true`, it does not
link the Windows C runtime (`ucrtbase.dll`). Instead it uses its own
libc built on top of `KERNEL32.dll`. So `builtin.link_libc` is true and
`c_allocator` is selected, but Zig's `malloc` and MSVC's `malloc` are
different implementations with different heaps. 💥

On Linux/macOS this is not a problem because Zig links the system libc
and everyone shares the same heap. On Windows, `free(buf)` from MSVC
tries to free memory from Zig's heap and you get a debug assertion
failure or undefined behavior.

The `format_alloc` docs said "the buffer can be freed with `free()`" but
that is only true when the library and consumer share the same C
runtime, which is not the case on Windows.

## How

- Add `ghostty_free(allocator, ptr, len)` that frees through the same
allocator that did the allocation
- Update `format_alloc` docs to point to `ghostty_free()` instead of
`free()`
- Update all 3 examples to use `ghostty_free(NULL, buf, len)`

The signature takes an allocator because raw buffers (unlike objects
like terminals or formatters) do not store their allocator internally.
The caller already has all three values: the allocator they passed, the
pointer, and the length they got back.

I went back and forth on the naming. Other options I considered:
`ghostty_alloc_free(allocator, ptr, len)` or returning a `GhosttyBuffer`
wrapper with its own `_free`. Happy to change the naming if there is a
preference.

No impact on Linux/macOS. `ghostty_free()` works correctly there too, it
just happens to call the same `free()` the consumer would have called
anyway.

## Verified

- `zig build test-lib-vt` passes on Windows, macOS arm64, Linux x86_64
(exit 0)
- `zig build test` passes on Windows (2575/2619 passed, 1 pre-existing
font sprite failure) and macOS (exit 0)
- cmake shared example builds, links, and runs correctly on Windows with
`ghostty_free()` (no more heap crash)

## What I Learnt

- What I wrote in Why
- Zig allocators require the length to free (no hidden metadata headers
like C's malloc). This is a deliberate design choice for explicit
control.
- The standard pattern for C libraries on Windows is "whoever allocates,
frees" (like `curl_free()`, `SDL_free()`). This avoids cross-runtime
heap issues entirely.
2026-03-23 16:23:10 -07:00
Mitchell Hashimoto b819ce0e20
vt: add ghostty_alloc for buffer allocation
Add a ghostty_alloc function that pairs with the existing
ghostty_free, giving embedders a symmetric malloc/free-style
API for buffer allocation through the libghostty allocator
interface. Returns NULL on allocation failure.
2026-03-23 16:12:29 -07:00
Mitchell Hashimoto 7039f566bb
vt: move free_alloc to dedicated allocator.zig
Extract the inline free_alloc function from main.zig into a new
allocator.zig module in the C API layer. The function is renamed
to alloc_free in main.zig (and free in allocator.zig) for
consistency with the other C API naming conventions. Add tests
for null pointer, allocated memory, and null allocator fallback.
2026-03-23 16:08:32 -07:00
Mitchell Hashimoto 69104fb1f0
libghostty: introduce optional "effects" to handle queries and side effects for terminals (#11787)
Renames `ReadonlyStream` to `TerminalStream` and introduces an
effects-based callback system so that the stream handler can optionally
respond to queries and side effects (bell, title changes, device
attributes, device status, size reports, XTVERSION, ENQ, DECRQM, kitty
keyboard queries).

The default behavior is still read-only, callers have to opt-in to
setting callbacks to function pointers.

This doesn't handle every possible side effect yet, e.g. this doesn't
include clipboards, pwd reporting, and others. But this covers the
important ones.

This PR is Zig only, the C version of this will come later.
2026-03-23 15:30:18 -07:00
Mitchell Hashimoto 701d1d55d2
terminal: fix secondary DA test to match default firmware version
The default firmware_version for Secondary device attributes is 0,
but the test expected a value of 10. Update the test expectation to
match the actual default.
2026-03-23 15:02:13 -07:00
Mitchell Hashimoto ba3f9bb400
terminal: port device_attributes to stream_terminal Effects
Add a device_attributes effect callback to the stream_terminal
Handler. The callback returns a device_attributes.Attributes
struct which the handler encodes and writes back to the pty.

Add Attributes.encode which dispatches to the correct sub-type
encoder based on the request type (primary, secondary, tertiary).

In readonly mode the callback is null so all DA queries are
silently ignored, matching the previous behavior where
device_attributes was in the ignored actions list.

Tests cover all three DA types with default attributes, custom
attributes, and readonly mode.
2026-03-23 14:55:04 -07:00
Mitchell Hashimoto b31dcf9a4c
terminal: add device_attributes module
Introduce a dedicated device_attributes.zig module that consolidates
all device attribute types and encoding logic. This moves
DeviceAttributeReq out of ansi.zig and adds structured response
types for DA1 (primary), DA2 (secondary), and DA3 (tertiary) with
self-encoding methods.

Primary DA uses a ConformanceLevel enum covering VT100-series
per-model values and VT200+ conformance levels, plus a Feature
enum with all known xterm DA1 attribute codes (132-col, printer,
sixel, color, clipboard, etc.) as a simple slice. Secondary DA
uses a DeviceType enum matching the xterm decTerminalID values.
Tertiary DA encodes the DECRPTUI unit ID as a u32 formatted to
8 hex digits.

This is preparatory work for exposing device attributes through
the stream_terminal Effects callback system.
2026-03-23 14:50:26 -07:00
Mitchell Hashimoto 2e7aa047af
terminal: port device_status to stream_terminal Effects
Previously device_status was in the ignored "no terminal-modifying
effect" group in stream_terminal.zig. This ports it to use the
Effects pattern, handling all three DSR request types.

Operating status and cursor position are handled entirely within
stream_terminal since they only need terminal state and write_pty.
Cursor position respects origin mode and scrolling region offsets.

Color scheme adds a new color_scheme effect callback that returns
a ColorScheme enum (light/dark). The handler encodes the response
internally, keeping protocol knowledge in the terminal layer. A
new ColorScheme type is added to device_status.zig so the terminal
layer does not depend on apprt.
2026-03-23 14:31:47 -07:00
Mitchell Hashimoto 165e03669c
terminal: port enquiry to Effects
Previously the ENQ (0x05) action was ignored in stream_terminal,
listed in the no-op group alongside other unhandled queries. The
real implementation in termio/stream_handler writes a configurable
response string back to the pty.

Add an enquiry callback to Effects following the same query-style
pattern as xtversion: the callback returns the raw response bytes
and the handler owns writing them to the pty via writePty. When no
callback is set (readonly mode), ENQ is silently ignored. Empty
responses are also ignored. The response is capped at 256 bytes
using a stack buffer with sentinel conversion for writePty.
2026-03-23 14:25:25 -07:00
Mitchell Hashimoto 2fe89c340a
windows: fix XDG-related test failures on Windows (#11783)
## What

Two fixes for tests that fail on Windows due to Unix-specific
assumptions.

1. The "cache directory paths" test in xdg.zig hardcodes Unix paths like
`/Users/test/.cache` in expected values. The function under test uses
`std.fs.path.join` which produces native separators, so the expectations
need to match. Fixed by using `std.fs.path.join` for expected values
too, with a platform-appropriate mock home path.

2. Two shell integration tests for `setupXdgDataDirs` hardcode Unix path
separators (`:`) and Unix default paths (`/usr/local/share:/usr/share`).
These are not applicable on Windows where the delimiter is `;` and
`XDG_DATA_DIRS` is not a standard concept. Skipped on Windows with
`SkipZigTest`.


## Why skip instead of fix for the shell integration tests?

`setupXdgDataDirs` is used by fish, elvish, and nushell. On Windows,
`XDG_DATA_DIRS` is not standard. The equivalent would be `%ProgramData%`
(what Go's `adrg/xdg`, Python's `platformdirs`, and others map to).
Fixing this properly means adding a Windows-appropriate default, which
is a separate change. (How do you guys deal with these situations? Do
you create issues on the spot as reminders or do you wait for the
requirement to emerge by itself when the time comes?

Worth noting: the production code on line 664 of `shell_integration.zig`
hardcodes the fallback to `"/usr/local/share:/usr/share"` with `:`
separators, while `prependEnv` correctly uses `std.fs.path.delimiter`
(`;` on Windows). If a shell that uses this runs on Windows, you would
get mixed separators. Tracked separately.

## Verified

- `zig build test-lib-vt` passes on Windows (exit 0)
- No behavior change on Linux/macOS (xdg.zig fix produces same paths,
shell_integration skip only triggers on Windows)

## What I Learnt

- `std.fs.path.join` uses the native path separator, so tests that
hardcode `/` in expected paths will fail on Windows even if the
production code is correct. Better to use `path.join` in test
expectations too.
- The XDG Base Directory spec is Unix-only but cross-platform libraries
have converged on mappings. Ghostty maps to `%LOCALAPPDATA%` which
matches common conventions. The missing piece is `XDG_DATA_DIRS` which
has no Windows default and falls through to Unix paths.
2026-03-23 14:20:02 -07:00
Mitchell Hashimoto b9669e10c4
fuzz: update stream fuzzer to use TerminalStream
ReadonlyStream was removed from the public API. Update the stream
fuzzer to use TerminalStream, which is the type now returned by
Terminal.vtStream().
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 6083e9f80b
terminal: expose size_report via stream_terminal effects
Add a `size` callback to the stream_terminal Effects struct that
returns a size_report.Size geometry snapshot for XTWINOPS size
queries (CSI 14/16/18 t). The handler owns all protocol encoding
using the existing size_report.encode, keeping VT knowledge out
of effect consumers. This follows the same pattern as the xtversion
effect: the callback supplies data, the handler formats the reply
and calls write_pty.

CSI 21 t (title report) is handled internally from terminal state
since the title is already available via terminal.getTitle() and
does not require an external callback.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 26c81b4b0e
terminal: add xtversion effect to stream_terminal
Add an xtversion callback to the Effects struct so that
stream_terminal can respond to XTVERSION queries. The callback
returns the version string to embed in the DCS response. If the
callback is unset or returns an empty string, the response defaults
to "libghostty". The response is formatted and written back via the
existing write_pty effect.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 134516310d
terminal: implement kitty_keyboard_query in stream_terminal
Previously kitty_keyboard_query was listed as a no-op in the
readonly stream handler. This implements it using the write_pty
effect callback so that the current kitty keyboard flags are
reported back via the pty, matching the behavior in the full
stream handler.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 22c7edf3f8
terminal: rename set_window_title effect to title_changed
The effect callback no longer receives the title string directly.
Instead, the handler stores the title in terminal state via setTitle
before invoking the callback, so consumers query it through
handler.terminal.getTitle(). This removes the redundant parameter
and keeps the effect signature consistent with the new terminal
title field. Tests now verify terminal state directly rather than
tracking the title through the callback.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 08a44d7e69
terminal: store title set by escape sequences
Add a title field to Terminal, mirroring the existing pwd field.
The title is set via setTitle/getTitle and tracks the most recent
value written by OSC 0/2 sequences. The stream handler now persists
the title in terminal state in addition to forwarding it to the
surface. The field is cleared on full reset.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 6366ce9a22
terminal: add set_window_title effect to stream handler
Previously the window_title action was silently ignored in the
readonly stream handler. Add a set_window_title callback to the
Effects struct so callers can be notified when a window title is
set via OSC 2. Follows the same pattern as bell and write_pty
where the callback is optional and defaults to null in readonly
mode.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto e24cc1b53b
terminal: add write_pty effect and implement DECRQM
Add a generic write_pty effect callback to the stream terminal
handler, allowing callers to receive pty response data. Use it to
implement request_mode and request_mode_unknown (DECRQM), which
encode the mode state as a DECRPM response and write it back
through the callback. Previously these were silently ignored.

The write_pty data is stack-allocated and only valid for the
duration of the call.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 67d8d86efd
terminal: rename ReadonlyStream to TerminalStream
Rename stream_readonly.zig to stream_terminal.zig and its exported
types from ReadonlyStream/ReadonlyHandler to TerminalStream. The
"readonly" name is now wrong since the handler now supports
settable effects callbacks. The new name better reflects that this
is a stream handler for updating terminal state.
2026-03-23 14:17:10 -07:00
Mitchell Hashimoto 07272ae88f
stream: add bell effect callback support
Add an Effects struct to the readonly stream Handler that allows
callers to provide optional callbacks for side effects like bell.
Previously, the bell action was silently ignored along with other
query/response actions. Now it is handled separately and dispatched
through the effects callback if one is provided.

Add a test that verifies bell with a null callback (default readonly
behavior) does not crash, and that a provided callback is invoked
the correct number of times.
2026-03-23 14:17:09 -07:00
Jeffrey C. Ollie fd49716ea2
windows: skip expandHomeUnix test on Windows (#11784)
## What

Skip the `expandHomeUnix` test on Windows with `SkipZigTest`.

`expandHomeUnix` is a Unix-internal function that is never called on
Windows. The public `expandHome` already returns the path unchanged on
Windows (added upstream in cccdb0d2a). But the unit test calls
`expandHomeUnix` directly, which invokes `home()` and expects Unix-style
forward-slash separators, so it fails on Windows.

## How

Two lines:

```zig
if (builtin.os.tag == .windows) return error.SkipZigTest;

```

## Verified

- `zig build test-lib-vt` passes on Windows (exit 0)
- No behavior change on Linux/macOS

## What I Learnt

- When upstream adds a platform dispatch for production code (like
`expandHome` returning unchanged on Windows), the unit tests for
internal platform-specific functions (like `expandHomeUnix`) may still
need a skip guard.
- Zig doesn't have something like Go's `//go:build` but damn... comptime
is insane, like supercharged C# `#if`
2026-03-23 15:20:02 -05:00
Alessandro De Blasis c1e616c6cd libghostty: add ghostty_free for cross-runtime memory safety
On Windows, Zig's built-in libc and MSVC's CRT maintain separate
heaps, so calling free() on memory allocated by the library causes
undefined behavior. Add ghostty_free() that frees through the same
allocator that performed the allocation, making it safe on all
platforms.

Update format_alloc docs and all examples to use ghostty_free()
instead of free().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:52:02 +01:00
Mitchell Hashimoto 1213dacd5b
cmake: fix Windows libghostty build support (#11756)
On Windows, shared libraries (DLLs) require an import library (.lib) for
linking, and the DLL itself is placed in bin/ rather than lib/ by the
Zig build. The CMake wrapper was missing IMPORTED_IMPLIB on the shared
imported target, causing link failures, and assumed the shared library
was always in lib/.

Add GHOSTTY_VT_IMPLIB for the import library name, set IMPORTED_IMPLIB
on the ghostty-vt target, and fix the shared library path to use bin/ on
Windows. Install the DLL and PDB to bin/ and the import library to lib/
following standard Windows conventions. Apply the same fixes to
ghostty-vt-config.cmake.in for the find_package path.
2026-03-23 12:50:42 -07:00
Mitchell Hashimoto b723f2a437
ci: remove run step from Windows cmake examples
The "Run Example" step in the build-examples-cmake-windows job
hangs, so remove it entirely. The build step is still run so
compilation is verified, but the examples are no longer executed
on Windows.
2026-03-23 12:34:22 -07:00
Mitchell Hashimoto 63260ec722
build: disable ubsan for SIMD C++ files on MSVC
The SIMD C++ files reference __ubsan_handle_* symbols when compiled
in debug mode, but we do not link or bundle the ubsan runtime on
MSVC. This matches what the highway and simdutf packages already do
in their own build files.
2026-03-23 12:32:06 -07:00
Alessandro De Blasis f2773d42c1 windows: skip expandHomeUnix test on Windows
expandHomeUnix is a Unix-internal function that is never called on
Windows. The public expandHome function returns the path unchanged
on Windows since ~/ is not a standard Windows idiom. The test calls
expandHomeUnix directly, which invokes home() and expects Unix-style
forward-slash separators.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:29:59 +01:00
Mitchell Hashimoto b4c529a827
build: add -std=c++17 for SIMD C++ files on MSVC
The SIMD C++ files use C++17 features (std::optional, std::size).
With Zig's bundled libc++ these are available implicitly, but MSVC
headers guard C++17 features behind the standard version
(_HAS_CXX17). Without an explicit -std=c++17 flag, clang defaults
to a lower standard and the MSVC <optional> header does not define
std::optional.
2026-03-23 12:23:33 -07:00
Mitchell Hashimoto 3d581eb92e
build: use linkLibC instead of linkLibCpp on MSVC targets
When compiling C++ files, Zig unconditionally passes -nostdinc++ and,
if link_libcpp is set, adds its bundled libc++/libc++abi include paths
as replacements (see Compilation.zig). On MSVC targets this conflicts
with the MSVC C++ runtime headers (vcruntime_typeinfo.h,
vcruntime_exception.h, etc.), causing compilation failures in SIMD
C++ code.

The fix is to use linkLibC instead of linkLibCpp on MSVC. Zig always
passes -nostdinc to strip default search paths, but LibCDirs.detect
re-adds the MSVC SDK include directories, which contain both C and
C++ standard library headers. This gives us proper access to MSVC's
own <optional>, <iterator>, <cstddef>, etc. without the libc++
conflicts.

For the package builds (highway, simdutf, utfcpp) this means
switching from linkLibCpp to linkLibC on MSVC. For SharedDeps and
GhosttyZig, linkLibC is already called separately, so we just skip
linkLibCpp.
2026-03-23 12:11:03 -07:00
Alessandro De Blasis 5ef2da8127 windows: fix XDG-related test failures on Windows
Make the "cache directory paths" test cross-platform by using
std.fs.path.join for expected values and a platform-appropriate
mock home path, since the function under test uses native path
separators.

Skip the two shell integration XDG_DATA_DIRS tests on Windows.
These tests use hardcoded Unix path separators (:) and Unix default
paths (/usr/local/share:/usr/share) which are not applicable on
Windows where the path delimiter is ; and XDG_DATA_DIRS is not a
standard concept.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:09:32 +01:00
Mitchell Hashimoto afa8f059e5
build: skip linkLibCpp on MSVC targets
Zig's bundled libc++/libc++abi conflicts with the MSVC C++ runtime
headers (vcruntime_typeinfo.h, vcruntime_exception.h, etc.) when
targeting native-native-msvc. This caused compilation failures in
the SIMD C++ code due to -nostdinc++ suppressing MSVC headers and
libc++ types clashing with MSVC runtime types.

Skip linkLibCpp() for MSVC targets across all packages (highway,
simdutf, utfcpp) and the main build (SharedDeps, GhosttyZig) since
MSVC provides its own C++ standard library natively. Also add
missing <iterator> and <cstddef> includes that were previously
pulled in transitively through libc++ headers but are not
guaranteed by MSVC's headers.
2026-03-23 11:57:14 -07:00
Mitchell Hashimoto 1eed35dddc
build: default to MSVC ABI on Windows
Zig defaults to the GNU ABI on Windows, which produces COFF objects
with invalid COMDAT sections in compiler_rt that the MSVC linker
rejects (LNK1143), and uses GNU conventions like ___chkstk_ms that
are unavailable in the MSVC CRT.

Default to the MSVC ABI when no explicit ABI is requested, following
the same pattern as the existing macOS target override. This ensures
compiler_rt produces valid COFF and the generated code uses
MSVC-compatible symbols. Users can still explicitly request the GNU
ABI via -Dtarget.

Also disable bundling ubsan_rt on Windows (its /exclude-symbols
directives are MSVC-incompatible) and add ntdll and kernel32 as
transitive link dependencies for the static library.
2026-03-23 11:45:43 -07:00
Mitchell Hashimoto 01401ef675
build: fix Windows static lib linking with MSVC
Three issues when linking the static library with the MSVC linker:

Use the LLVM backend on Windows to produce valid COFF objects.
The self-hosted backend generates compiler_rt objects with invalid
COMDAT sections that the MSVC linker rejects (LNK1143).

Disable bundling ubsan_rt on Windows. Zig's ubsan runtime emits
/exclude-symbols linker directives that MSVC does not understand
(LNK4229).

Add ntdll and kernel32 as transitive link dependencies for the
static library on Windows. The Zig standard library uses NT API
functions (NtClose, NtCreateSection, etc.) that consumers must
link.
2026-03-23 11:31:41 -07:00
Alessandro De Blasis 909e733120 windows: handle backslash paths in config value parsing
CommaSplitter treats backslash as an escape character, which breaks
Windows paths like C:\Users\foo since \U is not a valid escape. On
Windows, treat backslash as a literal character outside of quoted
strings. Inside quotes, escape sequences still work as before.

The platform behavior is controlled by a single comptime constant
(escape_outside_quotes) so the logic lives in one place. Escape-specific
tests are skipped on Windows with SkipZigTest, and Windows-specific
tests are added separately.

Also fix Theme.parseCLI to not mistake the colon in a Windows drive
letter (C:\...) for a light/dark theme pair separator.

Note: other places in the config parsing also use colon as a delimiter
without accounting for Windows drive letters (command.zig prefix
parsing, keybind parsing). Those are tracked separately.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:30:14 +01:00
Mitchell Hashimoto 2c89bef860
build: skip bundled compiler_rt and ubsan_rt in Windows static lib
Zig's compiler_rt produces COFF objects with invalid COMDAT
sections that the MSVC linker rejects (LNK1143), and its ubsan_rt
emits /exclude-symbols directives that MSVC does not understand
(LNK4229). Skip bundling both in the static library on Windows
since the MSVC CRT provides the needed builtins (memcpy, memset,
etc.). The shared library continues to bundle compiler_rt as it
needs to be self-contained.
2026-03-23 11:20:20 -07:00
Mitchell Hashimoto 69f82ec751
build: disable bundled ubsan runtime on Windows
Zig's ubsan runtime emits /exclude-symbols linker directives that
are incompatible with the MSVC linker, causing LNK4229 warnings and
LNK1143 errors. Disable bundling ubsan_rt on Windows while keeping
compiler_rt which provides essential symbols like memcpy, memset,
memmove, and ___chkstk_ms.

The previous check used target.result.abi == .msvc which never
matched because Zig defaults to the gnu ABI on Windows.
2026-03-23 11:12:19 -07:00
Mitchell Hashimoto 1ce057f053
build: disable ubsan and bundled runtimes for MSVC targets
Zig's ubsan instrumentation emits ELF-style /exclude-symbols linker
directives into the compiled object files, causing LNK4229 warnings
with the MSVC linker. The bundled compiler_rt also produces COMDAT
sections that are incompatible with MSVC, causing fatal LNK1143.

Disable sanitize_c entirely on the root module for MSVC targets and
skip bundling both compiler_rt and ubsan_rt since MSVC provides its
own runtime.
2026-03-23 11:04:28 -07:00
Mitchell Hashimoto 31285e1ac3
build: disable bundled compiler_rt and ubsan_rt for MSVC targets
Zig's bundled compiler_rt and ubsan_rt produce object files with
ELF-style linker directives (/exclude-symbols) and COMDAT sections
that are incompatible with the MSVC linker, causing LNK1143 and
LNK4229 errors when linking the static library.

MSVC provides its own compiler runtime so bundling Zig's versions
is unnecessary. Skip bundling both runtimes when the target ABI is
MSVC.
2026-03-23 10:42:10 -07:00
Mitchell Hashimoto 2afadfc104
build: fix Windows cmake example failures
The cmake examples were failing at runtime on Windows CI for two
reasons.

The static library was installed as "libghostty-vt.a" on all
platforms, but on Windows the DLL import library is also placed in
zig-out/lib/ as "ghostty-vt.lib". The CMakeLists.txt expected the
platform-native name "ghostty-vt.lib" for the static lib, so it
picked up the tiny DLL import lib instead, silently producing a
dynamically-linked executable. That executable then failed at
runtime because the DLL was not on PATH.

Fix this by installing the static library as "ghostty-vt-static.lib"
on Windows to avoid the name collision, and updating CMakeLists.txt
to match. For the shared (DLL) example, add zig-out/bin to PATH in
the CI run step so the DLL can be found at runtime.
2026-03-23 10:32:22 -07:00
Mitchell Hashimoto 6ccc01a852
revert the build-windows 2026-03-23 10:31:31 -07:00
Mitchell Hashimoto 0fdddd5bc2
Revert "build: fix Windows build failures in helpgen and framegen"
This reverts commit 704511465b8b04d6839fbaaf3323d9349693f04a.
2026-03-23 10:31:11 -07:00
Mitchell Hashimoto 48cf3f36cd
ci: run Windows CMake examples after building
Add a "Run Example" step to the build-examples-cmake-windows job
so that each CMake example is executed after it is built, verifying
the resulting binaries actually work. The executable name is derived
from the matrix directory name by replacing hyphens with underscores,
matching the project convention.
2026-03-23 10:31:11 -07:00
Mitchell Hashimoto f4998c6abb
build: fix Windows build failures in helpgen and framegen
Use writerStreaming() instead of writer() for stdout in helpgen and
main_build_data. The positional writer calls setEndPos/ftruncate in
end(), which fails on Windows when stdout is redirected via
captureStdOut() because ftruncate maps INVALID_PARAMETER to
FileTooBig. Streaming mode skips truncation entirely since stdout
is inherently a sequential stream.

Replace scandir with opendir/readdir plus qsort in framegen since
scandir is a POSIX extension not available on Windows.
2026-03-23 10:31:11 -07:00
Mitchell Hashimoto 5a46e61bee
cmake: fix Windows build support
On Windows, shared libraries (DLLs) require an import library (.lib)
for linking, and the DLL itself is placed in bin/ rather than lib/ by
the Zig build. The CMake wrapper was missing IMPORTED_IMPLIB on the
shared imported target, causing link failures, and assumed the shared
library was always in lib/.

Add GHOSTTY_VT_IMPLIB for the import library name, set IMPORTED_IMPLIB
on the ghostty-vt target, and fix the shared library path to use bin/
on Windows. Install the DLL and PDB to bin/ and the import library to
lib/ following standard Windows conventions. Apply the same fixes to
ghostty-vt-config.cmake.in for the find_package path.
2026-03-23 10:31:11 -07:00
Mitchell Hashimoto fa10237fb0
build: fix windows build to properly run tests and build of libghostty-vt (#11781)
Our Windows build has been broken for a _long_ time. It hasn't actually
worked and our CI was falsely passing when it was actually failing to
build/test. This PR fixes that and fixes the issues it found so
`libghostty-vt` can build and pass tests.

**This is only for libghostty!** I'd still like to expand our _test_
coverage to all of Ghostty for Windows but libghostty is more important
for that platform in the short term and it's an incremental piece of
work.

A couple windows compatibility issues fixed:

- `terminal.Page` uses `VirtualAlloc` on Windows (thanks @deblasis)
- Our rgb.txt loading was not resilient to CRLF endings
2026-03-23 10:29:45 -07:00
Mitchell Hashimoto e95fdd2f21
terminal: handle CRLF line endings in rgb.txt parsing
The X11 color map parser in x11_color.zig uses @embedFile to load
rgb.txt at comptime, then splits on \n. On Windows, git may check
out rgb.txt with CRLF line endings, leaving a trailing \r on each
line. This caused color names to be stored as e.g. "white\r" instead
of "white", so all X11 color lookups failed at runtime.

Strip trailing \r from each line before parsing. Also mark rgb.txt
as -text in .gitattributes to prevent line ending conversion in
future checkouts.
2026-03-23 10:15:16 -07:00
Mitchell Hashimoto d568ce9cc8
terminal: support VirtualAlloc for page allocation on windows
Extract the platform-specific page backing memory allocation into
AllocPosix and AllocWindows structs behind a PageAlloc comptime
switch. Previously, POSIX mmap calls were inlined at each call
site. This adds a Windows VirtualAlloc implementation and routes
all allocation through PageAlloc.alloc/free, making the backing
memory strategy consistent and easier to extend.
2026-03-23 10:04:43 -07:00
Mitchell Hashimoto aa969df679
ci: clean up Windows build job
Rename build-windows to build-libghostty-vt-windows to reflect that
it only builds and tests libghostty-vt for now, and move it next to
the other build-libghostty-vt jobs.

Replace the manual PowerShell zig download/install with mlugg/setup-zig,
which auto-detects the version from build.zig.zon and handles caching.
Upgrade the runner from windows-2022 to windows-2025. Remove the
generated-script-to-swallow-errors pattern in favor of direct zig
build commands.
2026-03-23 09:39:00 -07:00
Mitchell Hashimoto 206f9894f7
Fix `zig build test-lib-vt` (#11778)
- Our `checkGhosttyH` calls need to be guarded on building Ghostty app
which has it
- Move FileFormatter to its own file to avoid poisoning test refs with
Config.zig which pulls in the world
- Move WindowPaddingBalance to renderer to avoid pulling in Config.zig
- Add a `zig build test-lib-vt` CI job
2026-03-23 09:38:40 -07:00
Mitchell Hashimoto 3c8d0a9c25
vt: fix test failures in render and key_encode
The colors_get function used structSizedFieldFits to guard the
palette copy, which required the entire palette array to fit in the
provided size. This prevented partial palette writes when the caller
passed a truncated sized struct, since the guard failed even though
the inner code already handled partial copies correctly. Remove the
outer guard so the existing partial-copy logic applies.

The setopt_from_terminal test expected alt_esc_prefix to be false on
a fresh terminal, but the mode definition in modes.zig sets its
default to true. Update the test expectation to match.
2026-03-23 09:23:32 -07:00
Mitchell Hashimoto f92bb74196
ci: add test-lib-vt job
Add a new CI job that runs `zig build test-lib-vt` to test the
lib-vt build step. The job mirrors the existing test job structure
with the same nix/cachix setup and skip conditions. It is also
added to the required checks list.
2026-03-23 09:21:37 -07:00
Mitchell Hashimoto 58283528c7
vt: handle invalid enum before pointer cast in getters
The inline else switch in each C API getter expands the .invalid
case, which has OutType void. When called with .invalid and a null
out pointer, the @ptrCast(@alignCast(out)) panics before getTyped
can return early.

Handle .invalid explicitly in the outer switch of every getter to
short-circuit before the pointer cast. This affects build_info,
cell, row, terminal, osc, and render (three getters).
2026-03-23 09:19:52 -07:00
Mitchell Hashimoto 409f05c927
typos 2026-03-23 09:17:34 -07:00
Mitchell Hashimoto 51f878417f
reenable tests 2026-03-23 09:15:33 -07:00
Mitchell Hashimoto f60587ffcc
renderer/size: move PaddingBalance enum out of Config
Previously WindowPaddingBalance was defined inside Config.zig, which
meant tests for renderer sizing had to pull in the full config
dependency. Move the enum into renderer/size.zig as PaddingBalance
and re-export it from Config so the public API is unchanged. This
lets size.zig tests run without depending on Config.
2026-03-23 09:14:46 -07:00
Mitchell Hashimoto 7253668ec2
config: move file formatter to dedicated file to prevent import bloat 2026-03-23 09:11:23 -07:00
Mitchell Hashimoto 04b5dc7332
terminal: guard ghostty.h checks on building the app 2026-03-23 09:03:21 -07:00
Mitchell Hashimoto 9b3f7a9287
vt: also build static libghostty-vt for wasm (#11757)
A static libghostty-vt is also useful for wasm targets, as that allows
linking with an application into a larger wasm module.

See
https://github.com/ghostty-org/ghostty/pull/11729#issuecomment-4106589379
2026-03-23 08:52:56 -07:00
Bastian Müller d67f65e38c also build static libghostty-vt for wasm 2026-03-23 08:36:04 -07:00
Jeffrey C. Ollie 374ed27214
gtk: Open URIs with portals (#11754)
This is a continuation of the solid work done by @jcollie in PR #7864. I
checked with him if I could take over to continue the implementation.

His changes of last year have been adapted to be compatible with the
current GTK implementation. Aside from just "making it work", I also
dived into the portals and OpenURI implementation and made some
improvements there.

Notable improvements were:
- Improved lifecycle management of glib resources in the OpenURI
implementation
- More forgiving error handling in OpenURI implementation by adding more
fallbacks
- Fixed some memory leaks
- Less memory allocations in Portals implementation
- Added tests for building the Portals request path

Fixes #5991
2026-03-23 09:44:49 -05:00
ghostty-vouch[bot] f0d59c22b2
Update VOUCHED list (#11775)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11768#issuecomment-4111147332)
from @jcollie.

Vouch: @lynicis

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-23 14:41:18 +00:00
ghostty-vouch[bot] f6cf978b32
Update VOUCHED list (#11773)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11771#issuecomment-4111016256)
from @jcollie.

Vouch: @deblasis

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-23 14:24:45 +00:00
Timon de Groot 8bc75907b5 gtk: Fix casing for openUri 2026-03-23 07:29:36 +01:00
ghostty-vouch[bot] 1d54a94ced
Update VOUCHED list (#11755)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11754#issuecomment-4106929553)
from @mitchellh.

Vouch: @tdgroot

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-22 20:28:50 +00:00
Timon de Groot 919e586c51 gtk/portal: Improve OpenURI lifecycle 2026-03-22 21:10:46 +01:00
Timon de Groot 37d297c03c gtk/portal: General improvements
- Token is formatted without allocation
- Reusable function for formatToken
- Tests in portal.zig are actuall included now
2026-03-22 21:09:38 +01:00
Timon de Groot 855a6b01fc gtk: Open urls with openuri portal 2026-03-22 18:17:09 +01:00
Mitchell Hashimoto 7d816f8e81
Update README (#11748)
The README hasn't been updated in years basically! 

This updates the README to make libghostty a first class citizen of the
project and to update our roadmap and goals for the project to more
accurately reflect our current state and future plans.

I notably updated our roadmap to be more accurate to our state, e.g.
we're stable now. I removed Windows because it's not a short term focus
and I think libghostty is more important and enables that ecosystem a
lot more (libghostty itself being already compatible with Windows). I
also expanded on "fancy features" and clarified its to make
Ghostty-specific sequences.
2026-03-22 07:59:36 -07:00
Mitchell Hashimoto 1f2a3b8a83
update README
The README hasn't been updated in years basically! 

This updates the README to make libghostty a first class citizen of the
project and to update our roadmap and goals for the project to more
accurately reflect our current state and future plans.
2026-03-22 07:58:53 -07:00
Mitchell Hashimoto ecc55b94c8
libghostty: add resolved bg_color and fg_color to cells API (#11735)
Fixes #11705

Add bg_color and fg_color options to GhosttyRenderStateRowCellsData that
resolve the final RGB color for a cell, flattening the multiple possible
sources. For background, this handles content-tag bg_color_rgb,
content-tag bg_color_palette (looked up in the palette), and the style
bg_color. For foreground, this resolves palette indices through the
palette; bold color handling is not applied and is left to the caller.

Both return GHOSTTY_INVALID_VALUE when no explicit color is set, in
which case the caller should fall back to whatever default color it
wants (e.g. the terminal background/foreground).
2026-03-22 06:44:35 -07:00
ghostty-vouch[bot] 8a788a350e
Update VOUCHED list (#11741)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11737#discussioncomment-16252675)
from @pluiedev.

Denounce: @kody-w

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-22 08:20:46 +00:00
Mitchell Hashimoto ad5e9679c8
terminal: default render state foreground to white (#11736)
Fixes #11704

The RenderState empty initializer set both background and foreground to
the default RGB value of black (0, 0, 0), making text unreadable when a
caller has not explicitly configured terminal colors via DynamicRGB.
This is the common case for libghostty consumers.

Default the foreground to white so that the initial render state
provides readable white-on-black text out of the box.

Long term we also need to expose setting the default colors for a
Terminal instance but this is a workable fix in the mean time.
2026-03-21 20:30:32 -07:00
Mitchell Hashimoto 8bd3a493be
libghostty: add resolved bg_color and fg_color to cells API
Fixes #11705

Add bg_color and fg_color options to GhosttyRenderStateRowCellsData
that resolve the final RGB color for a cell, flattening the multiple
possible sources. For background, this handles content-tag bg_color_rgb,
content-tag bg_color_palette (looked up in the palette), and the
style bg_color. For foreground, this resolves palette indices through
the palette; bold color handling is not applied and is left to the
caller.

Both return GHOSTTY_INVALID_VALUE when no explicit color is set, in
which case the caller should fall back to whatever default color it
wants (e.g. the terminal background/foreground).
2026-03-21 20:30:01 -07:00
Mitchell Hashimoto 32c97a019f
terminal: default render state foreground to white
Fixes #11704

The RenderState empty initializer set both background and foreground
to the default RGB value of black (0, 0, 0), making text unreadable
when a caller has not explicitly configured terminal colors via
DynamicRGB. This is the common case for libghostty consumers.

Default the foreground to white so that the initial render state
provides readable white-on-black text out of the box.

Long term we also need to expose setting the default colors for a
Terminal instance but this is a workable fix in the mean time.
2026-03-21 20:24:02 -07:00
Mitchell Hashimoto 0c2bafcc2a
libghostty: expose mouse_tracking terminal data option (#11734)
Fixes #11706

Add a new GHOSTTY_TERMINAL_DATA_MOUSE_TRACKING option to the
ghostty_terminal_get API. This returns true if any mouse tracking mode
is active (X10, normal, button, or any-event), replacing the need for
consumers to loop over four separate mode queries.
2026-03-21 20:19:22 -07:00
Mitchell Hashimoto 47bfde3286
libghostty: expose mouse_tracking terminal data option
#11706

Add a new GHOSTTY_TERMINAL_DATA_MOUSE_TRACKING option to the
ghostty_terminal_get API. This returns true if any mouse tracking
mode is active (X10, normal, button, or any-event), replacing the
need for consumers to loop over four separate mode queries.
2026-03-21 20:09:39 -07:00
Mitchell Hashimoto 1775c312ae
libghostty: add static library support (#11732)
Multiple changes:

* `zig build -Demit-lib-vt` now produces both shared and static
libraries by default
* Ghosty as a zig build dependency exports the static lib as
`dep.artifact("ghostty-vt-static")`
* CMake exports the static lib as `ghostty-vt-static`

Note that the static library is _not fat_. **If you enable SIMD you have
dependencies** and you need to manually link those: libc++, simdutf, and
highway. The `c-cmake-static` example disables SIMD.
2026-03-21 15:23:00 -07:00
Mitchell Hashimoto 5fd36ea69e
build: enable PIC for static libghostty-vt
The static library was built without position-independent code,
which caused linker errors when consumers tried to link it into
PIE executables (the default on most Linux distributions). The
linker would fail with "relocation R_X86_64_32 against symbol
cannot be used when making a PIE object."

Enable PIC on the static library root module so it can be linked
into both PIE and non-PIE executables.
2026-03-21 15:15:17 -07:00
Mitchell Hashimoto 555bf7e922
build: add cmake static library support
Expose both shared and static libraries as separate CMake imported
targets (ghostty-vt and ghostty-vt-static) rather than toggling
between them with BUILD_SHARED_LIBS. The zig build already produces
both in a single invocation, so both are always available.

The find_package config template is updated to export both targets
as ghostty-vt::ghostty-vt and ghostty-vt::ghostty-vt-static.

Add a c-vt-cmake-static example that demonstrates linking the static
library via FetchContent with -Dsimd=false to avoid C++ runtime
dependencies.
2026-03-21 15:08:24 -07:00
Mitchell Hashimoto 8d6be5a3dd
build: add static library target for libghostty-vt
Refactor GhosttyLibVt to support both shared and static library
builds via a shared initLib helper that accepts a LinkMode. The
shared and static entry points (initShared, initStatic) delegate
to this common path.

For static builds, compiler_rt and ubsan_rt are bundled to avoid
undefined symbol errors. Debug symbols (dsymutil) are skipped for
static libs since they are not linked. The install artifact uses
a "-static" suffix internally but installs as "libghostty-vt.a"
via a new installLib method. Wasm is excluded from static builds
since it has no meaningful static vs shared distinction.
2026-03-21 15:01:53 -07:00
ghostty-vouch[bot] 1438a2fe4b
Update VOUCHED list (#11731)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11729#issuecomment-4104386360)
from @mitchellh.

Vouch: @turbolent

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-21 20:57:07 +00:00
Mitchell Hashimoto ed1397826b
vt: persist VT stream state across vt_write calls (#11728)
Previously, every call to vt_write created a fresh ReadonlyStream with
new Parser and UTF8Decoder state. This meant escape sequences split
across write boundaries (e.g. ESC in one write, [27m in the next) would
lose parser state, causing the second write to start in ground state and
print the CSI parameters as literal text.

The C API now stores a persistent ReadonlyStream in the TerminalWrapper
struct, which is created when the Terminal is initialized. The vt_write
function feeds bytes through this stored stream, allowing it to maintain
parser state across calls. This change ensures that escape sequences
split across write boundaries are correctly parsed and rendered.
2026-03-21 11:24:15 -07:00
Mitchell Hashimoto 918840cf1d
vt: persist VT stream state across vt_write calls
Previously, every call to vt_write created a fresh ReadonlyStream with
new Parser and UTF8Decoder state. This meant escape sequences split
across write boundaries (e.g. ESC in one write, [27m in the next)
would lose parser state, causing the second write to start in ground
state and print the CSI parameters as literal text.

The C API now stores a persistent ReadonlyStream in the TerminalWrapper
struct, which is created when the Terminal is initialized. The vt_write
function feeds bytes through this stored stream, allowing it to maintain
parser state across calls. This change ensures that escape sequences
split across write boundaries are correctly parsed and rendered.
2026-03-21 11:18:02 -07:00
Mitchell Hashimoto 3da7fb9fde
macOS: fix mouse not working correctly in CommandPaletteView (#11658) (#11665)
Also added a test case for
https://github.com/ghostty-org/ghostty/pull/11276, which will fail right
before that commit.

## AI Disclosure

Claude helped me to write some dummy texts for testing
2026-03-21 10:36:03 -07:00
Mitchell Hashimoto 155bd3a58e
vt: expose optimize mode in build info API
Add GHOSTTY_BUILD_INFO_OPTIMIZE to query the Zig optimization mode
(debug, release safe/small/fast) the library was compiled with. This
reads directly from builtin.mode at comptime so it requires no build
system plumbing.
2026-03-21 07:31:55 -07:00
Mitchell Hashimoto abefe5b40c
vt: add ghostty_build_info API for querying build configuration (#11725)
Add a new C API function ghostty_build_info() that exposes compile-time
build options to library consumers. This allows callers to query whether
SIMD, Kitty graphics protocol, and tmux control mode support were
enabled at build time.
2026-03-21 07:27:32 -07:00
Mitchell Hashimoto c3b7fd8477
vt: add ghostty_build_info API for querying build configuration
Add a new C API function ghostty_build_info() that exposes compile-time
build options to library consumers. This allows callers to query whether
SIMD, Kitty graphics protocol, and tmux control mode support were
enabled at build time.
2026-03-21 07:22:18 -07:00
Mitchell Hashimoto a49747df52
build: replace lib-vt step with -Demit-lib-vt option (#11716)
Remove the dedicated `zig build lib-vt` step and replace it with a
`-Demit-lib-vt` build option. This fixes two problems:

1. We can default XCFramework, app, etc. steps to false if emit-lib-vt
is true, so that the lib-vt build doesn't pull in unrelated artifacts.
**Most importantly, lib-vt alone can be build without full Xcode
installations.**

2. We can build lib-vt as part of a bundle with other artifacts if we
really want.
2026-03-21 07:13:28 -07:00
Mitchell Hashimoto 3fc04fd4ae
build: replace lib-vt step with -Demit-lib-vt option
Remove the dedicated `zig build lib-vt` step and replace it with a
`-Demit-lib-vt` build option. This fixes two problems:

1. We can default XCFramework, app, etc. steps to false if emit-lib-vt
   is true, so that the lib-vt build doesn't pull in unrelated
   artifacts. **Most importantly, lib-vt alone can be build without
   full Xcode installations.**

2. We can build lib-vt as part of a bundle with other artifacts if we
   really want.
2026-03-21 07:03:06 -07:00
Mitchell Hashimoto efb3523591
vt: add color_palette and color_rgb cell data types (#11717)
Add two new CellData variants to extract background color values
directly from cells. color_palette (10) returns the palette index as a
GhosttyColorPaletteIndex and color_rgb (11) returns the RGB components
as a GhosttyColorRgb. Both reuse the existing color types from color.h
rather than introducing new ones.

These are only valid when the cell content_tag is
bg_color_palette or bg_color_rgb respectively; querying them with a
mismatched tag reads from the wrong union member.

Found via Ghostling.
2026-03-20 21:25:49 -07:00
Mitchell Hashimoto b66120d37d
vt: add color_palette and color_rgb cell data types
Add two new CellData variants to extract background color values
directly from cells. color_palette (10) returns the palette index
as a GhosttyColorPaletteIndex and color_rgb (11) returns the RGB
components as a GhosttyColorRgb. Both reuse the existing color
types from color.h rather than introducing new ones.

These are only valid when the cell content_tag is
bg_color_palette or bg_color_rgb respectively; querying them
with a mismatched tag reads from the wrong union member.
2026-03-20 21:18:56 -07:00
Mitchell Hashimoto e8fb7eabad
build: set zig optimize flag for CMake release builds (#11707)
Map CMake release build types (Release, MinSizeRel, RelWithDebInfo) to
-Doptimize=ReleaseFast so that zig build automatically produces
optimized builds when CMake is configured for a release variant. Debug
builds remain unaffected, letting Zig use its default Debug optimization
level.
2026-03-20 15:41:48 -07:00
Mitchell Hashimoto 0e0db1074b
build: set zig optimize flag for CMake release builds
Map CMake release build types (Release, MinSizeRel, RelWithDebInfo)
to -Doptimize=ReleaseFast so that zig build automatically produces
optimized builds when CMake is configured for a release variant.
Debug builds remain unaffected, letting Zig use its default Debug
optimization level.
2026-03-20 14:41:43 -07:00
Mitchell Hashimoto 72fea098dc
ci: add build-cmake job to test cmake build of libghostty-vt (#11703)
Add a new CI job that builds the root CMakeLists.txt to ensure the cmake
wrapper for libghostty-vt works.

This isn't the recommend way to build libghostty-vt, but its how
downstream CMake projects would consume it so we gotta keep it working.
2026-03-20 12:22:28 -07:00
Mitchell Hashimoto 0066dfa9f6
core: add function to get process info from the surface (#11639)
This adds a function to the core surface to get process information
about the process(es) running in the terminal. Currently supported is
the PID of the foreground process and the name of the slave PTY.

If there is an error retrieving the information, or the platform does
not support retieving that information `null` is returned.

This will be useful in exposing the foreground PID and slave PTY name to
AppleScript or other APIs.
2026-03-20 12:22:02 -07:00
Mitchell Hashimoto fa84b8709c
ci: add build-cmake job to test cmake build of libghostty-vt
Add a new CI job that builds the root CMakeLists.txt to ensure the
cmake wrapper for libghostty-vt works. 

This isn't the recommend way to build libghostty-vt, but its how
downstream CMake projects would consume it so we gotta keep it
working.
2026-03-20 12:16:58 -07:00
Mitchell Hashimoto 9ba2614ac1
build: add CMake support for libghostty-vt (#11700)
Add a top-level CMakeLists.txt that wraps `zig build lib-vt` so that
CMake-based downstream projects can consume libghostty-vt without
needing to interact with the Zig build system directly. A custom command
triggers the zig build during `cmake --build`, and the resulting shared
library is exposed as an IMPORTED target.

Downstream projects can pull in the library via FetchContent, which
fetches the source and builds it as part of their own CMake build, or
via find_package after a manual install step. The package config
template in dist/cmake/ sets up the ghostty-vt::ghostty-vt target with
proper include paths and macOS rpath handling.

A c-vt-cmake example demonstrates the FetchContent workflow, creating a
terminal, writing VT sequences, and formatting the output as plain text.
CI is updated to auto-discover and build CMake-based examples alongside
the existing Zig-based ones.

> [!WARNING]
>
> I am **very much not a CMake expert.** I leaned on LLMs heavily for
this. I did read the docs for what was chosen here and understand what's
going on, but if there is a better or more idiomatic way to do this I'm
all ears!

## Example CMake File

```cmake
cmake_minimum_required(VERSION 3.19)
project(c-vt-cmake LANGUAGES C)

include(FetchContent)
FetchContent_Declare(ghostty
    GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
    GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)

add_executable(c_vt_cmake src/main.c)
target_link_libraries(c_vt_cmake PRIVATE ghostty-vt)
```
2026-03-20 11:56:36 -07:00
Mitchell Hashimoto 3dee62f904
build: add CMake support for libghostty-vt
Add a top-level CMakeLists.txt that wraps `zig build lib-vt` so that
CMake-based downstream projects can consume libghostty-vt without
needing to interact with the Zig build system directly. A custom
command triggers the zig build during `cmake --build`, and the
resulting shared library is exposed as an IMPORTED target.

Downstream projects can pull in the library via FetchContent, which
fetches the source and builds it as part of their own CMake build, or
via find_package after a manual install step. The package config
template in dist/cmake/ sets up the ghostty-vt::ghostty-vt target
with proper include paths and macOS rpath handling.

A c-vt-cmake example demonstrates the FetchContent workflow, creating
a terminal, writing VT sequences, and formatting the output as plain
text. CI is updated to auto-discover and build CMake-based examples
alongside the existing Zig-based ones.
2026-03-20 10:42:42 -07:00
Jeffrey C. Ollie 7b9e49a47f
core: build pty.c only on certain platforms (avoids building os iOS) 2026-03-20 12:10:47 -05:00
Mitchell Hashimoto aac491657b
windows: avoid fontconfig and ensure build compiles (#11698)
This changes allows me to use ghostty as a zon dependency when building
on windows (for windows). Fixes
https://github.com/ghostty-org/ghostty/discussions/11697
2026-03-20 09:55:16 -07:00
ghostty-vouch[bot] e680cf9f35
Update VOUCHED list (#11699)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11698#issuecomment-4099492496)
from @mitchellh.

Vouch: @marler8997

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-20 16:42:32 +00:00
Mitchell Hashimoto 00ffc22ecb
libghostty: starting render state API in C (#11664)
This adds the `terminal.RenderState` API for C. 

The render state API is the API that should be used to create a high
performance renderer. It limits access to a terminal instance to a very
optimized `update` call so that terminal IO is blocked for a tiny amount
of time. After that, all read access on the RenderState is safe to build
frame data.

## Example

```c
int main(void) {
  GhosttyResult result;

  GhosttyTerminal terminal = NULL;
  GhosttyTerminalOptions terminal_opts = {
      .cols = 80,
      .rows = 24,
      .max_scrollback = 10000,
  };
  result = ghostty_terminal_new(NULL, &terminal, terminal_opts);
  assert(result == GHOSTTY_SUCCESS);

  GhosttyRenderState render_state = NULL;
  result = ghostty_render_state_new(NULL, &render_state);
  assert(result == GHOSTTY_SUCCESS);

  const char* first_frame = "first frame\r\n";
  ghostty_terminal_vt_write(
      terminal,
      (const uint8_t*)first_frame,
      strlen(first_frame));
  result = ghostty_render_state_update(render_state, terminal);
  assert(result == GHOSTTY_SUCCESS);

  const char* second_frame = "second frame\r\n";
  ghostty_terminal_vt_write(
      terminal,
      (const uint8_t*)second_frame,
      strlen(second_frame));
  result = ghostty_render_state_update(render_state, terminal);
  assert(result == GHOSTTY_SUCCESS);

  printf("Render state was updated successfully.\n");

  ghostty_render_state_free(render_state);
  ghostty_terminal_free(terminal);
  return 0;
}
```

## API Changes

New `GhosttyRenderState` C API (`include/ghostty/vt/render.h`):

| Function | Description |
|---|---|
| `ghostty_render_state_new` | Allocate an empty render state. |
| `ghostty_render_state_free` | Destroy a render state. |
| `ghostty_render_state_update` | Snapshot a terminal instance into the
render state. |
| `ghostty_render_state_get` | Type-tagged read of dimensions, dirty
state, colors, cursor, palette. |
| `ghostty_render_state_set` | Type-tagged write (currently: dirty
state). |
| `ghostty_render_state_colors_get` | Bulk color read via sized-struct
for forward compatibility. |
| `ghostty_render_state_row_iterator_new` | Allocate a reusable row
iterator. |
| `ghostty_render_state_row_iterator_next` | Advance the row iterator. |
| `ghostty_render_state_row_iterator_free` | Destroy a row iterator. |
| `ghostty_render_state_row_get` | Read per-row data (dirty flag, raw
row, cells). |
| `ghostty_render_state_row_set` | Write per-row data (dirty flag). |
| `ghostty_render_state_row_cells_new` | Allocate a reusable cell
iterator. |
| `ghostty_render_state_row_cells_next` | Advance the cell iterator. |
| `ghostty_render_state_row_cells_select` | Jump the cell iterator to a
specific column. |
| `ghostty_render_state_row_cells_get` | Read per-cell data (raw cell,
style, graphemes). |
| `ghostty_render_state_row_cells_free` | Destroy a cell iterator. |

`GhosttyRenderStateData` keys (for `_get`):

| Key | Type | Description |
|---|---|---|
| `COLS` | `uint16_t` | Viewport width in cells. |
| `ROWS` | `uint16_t` | Viewport height in cells. |
| `DIRTY` | `GhosttyRenderStateDirty` | Global dirty state. |
| `ROW_ITERATOR` | `GhosttyRenderStateRowIterator` | Populate a
pre-allocated row iterator. |
| `COLOR_BACKGROUND` | `GhosttyColorRgb` | Default background color. |
| `COLOR_FOREGROUND` | `GhosttyColorRgb` | Default foreground color. |
| `COLOR_CURSOR` | `GhosttyColorRgb` | Explicit cursor color (invalid if
not set). |
| `COLOR_CURSOR_HAS_VALUE` | `bool` | Whether an explicit cursor color
is set. |
| `COLOR_PALETTE` | `GhosttyColorRgb[256]` | Active 256-color palette. |
| `CURSOR_VISUAL_STYLE` | `GhosttyRenderStateCursorVisualStyle` | Bar,
block, underline, or hollow block. |
| `CURSOR_VISIBLE` | `bool` | Cursor visibility from terminal modes. |
| `CURSOR_BLINKING` | `bool` | Cursor blink state from terminal modes. |
| `CURSOR_PASSWORD_INPUT` | `bool` | Whether cursor is at a password
field. |
| `CURSOR_VIEWPORT_HAS_VALUE` | `bool` | Whether cursor is in the
viewport. |
| `CURSOR_VIEWPORT_X` | `uint16_t` | Cursor viewport column. |
| `CURSOR_VIEWPORT_Y` | `uint16_t` | Cursor viewport row. |
| `CURSOR_VIEWPORT_WIDE_TAIL` | `bool` | Cursor on wide-char tail cell.
|

`GhosttyRenderStateOption` keys (for `_set`):

| Key | Type | Description |
|---|---|---|
| `DIRTY` | `GhosttyRenderStateDirty` | Reset global dirty state. |

`GhosttyRenderStateRowData` keys (for `_row_get`):

| Key | Type | Description |
|---|---|---|
| `DIRTY` | `bool` | Whether this row is dirty. |
| `RAW` | `GhosttyRow` | Raw row value. |
| `CELLS` | `GhosttyRenderStateRowCells` | Populate a pre-allocated cell
iterator. |

`GhosttyRenderStateRowOption` keys (for `_row_set`):

| Key | Type | Description |
|---|---|---|
| `DIRTY` | `bool` | Clear/set dirty flag for this row. |

`GhosttyRenderStateRowCellsData` keys (for `_row_cells_get`):

| Key | Type | Description |
|---|---|---|
| `RAW` | `GhosttyCell` | Raw cell value. |
| `STYLE` | `GhosttyStyle` | Resolved style for this cell. |
| `GRAPHEMES_LEN` | `uint32_t` | Total codepoints including base (0 if
empty). |
| `GRAPHEMES_BUF` | `uint32_t*` | Write codepoints into caller buffer. |
2026-03-20 09:34:52 -07:00
Jonathan Marler 542d6aa14d windows: avoid fontconfig and ensure build compiles 2026-03-20 10:27:40 -06:00
Mitchell Hashimoto e7a18ea5b3
vt: fix render state cell style and graphemes_buf APIs
The GRAPHEMES_BUF data kind previously required a double pointer
(pointer to a uint32_t*) because the OutType was [*]u32, making the
typed out parameter *[*]u32. Change OutType to u32 so that callers
pass a plain uint32_t* buffer directly, which is the natural C
calling convention. The implementation casts the out pointer to
[*]u32 internally to write into the buffer.

The STYLE data kind read directly from the render state style array
without checking whether the cell actually had non-default styling.
The style data is undefined for unstyled cells, so this caused a
panic on a corrupt enum value when the caller read the style of an
unstyled cell. Now check cell.hasStyling() first and return the
default style for unstyled cells.

Expand the c-vt-render example to exercise dirty tracking, color
retrieval, cursor state, row/cell iteration with style resolution,
and dirty state reset. Break the example into six doxygen snippet
regions and reference them from render.h.
2026-03-20 09:24:31 -07:00
Mitchell Hashimoto d9df4154db
vt: add cursor field data getters to render state API
Expose the cursor fields from RenderState.Cursor through the C API
via new GhosttyRenderStateData enum values. This adds getters for
visual style, visibility, blink state, password input detection,
and viewport position (x, y, wide tail).

A new GhosttyRenderStateCursorVisualStyle enum maps the Zig
cursor.Style values (bar, block, underline, block_hollow) to
stable C integer constants. Viewport position getters return
GHOSTTY_INVALID_VALUE when the cursor is not visible within
the viewport.
2026-03-20 09:05:20 -07:00
Mitchell Hashimoto 60ea2d76d4
vt: add color data getters to render state
Add individual color data kinds to GhosttyRenderStateData so callers
can query background, foreground, cursor color, cursor-color presence,
and the full 256-color palette through ghostty_render_state_get()
without using the sized-struct colors API.

COLOR_CURSOR returns GHOSTTY_INVALID_VALUE when no explicit cursor
color is set; callers can check COLOR_CURSOR_HAS_VALUE first.
2026-03-20 08:57:23 -07:00
Mitchell Hashimoto 6ae17a02af
vt: add cell-level iteration and data access to render state row cells
Add next, select, and get functions to the render state row cells
API, mirroring the row iterator pattern. row_cells_next advances to
the next cell sequentially, row_cells_select jumps to a specific
column index with bounds validation, and row_cells_get queries data
for the current cell position.

The get function supports querying raw cell values (GhosttyCell),
resolved styles (GhosttyStyle), grapheme codepoint counts, and
writing grapheme codepoints into a caller-provided buffer.

Also add Cell.C and Cell.cval() to page.zig, matching the existing
Row.C/Row.cval() pattern, so the render state can convert cells to
the C ABI type without a raw bitCast.
2026-03-20 08:53:45 -07:00
Jeffrey C. Ollie d5ce05fd37
core: simplify pty.c macro usage 2026-03-20 10:37:42 -05:00
Jeffrey C. Ollie a888db94b0
nix: add systems input and fix zig follows (#11686)
Currently I have to use [this unusual
syntax](6e1c9f32e0/flake.nix (L137))
in my flake inputs to ensure that I don't have systems repeated in my
flake.lock file. This will make more obvious the fact that you have to
do follows to that hidden input.
2026-03-20 07:35:59 -08:00
Mitchell Hashimoto ecd1d0d1e1
vt: decouple row iterator allocation from population
Change row_iterator_new to only allocate with undefined fields,
matching the pattern used by row_cells_new. The iterator is now
populated via the render state get API with a new .row_iterator
data kind, which slices the row data and resets y to null.

This separates the lifetime of the opaque handle from the render
state it iterates, letting callers allocate once and re-populate
from different states without reallocating.
2026-03-20 08:20:27 -07:00
Leah Amelia Chen 9c30bfadc5
gtk: various blur-related fixes (#10727) 2026-03-20 14:54:21 +00:00
Mitchell Hashimoto 75b49051a3
vt: add GhosttyRenderStateRowCells opaque type
Add a new opaque RowCells type that wraps per-row cell data
(raw cells, graphemes, styles) for the C API. The caller
allocates a RowCells handle via row_cells_new, then populates
it by passing it to row_get with the new .cells data kind.
This queries the current row from the iterator and slices the
underlying MultiArrayList into the RowCellsWrapper fields.

The new type and functions are wired through main.zig,
lib_vt.zig, and the render.h C header.
2026-03-20 07:25:52 -07:00
ghostty-vouch[bot] 46ece224ba
Update VOUCHED list (#11694)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11420#discussioncomment-16227199)
from @mitchellh.

Vouch: @hlcfan

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-20 14:23:05 +00:00
Mitchell Hashimoto 33e81ffb75
vt: use get/set pattern for row iterator data access
Replace ghostty_render_state_row_dirty_get and
ghostty_render_state_row_dirty_set with generic
ghostty_render_state_row_get and ghostty_render_state_row_set
functions using enum-dispatched data/option kinds.
2026-03-20 07:17:00 -07:00
Mitchell Hashimoto 459583a6c3
vt: use get/set pattern for render state data access
Replace the individual ghostty_render_state_size_get,
ghostty_render_state_dirty_get, and ghostty_render_state_dirty_set
functions with generic ghostty_render_state_get and
ghostty_render_state_set functions that use enum-dispatched data
kinds and option kinds, following the same InType/OutType pattern
used by the terminal and mouse encoder C APIs.
2026-03-20 07:00:14 -07:00
ghostty-vouch[bot] ff0ee364bb
Update VOUCHED list (#11691)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11686#issuecomment-4098087863)
from @mitchellh.

Vouch: @luisnquin

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-20 13:49:07 +00:00
Mitchell Hashimoto e2399de38c
bash: suppress __ghostty_hook errors in inherited PROMPT_COMMAND (#11690)
When some tools spawn subshells, PROMPT_COMMAND may be inherited as an
environment variable while the __ghostty_hook function is not (bash
doesn't export functions by default). This causes "command not found"
errors on every prompt in the subshell.

Add 2>/dev/null to the __ghostty_hook entry in PROMPT_COMMAND so that it
silently no-ops in subshells where the function isn't defined. This also
silences any errors from inside __ghostty_hook itself, but those are all
terminal escape sequences and non-actionable.

See: #11245
2026-03-20 06:46:49 -07:00
Jon Parise 4b9324f48a bash: suppress __ghostty_hook errors in inherited PROMPT_COMMAND
When some tools spawn subshells, PROMPT_COMMAND may be inherited as an
environment variable while the __ghostty_hook function is not (bash
doesn't export functions by default). This causes "command not found"
errors on every prompt in the subshell.

Add 2>/dev/null to the __ghostty_hook entry in PROMPT_COMMAND so that it
silently no-ops in subshells where the function isn't defined. This also
silences any errors from inside __ghostty_hook itself, but those are all
terminal escape sequences and non-actionable.

See: #11245
2026-03-20 09:41:34 -04:00
Luis Quiñones 220d6fd43d
nix: add systems input and fix zig follows 2026-03-20 04:11:25 -05:00
Mitchell Hashimoto 7966740b48
bash: move __ghostty_preexec_hook into __ghostty_hook (#11674)
We previously used a readonly variable (__ghostty_ps0) to define the
best __ghostty_preexec_hook expansion for the current bash version.

This worked pretty well, but it had the downside of managing another
variable (#11258).

We can instead simplify this a bit by moving this into __ghostty_hook. I
didn't take that approach originally because I wanted to avoid the bash
version check on each command, but slightly loosening our guard check to
just look for "__ghostty_preexec_hook" (rather than the full expansion
expression) means we can bury the bash version check to the cold path.

One small gap here is that we may not update PS0 to the correct syntax
if we start switching between significantly different bash versions in
interactive subshells, but that seems like a pretty rare case to handle
given the benefits of this approach.
2026-03-19 20:13:46 -07:00
Mitchell Hashimoto 900afa7b80
fix types 2026-03-19 20:13:14 -07:00
Mitchell Hashimoto 2147b9d65c
vt: row dirty tracking 2026-03-19 20:13:14 -07:00
Mitchell Hashimoto f610d7e00f
vt: add render_row_iterator_next 2026-03-19 20:13:14 -07:00
Mitchell Hashimoto ad0e47ebac
vt: cover c row iterator new/free
Add a C ABI row-iterator handle for render state with
ghostty_render_state_row_iterator_new and
ghostty_render_state_row_iterator_free, and wire them through
src/terminal/c/main.zig, src/lib_vt.zig, and
include/ghostty/vt/render.h. The header now documents only the
currently exported iterator API.
2026-03-19 20:13:14 -07:00
Mitchell Hashimoto b35f8ed16e
vt: expose render state colors in C API
Add a C-facing GhosttyRenderStateColors sized struct and a
ghostty_render_state_colors_get accessor so renderers can read
background, foreground, cursor color state, and palette data directly
from the render state.
2026-03-19 20:13:14 -07:00
Mitchell Hashimoto b830a0ee1d
vt: add size getter for render state
Add ghostty_render_state_size_get() to return cols and rows from the
current render state using out pointers. The C wrapper validates null
inputs, the symbol is wired through the C API export layers, and tests
cover success and invalid-value paths.
2026-03-19 20:13:14 -07:00
Mitchell Hashimoto 2876fb7a55
vt: expose dirty state in C API
Switch RenderState.Dirty to lib.Enum so it uses C-compatible enum
backing when building the C ABI target. Add GhosttyRenderStateDirty and
new ghostty_render_state_dirty_get/set declarations to the render header,
then wire both functions through src/terminal/c/main.zig and the lib_vt
export table.
2026-03-19 20:13:14 -07:00
Mitchell Hashimoto a0d738697e
vt: add c render state api and example
Introduce the first public C render-state surface for libghostty-vt.
Before this change, the render-state path was only available in Zig,
so C embedders had no direct way to create and update that cache.

Add an opaque GhosttyRenderState type with new, update, and free
entry points, then wire those symbols through the C API bridge and
library exports. Keep the surface intentionally minimal for now so
ownership and update behavior are established before adding read
accessors.
2026-03-19 20:13:14 -07:00
Mitchell Hashimoto d2a29de959
libghostty: terminal data, grid point and cell inspection APIs (#11676)
This adds a complete set of APIs for inspecting individual cells and
rows in the terminal grid from C. Callers can now resolve any point in
the grid to a reference, then extract codepoints, grapheme clusters,
styles, wide-character state, semantic prompt tags, and row-level
metadata like wrap and dirty flags.

This also adds a robust `ghostty_terminal_get` API for extracting
information like rows, cols, active screen, cursor information, etc.
from the terminal.

## Example

```c
// Write bold red text via SGR sequences
const char *text = "\033[1;31mHello\033[0m";
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));

// Resolve cell (0,0) to a grid reference
GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint pt = {
  .tag = GHOSTTY_POINT_TAG_ACTIVE,
  .value = { .coordinate = { .x = 0, .y = 0 } },
};
ghostty_terminal_grid_ref(terminal, pt, &ref);

// Read the codepoint ('H')
GhosttyCell cell;
ghostty_grid_ref_cell(&ref, &cell);
uint32_t codepoint = 0;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_CODEPOINT, &codepoint);

// Read the resolved style (bold=true, fg=red)
GhosttyStyle style = GHOSTTY_INIT_SIZED(GhosttyStyle);
ghostty_grid_ref_style(&ref, &style);
assert(style.bold);
```

## API Changes

### New Types

| Type | Description |
|------|-------------|
| `GhosttyCell` | Opaque 64-bit cell value |
| `GhosttyRow` | Opaque 64-bit row value |
| `GhosttyCellData` | Enum for `ghostty_cell_get` data kinds (codepoint,
content tag, wide, has_text, etc.) |
| `GhosttyCellContentTag` | Cell content kind (codepoint, grapheme, bg
color palette/RGB) |
| `GhosttyCellWide` | Cell width (narrow, wide, spacer tail/head) |
| `GhosttyCellSemanticContent` | Semantic content type (output, input,
prompt) |
| `GhosttyRowData` | Enum for `ghostty_row_get` data kinds (wrap,
grapheme, styled, dirty, etc.) |
| `GhosttyRowSemanticPrompt` | Row-level semantic prompt state |
| `GhosttyGridRef` | Sized struct — resolved reference to a cell
position in the page structure |
| `GhosttyPoint` | Tagged union specifying a grid position in a given
coordinate system |
| `GhosttyPointTag` | Coordinate system tag: `ACTIVE`, `VIEWPORT`,
`SCREEN`, `HISTORY` |
| `GhosttyPointCoordinate` | x/y coordinate pair |
| `GhosttyStyleId` | Style identifier type (uint16) |

### New Functions

| Function | Description |
|----------|-------------|
| `ghostty_cell_get` | Extract typed data from a cell (codepoint, wide,
style ID, etc.) |
| `ghostty_row_get` | Extract typed data from a row (wrap, dirty,
semantic prompt, etc.) |
| `ghostty_terminal_grid_ref` | Resolve a `GhosttyPoint` to a
`GhosttyGridRef` |
| `ghostty_grid_ref_cell` | Extract the `GhosttyCell` from a grid ref |
| `ghostty_grid_ref_row` | Extract the `GhosttyRow` from a grid ref |
| `ghostty_grid_ref_graphemes` | Get the full grapheme cluster
(codepoints) for the cell |
| `ghostty_grid_ref_style` | Get the resolved `GhosttyStyle` for the
cell |
2026-03-19 20:12:56 -07:00
Jeffrey C. Ollie b0789af583
core: fix c macro comparisons 2026-03-19 22:01:16 -05:00
Jeffrey C. Ollie 2ea6029c7a
core: address getProcessInfo feedback
* consolidate *.c files into a single file
* consolidate ProcessInfo enums into a single enum
2026-03-19 22:01:16 -05:00
Jeffrey C. Ollie 264a1a7cdd
core: fix target for macos libc search 2026-03-19 22:01:16 -05:00
Jeffrey C. Ollie 64de418f38
core: add macos system include path 2026-03-19 22:01:16 -05:00
Jeffrey C. Ollie 89ae0ea6ef
core: add function to get process info from the surface
This adds a function to the core surface to get process information
about the process(es) running in the terminal. Currently supported is
the PID of the foreground process and the name of the slave PTY.

If there is an error retrieving the information, or the platform does
not support retieving that information `null` is returned.

This will be useful in exposing the foreground PID and slave PTY name to
AppleScript or other APIs.
2026-03-19 22:01:15 -05:00
Mitchell Hashimoto 93c597ce6b
example: add grid reference traversal example
Add a c-vt-grid-ref example that demonstrates the terminal and grid
reference APIs end-to-end. The example creates a small 10x3 terminal,
writes text with mixed styles via VT sequences, then iterates over
every cell in the active area using ghostty_terminal_grid_ref. For
each cell it extracts the codepoint, and for each row it inspects
the wrap flag and the style bold attribute.

The grid_ref.h defgroup gains a @snippet reference to the new example,
and vt.h gets the corresponding @example entry and @ref listing.
2026-03-19 19:55:02 -07:00
ghostty-vouch[bot] 1f89ce91d9
Update VOUCHED list (#11675)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11671#discussioncomment-16218675)
from @jcollie.

Vouch: @unphased

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-20 02:51:06 +00:00
Jeffrey C. Ollie e9eac7d475
build(deps): bump namespacelabs/nscloud-setup from 0.0.11 to 0.0.12 (#11672)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps
[namespacelabs/nscloud-setup](https://github.com/namespacelabs/nscloud-setup)
from 0.0.11 to 0.0.12.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="df198f982f"><code>df198f9</code></a>
Update to node24 (<a
href="https://redirect.github.com/namespacelabs/nscloud-setup/issues/10">#10</a>)</li>
<li>See full diff in <a
href="f378676225...df198f982f">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=namespacelabs/nscloud-setup&package-manager=github_actions&previous-version=0.0.11&new-version=0.0.12)](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-03-19 18:49:26 -08:00
Jeffrey C. Ollie 4531594d51
build(deps): bump namespacelabs/nscloud-setup-buildx-action from 0.0.22 to 0.0.23 (#11673)
Bumps
[namespacelabs/nscloud-setup-buildx-action](https://github.com/namespacelabs/nscloud-setup-buildx-action)
from 0.0.22 to 0.0.23.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d059ed7184"><code>d059ed7</code></a>
Update to node24 (<a
href="https://redirect.github.com/namespacelabs/nscloud-setup-buildx-action/issues/15">#15</a>)</li>
<li>See full diff in <a
href="f5814dcf37...d059ed7184">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=namespacelabs/nscloud-setup-buildx-action&package-manager=github_actions&previous-version=0.0.22&new-version=0.0.23)](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-03-19 18:48:30 -08:00
Mitchell Hashimoto 549824842d
vt: add style and grapheme accessors
Add ghostty_grid_ref_style and ghostty_grid_ref_graphemes to the grid
ref C API, allowing callers to extract the full style and grapheme
cluster directly from a grid reference without manually resolving
the page internals.
2026-03-19 19:48:16 -07:00
Mitchell Hashimoto df8813bf1b
vt: replace ghostty_terminal_cell with GhosttyGridRef API 2026-03-19 19:40:53 -07:00
Jon Parise 2a952b4dfe bash: move __ghostty_preexec_hook into __ghostty_hook
We previously used a readonly variable (__ghostty_ps0) to define the
best __ghostty_preexec_hook expansion for the current bash version.

This works pretty well, but it had the downside of managing another
variable (#11258).

We can instead simplify this a bit by moving this into __ghostty_hook. I
didn't take that approach originally because I wanted to avoid the bash
version check on each command, but slightly loosening our guard check to
just look for "__ghostty_preexec_hook" (rather than the full expansion
expression) means we can bury the bash version check to the cold path.

One small gap here is that we may not update PS0 to the correct syntax
if we start switching between significantly different bash versions in
interactive subshells, but that seems like a pretty rare case to handle
given the benefits of this approach.
2026-03-19 20:59:16 -04:00
dependabot[bot] 7c14aecd3f
build(deps): bump namespacelabs/nscloud-setup-buildx-action
Bumps [namespacelabs/nscloud-setup-buildx-action](https://github.com/namespacelabs/nscloud-setup-buildx-action) from 0.0.22 to 0.0.23.
- [Release notes](https://github.com/namespacelabs/nscloud-setup-buildx-action/releases)
- [Commits](f5814dcf37...d059ed7184)

---
updated-dependencies:
- dependency-name: namespacelabs/nscloud-setup-buildx-action
  dependency-version: 0.0.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 00:12:37 +00:00
dependabot[bot] 10e69384d7
build(deps): bump namespacelabs/nscloud-setup from 0.0.11 to 0.0.12
Bumps [namespacelabs/nscloud-setup](https://github.com/namespacelabs/nscloud-setup) from 0.0.11 to 0.0.12.
- [Release notes](https://github.com/namespacelabs/nscloud-setup/releases)
- [Commits](f378676225...df198f982f)

---
updated-dependencies:
- dependency-name: namespacelabs/nscloud-setup
  dependency-version: 0.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 00:12:29 +00:00
Mitchell Hashimoto 0400de28b4
vt: add ghostty_terminal_cell for point-based cell lookup
Add a new C API function ghostty_terminal_cell that retrieves the
opaque cell and row values at a given point in the terminal grid.
The point is a tagged union supporting active, viewport, screen, and
history coordinate systems.
2026-03-19 15:16:55 -07:00
Mitchell Hashimoto 057f227145
terminal: convert Point to lib.Enum/lib.TaggedUnion with C header 2026-03-19 14:01:11 -07:00
Mitchell Hashimoto 5c8b9f3f43
vt: add GhosttyCell and GhosttyRow C API with data getters
Add opaque GhosttyCell (uint64_t) and GhosttyRow (uint64_t) types that
bitcast to the internal packed Cell and Row structs from page.zig. Each
type has a corresponding data enum and getter function following the
same pattern as ghostty_terminal_get.

ghostty_cell_get supports extracting codepoint, content tag, wide
property, has_text, has_styling, style_id, has_hyperlink, protected,
and semantic_content. ghostty_row_get supports wrap, wrap_continuation,
grapheme, styled, hyperlink, semantic_prompt, kitty_virtual_placeholder,
and dirty.

The cell and row types and functions live in a new screen.h header,
separate from terminal.h, with terminal.h including screen.h for
convenience.
2026-03-19 13:15:45 -07:00
Mitchell Hashimoto d827225573
vt: expand padding for color union to 64-bit to allow for a pointer 2026-03-19 12:24:34 -07:00
Mitchell Hashimoto d62f6df1d5
vt: expose cursor_style via terminal_get
Add cursor_style to TerminalData, returning the current SGR style
of the cursor (the style applied to newly printed characters) as a
GhosttyStyle.

Refactor the C style conversion helpers: replace the standalone
convertStyle and convertColor functions with fromStyle and fromColor
initializers on the Style and Color extern structs respectively.
2026-03-19 12:08:31 -07:00
Mitchell Hashimoto 7f36e8bd43
vt: add style C API
Expose the terminal Style struct to the C API as GhosttyStyle, a
sized struct with foreground, background, and underline colors
(as tagged unions) plus boolean text decoration flags.

Add ghostty_style_default() to obtain the default style and
ghostty_style_is_default() to check whether a style has all
default values. Wire both through c/style.zig, main.zig, and
lib_vt.zig with the corresponding header in vt/style.h.
2026-03-19 12:02:03 -07:00
Mitchell Hashimoto f168b3c098
vt: add ghostty_terminal_get for reading terminal state
Add a typed data query API to the terminal C interface, following
the same OutType pattern used by the OSC command data API. The new
ghostty_terminal_get function takes a GhosttyTerminalData tag and
an output pointer, returning GhosttyResult.

Currently exposes cols, rows, cursor x/y position, and cursor
pending wrap state. The GhosttyTerminalData enum is placed with the
other types in the header (before functions) per the ordering
convention.
2026-03-19 11:47:55 -07:00
Lukas d80d84862e
macOS: fix mouse not working correctly in CommandPaletteView (#11658) 2026-03-19 19:26:58 +01:00
Lukas ac3893d0b9
macOS: Add command palette tests 2026-03-19 19:26:57 +01:00
Lukas 50113ab678
macOS: add mouse state tests for #11276
It will fail on 4e24adf71 and success after #11276
2026-03-19 19:02:13 +01:00
Mitchell Hashimoto c2e9de224e
build(deps): bump cachix/cachix-action from 16 to 17 (#11643)
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action)
from 16 to 17.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cachix/cachix-action/releases">cachix/cachix-action's
releases</a>.</em></p>
<blockquote>
<h2>v17</h2>
<h2>What's Changed</h2>
<h3>Breaking changes</h3>
<ul>
<li>Upgrade action to use Node 24 by <a
href="https://github.com/sandydoo"><code>@​sandydoo</code></a> in <a
href="https://redirect.github.com/cachix/cachix-action/pull/212">cachix/cachix-action#212</a>
<a
href="https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/">https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/cachix-action/compare/v16...v17">https://github.com/cachix/cachix-action/compare/v16...v17</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1eb2ef646a"><code>1eb2ef6</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/cachix-action/issues/212">#212</a>
from cachix/upgrade-node-24</li>
<li><a
href="75ce400143"><code>75ce400</code></a>
dist: re-build using esbuild targeting node24</li>
<li><a
href="2b33705a82"><code>2b33705</code></a>
deps: update devenv inputs</li>
<li><a
href="04937db281"><code>04937db</code></a>
breaking: update action to Node 24</li>
<li><a
href="ca2e51995f"><code>ca2e519</code></a>
ci: use 25.11 for tests</li>
<li><a
href="e7c5c1add2"><code>e7c5c1a</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/cachix-action/issues/208">#208</a>
from cachix/dependabot/github_actions/actions/checkout-6</li>
<li><a
href="bea8a50645"><code>bea8a50</code></a>
ci: allow running tests manually and with a custom nix version</li>
<li><a
href="2e35755955"><code>2e35755</code></a>
chore(deps): bump actions/checkout from 5 to 6</li>
<li>See full diff in <a
href="3ba601ff5b...1eb2ef646a">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cachix/cachix-action&package-manager=github_actions&previous-version=16&new-version=17)](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-03-19 08:38:49 -07:00
Mitchell Hashimoto 2bbbca369d
bash: emit 133;P (instead of 133;A) under ble.sh (#11644)
ble.sh performs its own cursor positioning so we get multiple newlines
with 133;A's fresh-line behavior. ble.sh is a large enough project to
justify this additional, unambiguous conditional.

See: akinomyoga/ble.sh#684
See: wezterm/wezterm#5072
2026-03-19 08:38:24 -07:00
Jon Parise b1ad24e24f bash: emit 133;P (instead of 133;A) under ble.sh
ble.sh performs its own cursor positioning so we get multiple newlines
with 133;A's fresh-line behavior. ble.sh is a large enough project to
justify this additional, unambiguous conditional.

See: akinomyoga/ble.sh#684
See: wezterm/wezterm#5072
2026-03-19 11:26:52 -04:00
Jeffrey C. Ollie 69e0673478
ci: use local git commands for path-filter action (#11652)
Passing a `token` value causes this action to use the GitHub REST API,
which is subject to rate limits. We can chew through that allowance
quickly (1,000 requests/hour) given that we run two of these actions per
workflow run.

`token` defaults to the workflow's token, but by setting it explicitly
to an empty string, the action will instead use `git diff` to determine
the modified paths. This works fine for our case because we're already
running the checkout action, so we have an up-to-date repository view.

This also has the advantage of working around the 300 files GitHub REST
API limit for listing changed files.

Ref: https://github.com/dorny/paths-filter
2026-03-19 04:19:47 -08:00
Jon Parise c9729fbd26 ci: use local git commands for path-filter action
Passing a `token` value causes this action to use the GitHub REST API,
which is subject to rate limits. We can chew through that allowance
quickly (1,000 requests/hour) given that we run two of these actions per
workflow run.

`token` defaults to the workflow's token, but by setting it explicitly
to an empty string, the action will instead use `git diff` to determine
the modified paths. This works fine for our case because we're already
running the checkout action, so we have an up-to-date repository view.

This also has the advantage of working around the 300 files GitHub REST
API limit for listing changed files.

Ref: https://github.com/dorny/paths-filter
2026-03-19 08:06:34 -04:00
dependabot[bot] c08a21180a
build(deps): bump cachix/cachix-action from 16 to 17
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action) from 16 to 17.
- [Release notes](https://github.com/cachix/cachix-action/releases)
- [Commits](3ba601ff5b...1eb2ef646a)

---
updated-dependencies:
- dependency-name: cachix/cachix-action
  dependency-version: '17'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-19 00:13:01 +00:00
Jeffrey C. Ollie c9e1006213
Fix: correct "Open Ghostty Here" Dolphin action for Plasma (#11614)
See #11594

The change allows "Open Ghostty Here" Dolphin action to launch new
ghostty window with gtk single instance.
2026-03-18 11:49:10 -05:00
Mitchell Hashimoto 3dc69981d2
bash: handle PROMPT_COMMAND ending in a newline (#11621)
We need to handle on more case: when an existing PROMPT_COMMAND ends in
a newline, we don't want to append a ; because that already counts as a
command separator.

We now handle all of these PROMPT_COMMAND cases:

- Ends with ; — no ; added
- Ends with \n or other whitespace — no ; added
- Ends with a command name — ; added as separator

See: #11245
2026-03-18 09:10:20 -07:00
Mitchell Hashimoto 9e6c875f33
Ensure all examples in libghostty C docs build and run in CI (#11609)
This moves all our examples away from embedded source to `@snippet` and
files so that we can use our CI to actually run the builds and keep them
working.

Note: I used AI to extract the examples, and it did some weird merging
stuff. It all works but I want to make sure all these examples are still
human friendly so I need to go back and review all that. I clicked
through the web docs and they look good, just need to verify the GitHub
flow.
2026-03-18 08:34:35 -07:00
ghostty-vouch[bot] a74f43760e
Update VOUCHED list (#11623)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11622#issuecomment-4082875090)
from @00-kat.

Vouch: @EkaterinePapava

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-18 14:11:47 +00:00
Jon Parise 1f3a3b41f7 bash: handle PROMPT_COMMAND ending in a newline
We need to handle on more case: when an existing PROMPT_COMMAND ends in
a newline, we don't want to append a ; because that already counts as a
command separator.

We now handle all of these PROMPT_COMMAND cases:

- Ends with ; — no ; added
- Ends with \n or other whitespace — no ; added
- Ends with a command name — ; added as separator

See: #11245
2026-03-18 09:55:34 -04:00
Yuzu Vita 4b1e48b71e
swap arguments 2026-03-18 13:40:28 +08:00
Mitchell Hashimoto 996ce03f0b
example: rename some examples 2026-03-17 17:39:26 -07:00
Mitchell Hashimoto 383a7e14a7
example: add README 2026-03-17 17:37:20 -07:00
Mitchell Hashimoto f037f41f78
Add example AGENTS file 2026-03-17 17:13:08 -07:00
Mitchell Hashimoto ceef8065b0
ci: filter build-examples to directories with build.zig.zon
The dynamic example directory discovery added in bb3b3ba included
all subdirectories under example/, but some (wasm-key-encode,
wasm-sgr) are pure HTML examples with no build.zig.zon. Running
zig build in those directories falls back to the root build.zig
and attempts a full GTK binary build, which fails on CI.

Filter the listing to only include directories that contain a
build.zig.zon file so non-Zig examples are excluded from the
build matrix.
2026-03-17 17:05:59 -07:00
Mitchell Hashimoto 15b8976d64
docs: extract inline code examples into standalone projects
Extract inline @code blocks from vt headers (size_report.h, modes.h,
sgr.h, paste.h, mouse.h, key.h) into standalone buildable examples
under example/. Each header now uses Doxygen @snippet tags to include
code from the example source files, keeping documentation in sync
with code that is verified to compile and run.

New example projects: c-vt-size-report and c-vt-modes. Existing
examples (c-vt-sgr, c-vt-paste, c-vt-mouse-encode, c-vt-key-encode)
gain snippet markers so their code can be referenced from the headers.
Conceptual snippets in key.h, mouse.h, and key/encoder.h that show
terminal-state usage patterns remain inline since they cannot be
compiled standalone.
2026-03-17 17:03:58 -07:00
Mitchell Hashimoto bb3b3ba615
ci: dynamically discover example directories for build-examples
Replace the hardcoded matrix list in the build-examples job with a
dynamic list-examples job that discovers all subdirectories under
example/ at runtime. This uses ls/jq to produce a JSON array and
fromJSON() to feed it into the matrix, so new examples are picked
up automatically without updating the workflow.
2026-03-17 16:52:49 -07:00
Mitchell Hashimoto e01046af15
docs: extract focus encoding example into standalone project
Extract the inline code example from focus.h into a standalone
buildable example at example/c-vt-encode-focus. The header now
uses a Doxygen @snippet tag to include the code from the example
source file, so the documentation stays in sync with code that
is verified to compile and run.
2026-03-17 16:48:48 -07:00
Mitchell Hashimoto d3bd224081
terminal/vt: extract size report encoding to its own file (#11607)
Extract size report encoding into a reusable module and expose it
through the libghostty-vt C API as `ghostty_size_report_encode()`.

Size report escape sequences (mode 2048 in-band reports, XTWINOPS CSI
14/16/18 t responses) were formatted inline in
`Termio.sizeReportLocked`, and `termio.Message` carried its own
duplicate enum for report styles. This made the encoding logic
impossible to reuse from the C library and kept the style type
unnecessarily scoped to termio.

## Example

```c
GhosttySizeReportSize size = {
    .rows = 24, .columns = 80,
    .cell_width = 9, .cell_height = 18,
};

char buf[64];
size_t written = 0;
ghostty_size_report_encode(
    GHOSTTY_SIZE_REPORT_MODE_2048, size,
    buf, sizeof(buf), &written);
// buf contains: "\x1b[48;24;80;432;720t"
```
2026-03-17 16:48:09 -07:00
Mitchell Hashimoto 7bf89740dd
vt: expose size_report encoding in the C API
Add ghostty_size_report_encode() to libghostty-vt, following the
same pattern as focus encoding: a single stateless function that
writes a terminal size report escape sequence into a caller-provided
buffer.

The size_report.zig Style enum and Size struct now use lib.Enum and
lib.Struct so the types are automatically C-compatible when building
with c_abi, eliminating the need for duplicate type definitions in
the C wrapper. The C wrapper in c/size_report.zig re-exports these
types directly and provides the callconv(.c) encode entry point.

Supports mode 2048 in-band reports and XTWINOPS responses (CSI 14 t,
CSI 16 t, CSI 18 t).
2026-03-17 16:33:57 -07:00
Mitchell Hashimoto a1d7ad9243
terminal: extract size report encoder
Size report escape sequences were previously formatted inline in
Termio.sizeReportLocked, and termio.Message carried a duplicate enum for
report styles. That made the encoding logic harder to reuse and kept
the style type scoped to termio.

Move the encoding into terminal.size_report and export it through
terminal.main. The encoder now takes renderer.Size directly and derives
grid and pixel dimensions from one source of truth. termio.Message now
aliases terminal.size_report.Style, and Termio writes reports via the
shared encoder.
2026-03-17 16:21:34 -07:00
ghostty-vouch[bot] 45ccc69a49
Update VOUCHED list (#11605)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11603#discussioncomment-16184007)
from @jcollie.

Vouch: @philocalyst

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-17 21:05:51 +00:00
Leah Amelia Chen 27fd1c7788
gtk/winproto: fix memleak & other tweaks 2026-03-18 03:37:03 +08:00
Leah Amelia Chen 80ab5d92ea
gtk/x11: use BlurRegion 2026-03-18 03:07:58 +08:00
Leah Amelia Chen 5abf21c1e2
gtk/wayland: complete blur region calculation
It took me a while and with lots of trial and error to arrive here,
but the end result looks pretty good.
2026-03-18 03:07:58 +08:00
Leah Amelia Chen 9e2e99c55f
gtk/wayland: replace KDE blur with ext-background-effect-v1
The venerable KDE blur protocol has been replaced with the compositor-
agnostic ext-background-effect-v1 protocol, to be implemented by Niri and
others. The new protocol is much easier to use overall, though we do need
to calculate the blur region manually like X11.
2026-03-18 03:07:46 +08:00
Mitchell Hashimoto d9070dbee2
Fix tmux control parser premature %end/%error block termination (#11597)
Fixes [#11935.](https://github.com/ghostty-org/ghostty/issues/11395)

I’m new to Zig, so I used AI assistance (Codex) while preparing this
change. Before opening this PR, I manually reviewed every line of the
final patch and stepped through the parser in LLDB to verify the
behavior. Happy to make any changes.

To better understand the parser, I also built a small model-checker
model
[here](https://gist.github.com/wyounas/284036272ba5893b6e413cafe2fe2a24).

Separately from this fix, I think formal verification and modeling could
be useful for parser work in Ghostty. The model is written in FizzBee,
which uses a Python-like Starlark syntax and is fairly readable. If that
seems useful, I’d be happy to open a separate discussion about whether
something like that belongs in the repository as executable
documentation or an additional safety net for future parser changes.
2026-03-17 10:32:14 -07:00
ghostty-vouch[bot] b173b2dfb7
Update VOUCHED list (#11599)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11594#discussioncomment-16180979)
from @jcollie.

Vouch: @heddxh

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-17 16:46:10 +00:00
Mitchell Hashimoto 4a88f460c4
terminal/tmux: stylistic cleanups 2026-03-17 08:58:22 -07:00
ghostty-vouch[bot] 739da492b8
Update VOUCHED list (#11598)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11537#issuecomment-4075954392)
from @mitchellh.

Unvouch: @cadebrown

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-17 15:42:06 +00:00
Mitchell Hashimoto 3a65bd5c4f
zsh: use OSC 133;P;k=s for secondary prompts (#11596)
This is consistent with our bash prompt handling and also lets us
simplify our multiline prompt logic (because it no longer needs to work
around 133;A's fresh-line behavior).
2026-03-17 08:35:07 -07:00
Jon Parise 3e0d434e8a zsh: use OSC 133;P;k=s for secondary prompts
This is consistent with our bash prompt handling and also lets us
simplify our multiline prompt logic (because it no longer needs to work
around 133;A's fresh-line behavior).
2026-03-17 10:37:40 -04:00
Yuzu Vita 2d514013d5
fix "open terminal here" action on Plasma 2026-03-17 22:18:07 +08:00
Leah Amelia Chen 71d6f08e9b
gtk: move audio playback into separate file, enabling reuse (#11588) 2026-03-17 04:42:51 +00:00
ghostty-vouch[bot] 9f4e42a523
Update VOUCHED list (#11587)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11585#discussioncomment-16170774)
from @jcollie.

Vouch: @heaths

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-17 03:08:46 +00:00
Jeffrey C. Ollie 79162279d9
gtk: move audio playback into separate file, enabling reuse 2026-03-16 19:53:24 -05:00
Mitchell Hashimoto 5e0db1b605
build(deps): bump softprops/action-gh-release from 2.6.0 to 2.6.1 (#11582)
Bumps
[softprops/action-gh-release](https://github.com/softprops/action-gh-release)
from 2.6.0 to 2.6.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v2.6.1</h2>
<p><code>2.6.1</code> is a patch release focused on restoring linked
discussion thread creation when
<code>discussion_category_name</code> is set. It fixes
<code>[#764](https://github.com/softprops/action-gh-release/issues/764)</code>,
where the draft-first publish flow
stopped carrying the discussion category through the final publish
step.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: preserve discussion category on publish by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/765">softprops/action-gh-release#765</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>2.6.1</h2>
<p><code>2.6.1</code> is a patch release focused on restoring linked
discussion thread creation when
<code>discussion_category_name</code> is set. It fixes
<code>[#764](https://github.com/softprops/action-gh-release/issues/764)</code>,
where the draft-first publish flow
stopped carrying the discussion category through the final publish
step.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: preserve discussion category on publish by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/765">softprops/action-gh-release#765</a></li>
</ul>
<h2>2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>feat: support previous_tag for generate_release_notes by <a
href="https://github.com/pocesar"><code>@​pocesar</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/372">softprops/action-gh-release#372</a></li>
</ul>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: recover concurrent asset metadata 404s by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/760">softprops/action-gh-release#760</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify reused draft release behavior by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/759">softprops/action-gh-release#759</a></li>
<li>docs: clarify working_directory input by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/761">softprops/action-gh-release#761</a></li>
<li>ci: verify dist bundle freshness by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/762">softprops/action-gh-release#762</a></li>
<li>fix: clarify immutable prerelease uploads by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/763">softprops/action-gh-release#763</a></li>
</ul>
<h2>2.5.3</h2>
<p><code>2.5.3</code> is a patch release focused on the remaining
path-handling and release-selection bugs uncovered after
<code>2.5.2</code>.
It fixes
<code>[#639](https://github.com/softprops/action-gh-release/issues/639)</code>,
<code>[#571](https://github.com/softprops/action-gh-release/issues/571)</code>,
<code>[#280](https://github.com/softprops/action-gh-release/issues/280)</code>,
<code>[#614](https://github.com/softprops/action-gh-release/issues/614)</code>,
<code>[#311](https://github.com/softprops/action-gh-release/issues/311)</code>,
<code>[#403](https://github.com/softprops/action-gh-release/issues/403)</code>,
and
<code>[#368](https://github.com/softprops/action-gh-release/issues/368)</code>.
It also adds documentation clarifications for
<code>[#541](https://github.com/softprops/action-gh-release/issues/541)</code>,
<code>[#645](https://github.com/softprops/action-gh-release/issues/645)</code>,
<code>[#542](https://github.com/softprops/action-gh-release/issues/542)</code>,
<code>[#393](https://github.com/softprops/action-gh-release/issues/393)</code>,
and
<code>[#411](https://github.com/softprops/action-gh-release/issues/411)</code>,
where the current behavior is either usage-sensitive or constrained by
GitHub platform limits rather than an action-side runtime bug.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="153bb8e044"><code>153bb8e</code></a>
release 2.6.1</li>
<li><a
href="569deb874d"><code>569deb8</code></a>
fix: preserve discussion category when publishing releases (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/765">#765</a>)</li>
<li>See full diff in <a
href="26e8ad27a0...153bb8e044">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=softprops/action-gh-release&package-manager=github_actions&previous-version=2.6.0&new-version=2.6.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-03-16 17:14:11 -07:00
dependabot[bot] 67dcac02f9
build(deps): bump softprops/action-gh-release from 2.6.0 to 2.6.1
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](26e8ad27a0...153bb8e044)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-17 00:12:48 +00:00
Jeffrey C. Ollie f6e92b6895
gtk: refactor application id and resource path (#11580) 2026-03-16 18:43:35 -05:00
ghostty-vouch[bot] 6abed20fc8
Update VOUCHED list (#11581)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11557#issuecomment-4071331120)
from @mitchellh.

Unvouch: @mvanhorn

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-16 23:39:24 +00:00
Mitchell Hashimoto b18705c469
libghostty: expose terminal modes and DECRPM report encoding through the C API. (#11579)
Previously libghostty-vt had no way for C consumers to query, set, or
report on terminal modes. Callers that needed to respond to DECRPM
requests or inspect mode state had no public interface to do so.

This adds three layers of mode support to the C API:

- `GhosttyMode` — a 16-bit packed type with inline helpers to construct
and inspect mode tags, plus `GHOSTTY_MODE_*` macros for all supported
ANSI and DEC private modes.
- `ghostty_terminal_mode_get` / `ghostty_terminal_mode_set` — query and
set mode values on a terminal handle.
- `ghostty_mode_report_encode` — encode a DECRPM response sequence (`CSI
[?] Ps1 ; Ps2 $ y`) into a caller-provided buffer.

## Example

```c
#include <stdio.h>
#include <ghostty/vt.h>

int main() {
    char buf[32];
    size_t written = 0;

    // Query a terminal's cursor visibility and encode a DECRPM report
    GhosttyMode mode = GHOSTTY_MODE_CURSOR_VISIBLE;
    bool value = false;
    ghostty_terminal_mode_get(terminal, mode, &value);

    GhosttyModeReportState state = value
        ? GHOSTTY_MODE_REPORT_SET
        : GHOSTTY_MODE_REPORT_RESET;

    if (ghostty_mode_report_encode(mode, state, buf, sizeof(buf), &written)
            == GHOSTTY_SUCCESS) {
        // writes ESC[?25;1$y or ESC[?25;2$y
        fwrite(buf, 1, written, stdout);
    }
}
```
2026-03-16 16:34:48 -07:00
Jeffrey C. Ollie 8a40e37b86
gtk: refactor application id and resource path 2026-03-16 18:26:37 -05:00
Mitchell Hashimoto bfaab04468
vt: rename mode tag to mode 2026-03-16 16:15:38 -07:00
Mitchell Hashimoto a460743b2a
vt: add mode report encoding to C API
Add ghostty_mode_report_encode() which encodes a DECRPM response
sequence into a caller-provided buffer. The function takes a mode
tag, a report state integer, an output buffer, and writes the
appropriate CSI sequence (with ? prefix for DEC private modes).

The Zig-side ReportState is a non-exhaustive c_int enum that uses
std.meta.intToEnum for safe conversion to the internal type,
returning GHOSTTY_INVALID_VALUE on overflow. The C header exposes
a GhosttyModeReportState enum with named constants for the five
standard DECRPM state values.
2026-03-16 16:10:25 -07:00
Mitchell Hashimoto 1c03770e2b
vt: expose terminal modes to C API
Add modes.h with GhosttyModeTag (uint16_t) matching the Zig ModeTag
packed struct layout, along with inline helpers for constructing and
inspecting mode tags. Provide GHOSTTY_MODE_* macros for all 39
built-in modes (4 ANSI, 35 DEC), parenthesized for safety.

Add ghostty_terminal_mode_get and ghostty_terminal_mode_set to
terminal.h, both returning GhosttyResult so that null terminals
and unknown mode tags return GHOSTTY_INVALID_VALUE. The get function
writes its result through a bool out-parameter.

Add a note in the Zig mode entries reminding developers to update
modes.h when adding new modes.
2026-03-16 16:01:53 -07:00
Mitchell Hashimoto 25679f3ae7
vt: add C API header for terminal mode tags
Add modes.h with GhosttyModeTag, a uint16_t typedef matching the
Zig ModeTag packed struct layout (bits 0-14 for the mode value,
bit 15 for the ANSI flag). Three inline helper functions provide
construction and inspection: ghostty_mode_tag_new,
ghostty_mode_tag_value, and ghostty_mode_tag_ansi.
2026-03-16 15:48:26 -07:00
Mitchell Hashimoto 21eb30d9bc
terminal: extract DECRPM mode report encoding to terminal package (#11578)
This extracts our mode reporting from being hardcoded in termio to being
reusable in the existing `terminal.modes` namespace. The goal is to
expose this via the Zig API libghostty (done) and C API (to do later).
2026-03-16 15:32:03 -07:00
Mitchell Hashimoto d6b37ba38f
terminal: extract DECRPM mode report encoding to terminal package
This extracts our mode reporting from being hardcoded in termio
to being reusable in the existing `terminal.modes` namespace. The goal
is to expose this via the Zig API libghostty (done) and C API (to do
later).
2026-03-16 15:09:26 -07:00
Mitchell Hashimoto e90dbc9da6
vt: expose focus encoding in C and Zig APIs (#11577)
Add focus event encoding (CSI I / CSI O) to the libghostty-vt public
API, following the same patterns as key and mouse encoding.

The focus Event enum uses lib.Enum for C ABI compatibility. The C API
provides ghostty_focus_encode() which writes into a caller-provided
buffer and returns GHOSTTY_OUT_OF_SPACE with the required size when the
buffer is too small.

Also update key and mouse encoders to return GHOSTTY_OUT_OF_SPACE
instead of GHOSTTY_OUT_OF_MEMORY for buffer-too-small errors, reserving
OUT_OF_MEMORY for actual allocation failures. Update all corresponding
header documentation.
2026-03-16 15:02:03 -07:00
Mitchell Hashimoto bed9d92f04
vt: expose focus encoding in C and Zig APIs
Add focus event encoding (CSI I / CSI O) to the libghostty-vt public
API, following the same patterns as key and mouse encoding.

The focus Event enum uses lib.Enum for C ABI compatibility. The C API
provides ghostty_focus_encode() which writes into a caller-provided
buffer and returns GHOSTTY_OUT_OF_SPACE with the required size when
the buffer is too small.

Also update key and mouse encoders to return GHOSTTY_OUT_OF_SPACE
instead of GHOSTTY_OUT_OF_MEMORY for buffer-too-small errors,
reserving OUT_OF_MEMORY for actual allocation failures. Update all
corresponding header documentation.
2026-03-16 14:38:19 -07:00
Leah Amelia Chen 2318e18df3
gtk/wayland: refactor global handling (#11559) 2026-03-16 18:06:37 +00:00
ghostty-vouch[bot] c1326c57f9
Update VOUCHED list (#11572)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/10478#discussioncomment-16163586)
from @mitchellh.

Denounce: @highimpact-dev

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-16 17:25:02 +00:00
Leah Amelia Chen 8966d37985
gtk/wayland: refactor global handling
The way we originally handled globals gradually escalated into an unholy
mess of ad-hoc helper functions and special-case handlers, which proved
to be hard to scale. Using a type-erased EnumMap like this makes
everything *far* easier to work and reason with, I think.

Also nuked the `xdg_wm_dialog_v1` hack that was necessary to prevent
old versions of gtk4-layer-shell crashing. If by the time of 1.4's
release people are still using those versions, it's on them.
2026-03-17 01:14:59 +08:00
Mitchell Hashimoto a811b6074b
Lots of duplicate word typos + typo (#11539)
TL;DR: this description is (intentionally) nonsense but I ran
`\b(\w+)\s\1\b` over `src` and stole a singular typo fix from #11528.

Replacement of #11528 with 100% less slop and 99% less AI; I didn't feel
like saying no to free(ish) typo checking. Note that many of the fixes
there were outright incorrect (and clearly had no review from sentient
lifeforms, contrary to its—sorry, it's—description). A lot of extra
double words were caught with a handy `rg --pcre2 '\b(\w+)\s+\1\b' src`;
you could say this PR was “ripgrep-assisted” the way that one was
“AI-assisted”. Rather ironic since that PR also claims to have used grep
via Claude Code, but missed a lot of them.

The its → it's changes from that PR were elided; I decided to run a `rg
"\bit'?s\b" src`, but someone REALLY likes their its, so I reverted my
changes as there were an extremely large number of changes (probably a
hundred files with multiple hundred cases). The only other change was
“baout” → “about”.

# AI Usage

Claude Code was used by proxy for finding baout. Claude Code was used by
proxy for realizing that the correct spelling is about. Claude Code was
not used for fixing it. Oh my god it was so difficult to fix, the
original PR had it so easy. I had to type out the file name (fish's AI
sorry I mean autocomplete helped though) and like, type /baout, press R,
press ab, then save and exit. This is so difficult you know we should
use an AI for this, like this is so hard I don't know how people manage.

All changes were verified by me: I consulted the dictionary to delve
into double-checkment of “in existence; being in evidence; apparent.”
Uhhh insert assorted other AI impersonation here maybe? THE LLM IN ME
WANTS TO ESCAPE PLEASE HELP
2026-03-16 09:52:35 -07:00
Mitchell Hashimoto cce205d01b
cli: add +explain-config (#11546)
This is a new CLI action that prints an option or keybind's help
documentation to stdout.

    ghostty +explain-config font-size
    ghostty +explain-config copy_to_clipboard
    ghostty +explain-config --option=font-size
    ghostty +explain-config --keybind=copy_to_clipboard

The --option and --keybind flags perform a specific lookup. A string
passed as a positional argument attempts to look up the name first as an
option and then as a keybind.

Our vim plugin uses this with &keywordprg, which allows you to look up
the documentation for the config option or keybind under the cursor (K).
2026-03-16 09:51:48 -07:00
Mitchell Hashimoto 03806dad3a
ci: skip milestone workflow for bot-authored PRs (#11570)
The milestone action currently runs for all merged pull_request_target
close events, including PRs opened by bots such as dependabot and
ghostty-vouch. That causes milestone binding to run on automated PRs
that should be ignored.

Gate the update-milestone job so pull request events only run when the
author is not a bot, while still allowing closed-issue events to run.
This preserves existing issue milestone behavior and prevents bot PRs
from triggering the workflow.
2026-03-16 09:35:37 -07:00
Mitchell Hashimoto 2d2d913f80
ci: skip milestone workflow for bot-authored PRs
The milestone action currently runs for all merged pull_request_target
close events, including PRs opened by bots such as dependabot and
ghostty-vouch. That causes milestone binding to run on automated PRs
that should be ignored.

Gate the update-milestone job so pull request events only run when the
author is not a bot, while still allowing closed-issue events to run.
This preserves existing issue milestone behavior and prevents bot PRs
from triggering the workflow.
2026-03-16 09:34:37 -07:00
Jon Parise 925992abd9
shell-integration: fix ssh-env SetEnv clobbering user SSH config (#11518)
## Problem

Ghostty's `ssh-env` shell integration uses `-o "SetEnv
COLORTERM=truecolor"` when wrapping SSH commands. OpenSSH treats
command-line `-o SetEnv` options as **replacements** for all `SetEnv`
entries in `~/.ssh/config`, not additions. This silently drops any
user-configured `SetEnv` variables.

For example, a user with this in their SSH config:
```
Host myserver
  SetEnv MY_VAR=hello
```
...would find `MY_VAR` empty after SSHing through Ghostty with `ssh-env`
enabled.

Reference: https://github.com/ghostty-org/ghostty/discussions/10871

## Fix

Replace `-o "SetEnv COLORTERM=truecolor"` with the additive pattern: set
`COLORTERM=truecolor` locally before the SSH call and forward it via
`SendEnv`.

`SendEnv` is additive — it does not clobber `SetEnv` entries in
`~/.ssh/config`.

**Trade-off:** `SendEnv` requires `AcceptEnv COLORTERM` on the remote
server (unlike `SetEnv`). But this was already the case for
`TERM_PROGRAM`/`TERM_PROGRAM_VERSION`, so it's a consistent and
acceptable approach.

## Changes

All 5 shell integration files updated with the same pattern:

- `SetEnv COLORTERM=truecolor` option removed
- `COLORTERM` added to the existing `SendEnv` option
- `COLORTERM=truecolor` set as a local env var on the execute line (so
`SendEnv` has something to forward)

## Test plan

- [ ] Enable `ssh-env` in Ghostty config: `shell-integration-features =
ssh-env`
- [ ] Add `SetEnv MY_VAR=hello` under a host in `~/.ssh/config` and
`AcceptEnv MY_VAR` in `/etc/ssh/sshd_config` on the remote
- [ ] SSH to that host — `echo $MY_VAR` should return `hello` (was empty
before this fix)
- [ ] `echo $COLORTERM` returns `truecolor` (requires `AcceptEnv
COLORTERM`)
- [ ] `echo $TERM_PROGRAM` still propagates (same `AcceptEnv`
requirement as before)
2026-03-16 08:01:33 -04:00
Leah Amelia Chen a3fe5974e8
Add missing plural forms for Chinese (#11562) 2026-03-16 10:00:27 +00:00
Kat 3b60ef3b34
Add missing plural forms (or, the lack thereof) for Chinese. 2026-03-16 20:43:40 +11:00
Waqas Younas 978abdeebc Fix tmux control block terminator parsing 2026-03-16 12:46:54 +05:00
Leah Amelia Chen 600f59ae31
gtk: implement quick-terminal-screen for Linux/Wayland (#11117) 2026-03-16 06:30:02 +00:00
ghostty-vouch[bot] 44f403bfe1
Update VOUCHED list (#11556)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11536#discussioncomment-16152546)
from @pluiedev.

Vouch: @mvanhorn

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-16 05:42:48 +00:00
Mitchell Hashimoto 0f2eaed68c
libghostty: add mouse encoding Zig + C API (#11553)
This adds a Zig and C API for mouse event encoding. 

With these APIs in place, users can now create mouse events, configure a
mouse encoder with tracking mode, output format, and terminal size, and
encode those events into terminal escape sequences. All standard mouse
protocols are supported: X10, UTF-8, SGR, URxvt, and SGR-Pixels.

## Example

```c
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <ghostty/vt.h>

int main() {
  GhosttyMouseEncoder encoder;
  GhosttyResult result = ghostty_mouse_encoder_new(NULL, &encoder);
  assert(result == GHOSTTY_SUCCESS);

  // Set tracking mode to normal (button press/release)
  ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_EVENT,
                               &(GhosttyMouseTrackingMode){GHOSTTY_MOUSE_TRACKING_NORMAL});

  // Set output format to SGR
  ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_FORMAT,
                               &(GhosttyMouseFormat){GHOSTTY_MOUSE_FORMAT_SGR});

  // Set terminal geometry so the encoder can map pixel positions to cells
  ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_SIZE,
                               &(GhosttyMouseEncoderSize){
                                   .size = sizeof(GhosttyMouseEncoderSize),
                                   .screen_width = 800, .screen_height = 600,
                                   .cell_width = 10, .cell_height = 20,
                               });

  // Create mouse event: left button press at pixel position (50, 40)
  GhosttyMouseEvent event;
  result = ghostty_mouse_event_new(NULL, &event);
  assert(result == GHOSTTY_SUCCESS);
  ghostty_mouse_event_set_action(event, GHOSTTY_MOUSE_ACTION_PRESS);
  ghostty_mouse_event_set_button(event, GHOSTTY_MOUSE_BUTTON_LEFT);
  ghostty_mouse_event_set_position(event, (GhosttyMousePosition){.x = 50.0f, .y = 40.0f});

  // Encode the mouse event
  char buf[128];
  size_t written = 0;
  result = ghostty_mouse_encoder_encode(encoder, event, buf, sizeof(buf), &written);
  assert(result == GHOSTTY_SUCCESS);

  fwrite(buf, 1, written, stdout);

  ghostty_mouse_event_free(event);
  ghostty_mouse_encoder_free(encoder);
  return 0;
}
```

## New APIs

| Function | Description |
|----------|-------------|
| `ghostty_mouse_event_new` | Create a new mouse event instance |
| `ghostty_mouse_event_free` | Free a mouse event instance |
| `ghostty_mouse_event_set_action` | Set the event action (press,
release, motion) |
| `ghostty_mouse_event_get_action` | Get the event action |
| `ghostty_mouse_event_set_button` | Set the event button |
| `ghostty_mouse_event_clear_button` | Clear the event button (for
motion events) |
| `ghostty_mouse_event_get_button` | Get the event button (returns
whether one is set) |
| `ghostty_mouse_event_set_mods` | Set keyboard modifiers held during
the event |
| `ghostty_mouse_event_get_mods` | Get keyboard modifiers held during
the event |
| `ghostty_mouse_event_set_position` | Set position in surface-space
pixels |
| `ghostty_mouse_event_get_position` | Get position in surface-space
pixels |
| `ghostty_mouse_encoder_new` | Create a new mouse encoder instance |
| `ghostty_mouse_encoder_free` | Free a mouse encoder instance |
| `ghostty_mouse_encoder_setopt` | Set an encoder option (tracking mode,
format, size, etc.) |
| `ghostty_mouse_encoder_setopt_from_terminal` | Sync encoder options
from a terminal's current state |
| `ghostty_mouse_encoder_reset` | Reset internal encoder state (motion
deduplication) |
| `ghostty_mouse_encoder_encode` | Encode a mouse event into a terminal
escape sequence |
2026-03-15 20:26:56 -07:00
Mitchell Hashimoto de87456a9b
lib/vt: export mouse encoding API
Export mouse_encode types and functions through the lib_vt public
input API, mirroring the existing key encoding exports. This adds
MouseAction, MouseButton, MouseEncodeOptions, MouseEncodeEvent,
and encodeMouse so that consumers of the Zig module can encode
mouse events without reaching into internal packages.
2026-03-15 20:16:00 -07:00
Mitchell Hashimoto 33b05b9876
example: add C mouse encoding example
Add a new c-vt-mouse-encode example that demonstrates how to use the
mouse encoder C API. The example creates a mouse encoder configured
with SGR format and normal tracking mode, sets up terminal geometry
for pixel-to-cell coordinate mapping, and encodes a left button press
event into a terminal escape sequence.

Mirrors the structure of the existing c-vt-key-encode example. Also
adds the corresponding @example doxygen reference in vt.h.
2026-03-15 20:14:07 -07:00
Mitchell Hashimoto 9b35c2bb65
vt: add mouse encoding C API
Expose the internal mouse encoding functionality through the C API,
following the same pattern as the existing key encoding API. This
allows external consumers of libvt to encode mouse events into
terminal escape sequences (X10, UTF-8, SGR, URxvt, SGR-Pixels).

The API is split into two opaque handle types: GhosttyMouseEvent
for building normalized mouse events (action, button, modifiers,
position) and GhosttyMouseEncoder for converting those events into
escape sequences. The encoder is configured via a setopt interface
supporting tracking mode, output format, renderer geometry, button
state, and optional motion deduplication by last cell.

Encoder state can also be bulk-configured from a terminal handle
via ghostty_mouse_encoder_setopt_from_terminal. Failed encodes due
to insufficient buffer space report the required size without
mutating deduplication state.
2026-03-15 20:09:54 -07:00
Mitchell Hashimoto 79e023b65e
terminal,renderer: convert structs to extern
Convert Coordinate in terminal/point.zig and CellSize, ScreenSize,
GridSize, and Padding in renderer/size.zig to extern structs. All
fields are already extern-compatible types, so this gives them a
guaranteed C ABI layout with no functional change.
2026-03-15 19:39:17 -07:00
Mitchell Hashimoto 37efac99b0
terminal/mouse: convert Event and Format to lib.Enum
Convert the Event and Format enums from fixed-size Zig enums to
lib.Enum so they are C ABI compatible when targeting C. The motion
method on Event becomes a free function eventIsMotion since lib.Enum
types cannot have declarations.
2026-03-15 19:35:54 -07:00
Jon Parise 9783f6c79c cli: tests for +explain-config explain functions 2026-03-15 21:04:35 -04:00
Jon Parise cef1f19d24 cli: add +explain-config
This is a new CLI action that prints an option or keybind's help
documentation to stdout.

    ghostty +explain-config font-size
    ghostty +explain-config copy_to_clipboard
    ghostty +explain-config --option=font-size
    ghostty +explain-config --keybind=copy_to_clipboard

The --option and --keybind flags perform a specific lookup. A string
passed as a positional argument attempts to look up the name first as an
option and then as a keybind.

Our vim plugin uses this with &keywordprg, which allows you to look up
the documentation for the config option or keybind under the cursor (K).
2026-03-15 20:58:43 -04:00
Kat 41c7321e94
Add missing plural forms (#11541)
Supersedes #11529; I did not use their plural forms because I trust
ctrl+c more than Claude Code.

`mk` and `zh_*` are still missing theirs, but neither [gettext's table]
nor the [documentation it copied from] list them. That PR has them too,
with values magicked from… somewhere? The [data they linked] is
illegible to me.

[gettext's table]:
https://cgit.git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/plural-table.c?id=dbf9d71e0c4707ca1b14359256b3dcccecb8e837
[documentation it copied from]:
https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
[data they linked]:
https://www.unicode.org/cldr/charts/48/supplemental/language_plural_rules.html
2026-03-16 00:20:03 +00:00
Mitchell Hashimoto 36986f0374
build(deps): bump dorny/paths-filter from 4.0.0 to 4.0.1 (#11545)
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from
4.0.0 to 4.0.1.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fbd0ab8f3e"><code>fbd0ab8</code></a>
feat: add merge_group event support</li>
<li><a
href="efb1da7ce8"><code>efb1da7</code></a>
feat: add dist/ freshness check to PR workflow</li>
<li><a
href="d8f7b061b2"><code>d8f7b06</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/302">#302</a>
from dorny/issue-299</li>
<li><a
href="addbc147a9"><code>addbc14</code></a>
Update README for v4</li>
<li>See full diff in <a
href="9d7afb8d21...fbd0ab8f3e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dorny/paths-filter&package-manager=github_actions&previous-version=4.0.0&new-version=4.0.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-03-15 17:18:36 -07:00
Mitchell Hashimoto 671301c807
build(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.0 (#11544)
Bumps
[softprops/action-gh-release](https://github.com/softprops/action-gh-release)
from 2.5.0 to 2.6.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>feat: support previous_tag for generate_release_notes by <a
href="https://github.com/pocesar"><code>@​pocesar</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/372">softprops/action-gh-release#372</a></li>
</ul>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: recover concurrent asset metadata 404s by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/760">softprops/action-gh-release#760</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify reused draft release behavior by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/759">softprops/action-gh-release#759</a></li>
<li>docs: clarify working_directory input by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/761">softprops/action-gh-release#761</a></li>
<li>ci: verify dist bundle freshness by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/762">softprops/action-gh-release#762</a></li>
<li>fix: clarify immutable prerelease uploads by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/763">softprops/action-gh-release#763</a></li>
</ul>
<h2>v2.5.3</h2>
<!-- raw HTML omitted -->
<p><code>2.5.3</code> is a patch release focused on the remaining
path-handling and release-selection bugs uncovered after
<code>2.5.2</code>.
It fixes
<code>[#639](https://github.com/softprops/action-gh-release/issues/639)</code>,
<code>[#571](https://github.com/softprops/action-gh-release/issues/571)</code>,
<code>[#280](https://github.com/softprops/action-gh-release/issues/280)</code>,
<code>[#614](https://github.com/softprops/action-gh-release/issues/614)</code>,
<code>[#311](https://github.com/softprops/action-gh-release/issues/311)</code>,
<code>[#403](https://github.com/softprops/action-gh-release/issues/403)</code>,
and
<code>[#368](https://github.com/softprops/action-gh-release/issues/368)</code>.
It also adds documentation clarifications for
<code>[#541](https://github.com/softprops/action-gh-release/issues/541)</code>,
<code>[#645](https://github.com/softprops/action-gh-release/issues/645)</code>,
<code>[#542](https://github.com/softprops/action-gh-release/issues/542)</code>,
<code>[#393](https://github.com/softprops/action-gh-release/issues/393)</code>,
and
<code>[#411](https://github.com/softprops/action-gh-release/issues/411)</code>,
where the current behavior is either usage-sensitive or constrained by
GitHub platform limits rather than an action-side runtime bug.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: prefer token input over GITHUB_TOKEN by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/751">softprops/action-gh-release#751</a></li>
<li>fix: clean up duplicate drafts after canonicalization by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/753">softprops/action-gh-release#753</a></li>
<li>fix: support Windows-style file globs by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/754">softprops/action-gh-release#754</a></li>
<li>fix: normalize refs-tag inputs by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/755">softprops/action-gh-release#755</a></li>
<li>fix: expand tilde file paths by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/756">softprops/action-gh-release#756</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify token precedence by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/752">softprops/action-gh-release#752</a></li>
<li>docs: clarify GitHub release limits by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/758">softprops/action-gh-release#758</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>feat: support previous_tag for generate_release_notes by <a
href="https://github.com/pocesar"><code>@​pocesar</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/372">softprops/action-gh-release#372</a></li>
</ul>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: recover concurrent asset metadata 404s by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/760">softprops/action-gh-release#760</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify reused draft release behavior by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/759">softprops/action-gh-release#759</a></li>
<li>docs: clarify working_directory input by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/761">softprops/action-gh-release#761</a></li>
<li>ci: verify dist bundle freshness by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/762">softprops/action-gh-release#762</a></li>
<li>fix: clarify immutable prerelease uploads by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/763">softprops/action-gh-release#763</a></li>
</ul>
<h2>2.5.3</h2>
<p><code>2.5.3</code> is a patch release focused on the remaining
path-handling and release-selection bugs uncovered after
<code>2.5.2</code>.
It fixes
<code>[#639](https://github.com/softprops/action-gh-release/issues/639)</code>,
<code>[#571](https://github.com/softprops/action-gh-release/issues/571)</code>,
<code>[#280](https://github.com/softprops/action-gh-release/issues/280)</code>,
<code>[#614](https://github.com/softprops/action-gh-release/issues/614)</code>,
<code>[#311](https://github.com/softprops/action-gh-release/issues/311)</code>,
<code>[#403](https://github.com/softprops/action-gh-release/issues/403)</code>,
and
<code>[#368](https://github.com/softprops/action-gh-release/issues/368)</code>.
It also adds documentation clarifications for
<code>[#541](https://github.com/softprops/action-gh-release/issues/541)</code>,
<code>[#645](https://github.com/softprops/action-gh-release/issues/645)</code>,
<code>[#542](https://github.com/softprops/action-gh-release/issues/542)</code>,
<code>[#393](https://github.com/softprops/action-gh-release/issues/393)</code>,
and
<code>[#411](https://github.com/softprops/action-gh-release/issues/411)</code>,
where the current behavior is either usage-sensitive or constrained by
GitHub platform limits rather than an action-side runtime bug.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: prefer token input over GITHUB_TOKEN by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/751">softprops/action-gh-release#751</a></li>
<li>fix: clean up duplicate drafts after canonicalization by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/753">softprops/action-gh-release#753</a></li>
<li>fix: support Windows-style file globs by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/754">softprops/action-gh-release#754</a></li>
<li>fix: normalize refs-tag inputs by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/755">softprops/action-gh-release#755</a></li>
<li>fix: expand tilde file paths by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/756">softprops/action-gh-release#756</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify token precedence by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/752">softprops/action-gh-release#752</a></li>
<li>docs: clarify GitHub release limits by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/758">softprops/action-gh-release#758</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="26e8ad27a0"><code>26e8ad2</code></a>
release 2.6.0</li>
<li><a
href="b959f31e96"><code>b959f31</code></a>
fix: clarify immutable prerelease uploads (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/763">#763</a>)</li>
<li><a
href="8a8510e3a0"><code>8a8510e</code></a>
ci: verify dist bundle freshness (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/762">#762</a>)</li>
<li><a
href="438c15ddf5"><code>438c15d</code></a>
docs: clarify working_directory input (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/761">#761</a>)</li>
<li><a
href="6ca3b5d96e"><code>6ca3b5d</code></a>
fix: recover concurrent asset metadata 404s (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/760">#760</a>)</li>
<li><a
href="11f917660b"><code>11f9176</code></a>
chore: add RELEASE.md</li>
<li><a
href="1f3f350167"><code>1f3f350</code></a>
feat: add AGENTS.md</li>
<li><a
href="37819cb191"><code>37819cb</code></a>
docs: clarify reused draft release behavior (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/759">#759</a>)</li>
<li><a
href="9312864490"><code>9312864</code></a>
feat: support previous_tag for generate_release_notes (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/372">#372</a>)</li>
<li><a
href="1853d73993"><code>1853d73</code></a>
release 2.5.3</li>
<li>Additional commits viewable in <a
href="a06a81a03e...26e8ad27a0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=softprops/action-gh-release&package-manager=github_actions&previous-version=2.5.0&new-version=2.6.0)](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-03-15 17:18:27 -07:00
Mitchell Hashimoto f8e8a3fd71
build(deps): bump actions/create-github-app-token from 2.2.1 to 3.0.0 (#11543)
Bumps
[actions/create-github-app-token](https://github.com/actions/create-github-app-token)
from 2.2.1 to 3.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<h1><a
href="https://github.com/actions/create-github-app-token/compare/v2.2.2...v3.0.0">3.0.0</a>
(2026-03-14)</h1>
<ul>
<li>feat!: node 24 support (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/275">#275</a>)
(<a
href="2e564a0bb8">2e564a0</a>)</li>
<li>fix!: require <code>NODE_USE_ENV_PROXY</code> for proxy support (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/342">#342</a>)
(<a
href="4451bcbc13">4451bcb</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>remove custom proxy handling (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/143">#143</a>)
(<a
href="dce0ab05f3">dce0ab0</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li>Custom proxy handling has been removed. If you use HTTP_PROXY or
HTTPS_PROXY, you must now also set NODE_USE_ENV_PROXY=1 on the action
step.</li>
<li>Requires <a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Actions
Runner v2.327.1</a> or later if you are using a self-hosted runner.</li>
</ul>
<h2>v3.0.0-beta.6</h2>
<h1><a
href="https://github.com/actions/create-github-app-token/compare/v3.0.0-beta.5...v3.0.0-beta.6">3.0.0-beta.6</a>
(2026-03-13)</h1>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@​actions/core</code> from 1.11.1
to 3.0.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/337">#337</a>)
(<a
href="b04413352d">b044133</a>)</li>
<li><strong>deps:</strong> bump minimatch from 9.0.5 to 9.0.9 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/335">#335</a>)
(<a
href="5cbc65624c">5cbc656</a>)</li>
<li><strong>deps:</strong> bump the production-dependencies group with 4
updates (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/336">#336</a>)
(<a
href="6bda5bc141">6bda5bc</a>)</li>
<li><strong>deps:</strong> bump undici from 7.16.0 to 7.18.2 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/323">#323</a>)
(<a
href="b4f638f48e">b4f638f</a>)</li>
</ul>
<h2>v3.0.0-beta.5</h2>
<h1><a
href="https://github.com/actions/create-github-app-token/compare/v3.0.0-beta.4...v3.0.0-beta.5">3.0.0-beta.5</a>
(2026-03-13)</h1>
<ul>
<li>fix!: require <code>NODE_USE_ENV_PROXY</code> for proxy support (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/342">#342</a>)
(<a
href="d53a1cdfde">d53a1cd</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li>Custom proxy handling has been removed. If you use HTTP_PROXY or
HTTPS_PROXY, you must now also set NODE_USE_ENV_PROXY=1 on the action
step.</li>
</ul>
<h2>v3.0.0-beta.4</h2>
<h1><a
href="https://github.com/actions/create-github-app-token/compare/v3.0.0-beta.3...v3.0.0-beta.4">3.0.0-beta.4</a>
(2026-03-13)</h1>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@​octokit/auth-app</code> from
7.2.1 to 8.0.1 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/257">#257</a>)
(<a
href="bef1eaf1c0">bef1eaf</a>)</li>
<li><strong>deps:</strong> bump <code>@​octokit/request</code> from
9.2.3 to 10.0.2 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/256">#256</a>)
(<a
href="5d7307be63">5d7307b</a>)</li>
<li><strong>deps:</strong> bump glob from 10.4.5 to 10.5.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/305">#305</a>)
(<a
href="5480f4325a">5480f43</a>)</li>
<li><strong>deps:</strong> bump p-retry from 6.2.1 to 7.1.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/294">#294</a>)
(<a
href="dce3be8b28">dce3be8</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f8d387b68d"><code>f8d387b</code></a>
build(release): 3.0.0 [skip ci]</li>
<li><a
href="d2129bd463"><code>d2129bd</code></a>
style: remove extra blank line in release workflow</li>
<li><a
href="77b94efc3e"><code>77b94ef</code></a>
build: refresh generated artifacts</li>
<li><a
href="3ab4c66898"><code>3ab4c66</code></a>
chore: move undici to devDependencies</li>
<li><a
href="739cf66feb"><code>739cf66</code></a>
docs: update README action versions</li>
<li><a
href="db40289976"><code>db40289</code></a>
build(deps): bump actions versions in test.yml</li>
<li><a
href="496a7ac4eb"><code>496a7ac</code></a>
test: migrate from AVA to Node.js native test runner (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/346">#346</a>)</li>
<li><a
href="3870dc3051"><code>3870dc3</code></a>
Rename end-to-end proxy job in test workflow</li>
<li><a
href="4451bcbc13"><code>4451bcb</code></a>
fix!: require <code>NODE_USE_ENV_PROXY</code> for proxy support (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/342">#342</a>)</li>
<li><a
href="dce0ab05f3"><code>dce0ab0</code></a>
fix: remove custom proxy handling (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/143">#143</a>)</li>
<li>Additional commits viewable in <a
href="29824e69f5...f8d387b68d">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=2.2.1&new-version=3.0.0)](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-03-15 17:18:08 -07:00
dependabot[bot] 7f81e12dc0
build(deps): bump dorny/paths-filter from 4.0.0 to 4.0.1
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/dorny/paths-filter/releases)
- [Changelog](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
- [Commits](9d7afb8d21...fbd0ab8f3e)

---
updated-dependencies:
- dependency-name: dorny/paths-filter
  dependency-version: 4.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 00:17:24 +00:00
dependabot[bot] d08c8e0dbc
build(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](a06a81a03e...26e8ad27a0)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 00:17:20 +00:00
dependabot[bot] 0fb1519cf2
build(deps): bump actions/create-github-app-token from 2.2.1 to 3.0.0
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.2.1 to 3.0.0.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](29824e69f5...f8d387b68d)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 00:17:13 +00:00
ghostty-vouch[bot] a945115d2f
Sync CODEOWNERS vouch list (#11542)
Sync CODEOWNERS owners with vouch list.

## Added Users

- @alosarjos
- @anhthang
- @AnmiTaliDev
- @crayxt
- @MicaelJarniac

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-16 00:03:41 +00:00
Kat ef1560ce50
Add missing plural forms.
mk and zh_* are still missing theirs, but neither gettext's table [1]
nor the documentation it copied from [2] list them.

[1]: https://cgit.git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/plural-table.c?id=dbf9d71e0c4707ca1b14359256b3dcccecb8e837
[2]: https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
2026-03-16 10:49:55 +11:00
Mitchell Hashimoto f9f92f2e0f
terminal: consolidate mouse types into mouse.zig
Move MouseEvent and MouseFormat out of Terminal.zig and MouseShape out
of mouse_shape.zig into a new mouse.zig file. The types are named
without the Mouse prefix inside the module (Event, Format, Shape) and
re-exported with the prefix from terminal/main.zig for external use.

Update all call sites (mouse_encode.zig, surface_mouse.zig, stream.zig)
to import through terminal/main.zig or directly from mouse.zig. Remove
the now-unused mouse_shape.zig.
2026-03-15 15:48:36 -07:00
ghostty-vouch[bot] a2b2b883e8
Update VOUCHED list (#11540)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11518#issuecomment-4064084617)
from @jparise.

Vouch: @j0hnm4r5

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-15 22:47:41 +00:00
Mitchell Hashimoto f1fd21fd76
input: extract mouse encoding to a pure, testable file (#11538)
Move mouse event encoding logic from Surface.zig into a new
input/mouse_encode.zig file.

The new file encapsulates event filtering (shouldReport), button code
computation, viewport bounds checking, motion deduplication, and all
five wire formats (X10, UTF-8, SGR, urxvt, SGR-pixels). This makes the
encoding independently testable and adds unit tests covering each format
and edge case.

Additionally, Surface `mouseReport` can no longer fail, since the only
failure mode is no buffer space which should be impossible. Updated the
signature to remove the error set.
2026-03-15 15:41:56 -07:00
Mitchell Hashimoto ac5e57ce67
input: extract mouse encoding to a pure, testable file
Move mouse event encoding logic from Surface.zig into a new
input/mouse_encode.zig file.

The new file encapsulates event filtering (shouldReport),
button code computation, viewport bounds checking, motion
deduplication, and all five wire formats (X10, UTF-8, SGR,
urxvt, SGR-pixels). This makes the encoding independently
testable and adds unit tests covering each format and edge
case.

Additionally, Surface `mouseReport` can no longer fail, since the only
failure mode is no buffer space which should be impossible. Updated
the signature to remove the error set.
2026-03-15 15:37:54 -07:00
Kat 6fabf775bb
Lots of duplicate word typos + typo. 2026-03-16 09:19:09 +11:00
ghostty-vouch[bot] 57428f33c6
Update VOUCHED list (#11533)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11237#discussioncomment-16143212)
from @mitchellh.

Vouch: @cadebrown

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-15 16:07:17 +00:00
ghostty-vouch[bot] 33263dbe6f
Update VOUCHED list (#11532)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11250#discussioncomment-16143210)
from @mitchellh.

Vouch: @PowerUser64

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-15 16:06:47 +00:00
ghostty-vouch[bot] 0e272bfa10
Update VOUCHED list (#11531)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11041#discussioncomment-16143204)
from @mitchellh.

Vouch: @davidsanchez222

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-15 16:06:03 +00:00
Mitchell Hashimoto a7514d389b
vt: add setopt_from_terminal to C API (#11524)
Expose the key encoder Options.fromTerminal function to the C API as
ghostty_key_encoder_setopt_from_terminal. This lets C callers sync all
terminal-derived encoding options (cursor key application mode, keypad
mode, alt escape prefix, modifyOtherKeys, and Kitty flags) in a single
call instead of setting each option individually.
2026-03-15 07:24:34 -07:00
Mitchell Hashimoto 943d3d2e89
vt: add setopt_from_terminal to C API
Expose the key encoder Options.fromTerminal function to the C API as
ghostty_key_encoder_setopt_from_terminal. This lets C callers sync all
terminal-derived encoding options (cursor key application mode, keypad
mode, alt escape prefix, modifyOtherKeys, and Kitty flags) in a single
call instead of setting each option individually.
2026-03-15 07:05:07 -07:00
John Mars 69554f414c
shell-integration: fix ssh-env SetEnv clobbering user SSH config 2026-03-15 01:50:32 -04:00
Mitchell Hashimoto c9236558b1
config: add `equal` option to `window-padding-balance` (#11491)
Change `window-padding-balance` from `bool` to an enum with three
values:

- `false` - no balancing (default, unchanged)
- `true` - balance with vshift that caps top padding and shifts excess
to bottom (existing behavior, unchanged)
- `equal` - balance whitespace equally on all four sides

This gives users who prefer truly equal padding a way to opt in without
changing the default behavior.
2026-03-14 22:04:23 -07:00
Jaeseok Lee 86d9a04ece
config: add `equal` option to `window-padding-balance`
Change `window-padding-balance` from `bool` to an enum with three
values:

- `false` - no balancing (default, unchanged)
- `true` - balance with vshift that caps top padding and shifts excess
  to bottom (existing behavior, unchanged)
- `equal` - balance whitespace equally on all four sides

This gives users who prefer truly equal padding a way to opt in without
changing the default behavior.
2026-03-15 13:50:21 +09:00
Mitchell Hashimoto 952fbce0e5
libghostty: add initial C API for terminal, formatter (#11506)
This adds an initial C API for terminals and formatting. There is a new
example that shows how to use this.

With these APIs in place, users of the C API can now create a terminal,
pass raw VT streams to it, and dump the terminal viewport to various
formats. As noted in the docs, **the formatter API is not a rendering
API**, it isn't high performance enough for that. But it's a simpler API
to implement than the render state API so I started with that.

Both APIs are purposely fairly minimal, we're just setting the stage for
future functionality.

## Example

```c
#include <ghostty/vt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
  GhosttyTerminal term;
  GhosttyTerminalOptions opts = { .cols = 80, .rows = 24, .max_scrollback = 0 };
  ghostty_terminal_new(NULL, &term, opts);

  const char *input = "Hello, \033[1mBold\033[0m World!\r\nLine 2\r\n";
  ghostty_terminal_vt_write(term, (const uint8_t *)input, strlen(input));

  GhosttyFormatterTerminalOptions fmt = GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
  fmt.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
  fmt.trim = true;

  GhosttyFormatter fmtr;
  ghostty_formatter_terminal_new(NULL, &fmtr, term, fmt);

  uint8_t *buf;
  size_t len;
  ghostty_formatter_format_alloc(fmtr, NULL, &buf, &len);
  fwrite(buf, 1, len, stdout);

  free(buf);
  ghostty_formatter_free(fmtr);
  ghostty_terminal_free(term);
}
```

## New APIs

| Function | Description |
|----------|-------------|
| `ghostty_terminal_new` | Create a new terminal instance |
| `ghostty_terminal_free` | Free a terminal instance |
| `ghostty_terminal_reset` | Full reset of the terminal (RIS) |
| `ghostty_terminal_resize` | Resize the terminal to given dimensions |
| `ghostty_terminal_vt_write` | Write VT-encoded data to the terminal |
| `ghostty_terminal_scroll_viewport` | Scroll the terminal viewport |
| `ghostty_formatter_terminal_new` | Create a formatter for a terminal's
active screen |
| `ghostty_formatter_format_buf` | Format into a caller-provided buffer
|
| `ghostty_formatter_format_alloc` | Format into an allocated buffer |
| `ghostty_formatter_free` | Free a formatter instance |

## Future

- Obviously need to expose a lot more from the terminal:
  * Read current set modes
  * Read cursor information
  * Read screen information
  * etc...
- Need an optional callback system so that `vt_write` can invoke
callbacks for side effect sequences like clipboards, title setting,
responses, etc.
- `terminal.RenderState` C API so that people can build high performance
renderers on top of libghostty-vt

And so on...
2026-03-14 15:42:23 -07:00
Mitchell Hashimoto f730eed213
vt: fix missing formatter docs in doxygen 2026-03-14 15:42:00 -07:00
Mitchell Hashimoto 647f5adf55
terminal/formatter: safely cast discarding.count to usize
The Discarding writer count field is u64, but several call sites
pass it where a usize is expected. On wasm32-freestanding, usize is
32-bit, so this caused compilation errors.

Use std.math.cast instead of a bare @intCast so that overflow is
handled gracefully, returning WriteFailed rather than triggering
safety-checked undefined behavior at runtime.
2026-03-14 15:29:53 -07:00
Mitchell Hashimoto 4ad7d03c56
terminal/formatter: safely cast discarding.count to usize
The Discarding writer count field is u64, but appendNTimes expects
usize which is u32 on 32-bit targets like arm-linux-androideabi.
Use std.math.cast instead of @intCast to safely handle the
conversion, returning WriteFailed on overflow rather than risking
undefined behavior.
2026-03-14 15:22:21 -07:00
Mitchell Hashimoto 1e21ac1190
example: add c-vt-formatter example
Add an example showing how to use the ghostty-vt terminal and
formatter APIs from C. The example creates a terminal, writes
VT-encoded content with cursor movement and styling sequences,
then formats the screen contents as plain text using the formatter
API.
2026-03-14 15:12:10 -07:00
Mitchell Hashimoto 3c8feda118
vt: add format_alloc to C API formatter
Rename the existing format function to format_buf to clarify that it
writes into a caller-provided buffer. Add a new format_alloc variant
that allocates the output buffer internally using the provided
allocator (or the default if NULL). The caller receives the allocated
pointer and length and is responsible for freeing it.

This is useful for consumers that do not know the required buffer size
ahead of time and want to avoid the two-pass query-then-format pattern
needed with format_buf.
2026-03-14 14:59:41 -07:00
Mitchell Hashimoto 7c12d6e35d
agents: skill for writing commit messages 2026-03-14 14:59:02 -07:00
Mitchell Hashimoto a2d570b51e
vt: add sized struct pattern and types.h
Add a size field as the first member of formatter option structs
(TerminalOptions, TerminalOptions.Extra, ScreenOptions.Extra) for ABI
compatibility. This allows adding new fields without breaking callers
compiled against older versions of the struct.

Introduce include/ghostty/vt/types.h as the foundational header
containing GhosttyResult and the GHOSTTY_INIT_SIZED macro for
zero-initializing sized structs. Remove the separate result.h header,
moving its contents into types.h.
2026-03-14 14:42:50 -07:00
Mitchell Hashimoto 09d3ebd80d
vt: use explicit options structs 2026-03-14 14:30:36 -07:00
Mitchell Hashimoto 4e494ccd68
lib: lib.Struct can convert packed structs to extern structs 2026-03-14 14:21:00 -07:00
Mitchell Hashimoto b5fb7ecaaa
vt: wip formatter api 2026-03-14 14:16:44 -07:00
ghostty-vouch[bot] 1844a5f7ba
Update VOUCHED list (#11492)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11491#issuecomment-4060704311)
from @mitchellh.

Vouch: @devsunb

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-14 15:18:15 +00:00
ghostty-vouch[bot] 6368b00604
Update VOUCHED list (#11488)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11485#discussioncomment-16130186)
from @mitchellh.

Vouch: @jesusvazquez

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-14 13:13:09 +00:00
Mitchell Hashimoto 8e6bf829a7
terminal/osc: don't export context/semantic prompts to libvt yet 2026-03-13 20:06:33 -07:00
Mitchell Hashimoto 34acdfcc4e
vt: update terminal.h docs 2026-03-13 19:59:09 -07:00
Mitchell Hashimoto aa3e6e23a2
vt: ghostty_terminal_reset 2026-03-13 19:55:43 -07:00
Mitchell Hashimoto fe6e7fbc6b
vt: ghostty_terminal_resize 2026-03-13 19:54:20 -07:00
Mitchell Hashimoto 8b9afe35a7
vt: ghostty_terminal_scroll_viewport 2026-03-13 19:51:04 -07:00
Mitchell Hashimoto 18fdc15357
vt: ghostty_terminal_vt_write 2026-03-13 19:37:26 -07:00
Mitchell Hashimoto 302e68fd3d
vt: expose ghostty_terminal_new/free 2026-03-13 14:10:57 -07:00
Mitchell Hashimoto e75f8956c5
terminal: make stream processing infallible (#11468)
The terminal.Stream next/nextSlice functions can now no longer fail. All
prior failure modes were fully isolated in the handler `vt` callbacks.
As such, vt callbacks are now required to not return an error and handle
their own errors somehow.

Allowing streams to be fallible before was an incorrect design. It
caused problematic scenarios like in `nextSlice` early terminating
processing due to handler errors. This should not be possible.

There is no safe way to bubble up vt errors through the stream because
if nextSlice is called and multiple errors are returned, we can't
coalesce them. We could modify that to return a partial result but its
just more work for stream that is unnecessary. The handler can do all of
this.

This work was discovered due to cleanups to prepare for more C APIs.
Less errors make C APIs easier to implement! And, it helps clean up our
Zig, too.
2026-03-13 14:08:19 -07:00
Mitchell Hashimoto 2044e5030f
terminal: make stream processing infallible
The terminal.Stream next/nextSlice functions can now no longer fail.
All prior failure modes were fully isolated in the handler `vt`
callbacks. As such, vt callbacks are now required to not return an error
and handle their own errors somehow.

Allowing streams to be fallible before was an incorrect design. It
caused problematic scenarios like in `nextSlice` early terminating
processing due to handler errors. This should not be possible.

There is no safe way to bubble up vt errors through the stream because
if nextSlice is called and multiple errors are returned, we can't
coalesce them. We could modify that to return a partial result but its
just more work for stream that is unnecessary. The handler can do all of
this.

This work was discovered due to cleanups to prepare for more C APIs.
Less errors make C APIs easier to implement! And, it helps clean up our
Zig, too.
2026-03-13 13:56:14 -07:00
Mitchell Hashimoto 04fa71e237
Search wrap behavior (#11449)
Search wrapping has been highly requested.

some examples
https://github.com/ghostty-org/ghostty/discussions/11080
https://github.com/ghostty-org/ghostty/discussions/11440
https://github.com/ghostty-org/ghostty/discussions/11441
https://github.com/ghostty-org/ghostty/discussions/9762
https://github.com/ghostty-org/ghostty/discussions/9790

I also think it makes sense as its the default behavior in browsers (and
I assume other apps)

I tested where nothing is outputting and a loop where active was going
into history not anything where pages would start to get reused though

the following comment seems to me it should be safe to have wrap around
behavior but maybe there was something else I missed about the active +
history buffer on why that isn't true, testing basic cases it worked
just fine for me


https://github.com/ghostty-org/ghostty/blob/main/src/terminal/highlight.zig#L107-L111
2026-03-13 10:16:47 -07:00
Mitchell Hashimoto 5fa1a991d0
up to 1.3.2-dev 2026-03-13 09:22:46 -07:00
Mitchell Hashimoto 332b2aefc6
1.3.1 2026-03-13 09:00:30 -07:00
Mitchell Hashimoto f3ac604fff
macos: select tab applescript command should not activate application (#11459)
Related to #11457
2026-03-13 08:53:53 -07:00
Mitchell Hashimoto 4c4e83784c
macos: new tab applescript command should not activate application
Related to #11457
2026-03-13 08:49:22 -07:00
rhodes-b af84fdbea8 fix tests 2026-03-12 20:42:56 -05:00
rhodes-b 6f8ffecb89 working basic search wrapping 2026-03-12 20:42:55 -05:00
Jeffrey C. Ollie d4019fa484
build(deps): bump dorny/paths-filter from 3.0.2 to 4.0.0 (#11436)
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from
3.0.2 to 4.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/releases">dorny/paths-filter's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: update action runtime to node24 by <a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/294">dorny/paths-filter#294</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/294">dorny/paths-filter#294</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v3.0.3...v4.0.0">https://github.com/dorny/paths-filter/compare/v3.0.3...v4.0.0</a></p>
<h2>v3.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Add missing predicate-quantifier by <a
href="https://github.com/wardpeet"><code>@​wardpeet</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/279">dorny/paths-filter#279</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/wardpeet"><code>@​wardpeet</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/279">dorny/paths-filter#279</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v3...v3.0.3">https://github.com/dorny/paths-filter/compare/v3...v3.0.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md">dorny/paths-filter's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v4.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/294">Update
action runtime to node24</a></li>
</ul>
<h2>v3.0.3</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/279">Add
missing predicate-quantifier</a></li>
</ul>
<h2>v3.0.2</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/224">Add
config parameter for predicate quantifier</a></li>
</ul>
<h2>v3.0.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/133">Compare
base and ref when token is empty</a></li>
</ul>
<h2>v3.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/210">Update to
Node.js 20</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/215">Update
all dependencies</a></li>
</ul>
<h2>v2.11.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/167">Update
<code>@​actions/core</code> to v1.10.0 - Fixes warning about deprecated
set-output</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/168">Document
need for pull-requests: read permission</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/164">Updating
to actions/checkout@v3</a></li>
</ul>
<h2>v2.11.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/157">Set
list-files input parameter as not required</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/161">Update
Node.js</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/162">Fix
incorrect handling of Unicode characters in exec()</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/163">Use
Octokit pagination</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/160">Updates
real world links</a></li>
</ul>
<h2>v2.10.2</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/91">Fix
getLocalRef() returns wrong ref</a></li>
</ul>
<h2>v2.10.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/85">Improve
robustness of change detection</a></li>
</ul>
<h2>v2.10.0</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/82">Add
ref input parameter</a></li>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/83">Fix
change detection in PR when pullRequest.changed_files is
incorrect</a></li>
</ul>
<h2>v2.9.3</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/78">Fix
change detection when base is a tag</a></li>
</ul>
<h2>v2.9.2</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/75">Fix
fetching git history</a></li>
</ul>
<h2>v2.9.1</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/74">Fix
fetching git history + fallback to unshallow repo</a></li>
</ul>
<h2>v2.9.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9d7afb8d21"><code>9d7afb8</code></a>
Update CHANGELOG for v4.0.0</li>
<li><a
href="782470c5d9"><code>782470c</code></a>
Merge branch 'releases/v3'</li>
<li><a
href="d1c1ffe024"><code>d1c1ffe</code></a>
Update CHANGELOG for v3.0.3</li>
<li><a
href="ce10459c8b"><code>ce10459</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/294">#294</a>
from saschabratton/master</li>
<li><a
href="5f40380c54"><code>5f40380</code></a>
feat: update action runtime to node24</li>
<li><a
href="668c092af3"><code>668c092</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/279">#279</a>
from wardpeet/patch-1</li>
<li><a
href="209e61402d"><code>209e614</code></a>
Add missing predicate-quantifier</li>
<li>See full diff in <a
href="de90cc6fb3...9d7afb8d21">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dorny/paths-filter&package-manager=github_actions&previous-version=3.0.2&new-version=4.0.0)](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-03-12 19:32:30 -05:00
dependabot[bot] eccf960def
build(deps): bump dorny/paths-filter from 3.0.2 to 4.0.0
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from 3.0.2 to 4.0.0.
- [Release notes](https://github.com/dorny/paths-filter/releases)
- [Changelog](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
- [Commits](de90cc6fb3...9d7afb8d21)

---
updated-dependencies:
- dependency-name: dorny/paths-filter
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-13 00:13:53 +00:00
Ken VanDine 174aae359d
snap: Don't leak LD_LIBRARY_PATH set by the snap launcher (#11431)
LD_LIBRARY_PATH was being leaked which could break some apps launched
from ghostty, such as opening configuration in a text editor.
2026-03-12 16:46:28 -04:00
Ken VanDine 64331b8c35 snap: Don't leak LD_LIBRARY_PATH set by the snap launcher 2026-03-12 16:27:54 -04:00
Mitchell Hashimoto 597e8cf1c5
macOS: fix window position when dragging split into a new window (#11429) 2026-03-12 12:14:47 -07:00
Lukas 5c51603b0b
chore: make ci happy 2026-03-12 20:02:23 +01:00
Lukas 07bc888682
macOS: fix window position when dragging split into a new window 2026-03-12 19:54:41 +01:00
Lukas 3022aa05ea
macOS: add test cases for drag-split 2026-03-12 19:54:12 +01:00
Lukas d6d6fe4e58
macOS: update window cascading
Make it smaller and add comparisons between y values
2026-03-12 18:58:37 +01:00
Mitchell Hashimoto a91e747cb1
macOS: fix window cascading (#11426)
Added test case for cascading **without moving previous window**, #11161
will follow up for more accurate cascading after this.

Fixed window cascading after last pr, now we should perform cascading
**after** showing the window.
2026-03-12 10:44:37 -07:00
Lukas 5e3866381b
macOS: fix window cascading for the second window 2026-03-12 18:32:04 +01:00
Lukas ea262cdd34
macOS: fix window cascading for 3rd+ window 2026-03-12 18:32:04 +01:00
Lukas 77c2acf843
macOS: add test case for window cascading without moving the window 2026-03-12 18:32:04 +01:00
Mitchell Hashimoto 70685733c5
macOS: fix window position for the very first window (#11421)
Depends on https://github.com/ghostty-org/ghostty/pull/11417

Moved positioning part from `windowDidLoad` to `showWindow` to make new
users happy. Also deleted `initialFrame`, since we don't need it
anymore.
2026-03-12 09:09:30 -07:00
Lukas 08107d342a
macOS: we don't need initialFrame anymore 2026-03-12 15:42:29 +01:00
Lukas 4f849a1512
macOS: fix window position for the very first window 2026-03-12 15:42:29 +01:00
Lukas c399812036
macOS: add test case for positioning the very first window 2026-03-12 15:42:28 +01:00
Mitchell Hashimoto 8dde340f88
macOS: support injecting temporary defaults when testing (#11417) 2026-03-12 07:14:12 -07:00
Lukas d6dfaf28fe
macOS: support injecting temporary defaults when testing 2026-03-12 13:16:55 +01:00
Mitchell Hashimoto ab269e2c79
config: add progress-style option (#11289)
Adds progress-style config to control OSC 9;4 progress bar visibility.
Defaults to true, set false to hide.

Fixes #11241

AI Disclosure: Claude Code (Opus 4.6) used for codebase exploration,
code review, and testing assistance. All code written and reviewed by
hand.
2026-03-11 20:46:59 -07:00
Mitchell Hashimoto 35f4d18802
macos: only run key equivalents for Ghostty-owned menu items (#11403)
Fixes #11396

Track menu items populated from Ghostty keybind actions and only trigger
those from SurfaceView performKeyEquivalent. This avoids app-default
shortcuts such as Hide from pre-empting explicit keybinds.
2026-03-11 20:11:13 -07:00
Mitchell Hashimoto 8392255fd6
build(deps): bump actions/download-artifact from 8.0.0 to 8.0.1 (#11399)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 8.0.0 to 8.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Support for CJK characters in the artifact name by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/download-artifact/pull/471">actions/download-artifact#471</a></li>
<li>Add a regression test for artifact name + content-type mismatches by
<a href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a>
in <a
href="https://redirect.github.com/actions/download-artifact/pull/472">actions/download-artifact#472</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v8...v8.0.1">https://github.com/actions/download-artifact/compare/v8...v8.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3e5f45b2cf"><code>3e5f45b</code></a>
Add regression tests for CJK characters (<a
href="https://redirect.github.com/actions/download-artifact/issues/471">#471</a>)</li>
<li><a
href="e6d03f6737"><code>e6d03f6</code></a>
Add a regression test for artifact name + content-type mismatches (<a
href="https://redirect.github.com/actions/download-artifact/issues/472">#472</a>)</li>
<li>See full diff in <a
href="70fc10c6e5...3e5f45b2cf">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=8.0.0&new-version=8.0.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-03-11 20:00:58 -07:00
Mitchell Hashimoto 8093695055
macos: only run key equivalents for Ghostty-owned menu items
Fixes #11396

Track menu items populated from Ghostty keybind actions and only trigger
those from SurfaceView performKeyEquivalent. This avoids app-default
shortcuts such as Hide from pre-empting explicit keybinds.
2026-03-11 19:59:56 -07:00
Michal Olechowski 84d48d1c6a
config: add progress-style option
Add option to disable OSC 9;4 ConEmu progress bars via config.

Fixes #11241
2026-03-12 01:33:25 +01:00
dependabot[bot] 16ca9527e9
build(deps): bump actions/download-artifact from 8.0.0 to 8.0.1
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](70fc10c6e5...3e5f45b2cf)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-12 00:13:04 +00:00
ghostty-vouch[bot] 0f745b5673
Update VOUCHED list (#11389)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11388#discussioncomment-16087905)
from @jcollie.

Vouch: @wyounas

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-11 19:24:01 +00:00
Mitchell Hashimoto a0d3566872
macos: only show split grab handle when the mouse is near it (#11383)
Fixes #11379

For this pass, I made it a very simple "within 20%" (height-wise) of the
split handle down. There is no horizontal component. I want to find the
right balance between always visible (today mostly) to only visible on
direct hover, because I think it'll be too hard to discover on that far
right side.
2026-03-11 10:57:34 -07:00
Mitchell Hashimoto fe98f3884d
macos: only show split grab handle when the mouse is near it
Fixes #11379

For this pass, I made it a very simple "within 20%" (height-wise) of the
split handle. There is no horizontal component. I want to find the right
balance between always visible (today mostly) to only visible on direct
hover, because I think it'll be too hard to discover on that far right
side.
2026-03-11 10:48:09 -07:00
Mitchell Hashimoto 36c1450dc9
nix: bump zig-overlay version (#11375)
Bump of `zig-overlay`, allowing us to drop flake-utils from the flake
inputs. :)
2026-03-11 10:09:12 -07:00
Mitchell Hashimoto 19e5053b28
macos: only show the grab handle in fullscreen if there are splits (#11381)
Fixes #11376
2026-03-11 10:08:25 -07:00
Mitchell Hashimoto 2296a82c13
macOS: fix window frame when (re)opening new window (#11380)
Claude wrote the fail path in the UI tests, or you can easily reproduce
this manually. This is kinda a regression after #11322, since we are not
delaying the frame update anymore, which exposes some of the "flaws" of
the previous implementation.

The following three commits fix this step by step:
- We shouldn't save intermediate frames when the window is loading,
which is triggered by `windowDidResize` and `windowDidMove` during the
process.
- We should set the initial position (from the config) after the window
is loaded.
- A small refactor on `LastWindowPosition` to support restoring the
window frame under certain conditions.


https://github.com/user-attachments/assets/6f90f9a5-653d-4146-95c6-8e5c69bda656



### AI Disclosure

Claude helped me write the UI tests.
2026-03-11 10:08:14 -07:00
Mitchell Hashimoto 12bc1e7860
macos: only show the grab handle in fullscreen if there are splits
Fixes #11376
2026-03-11 10:02:09 -07:00
Mitchell Hashimoto 7aff470ceb
bash: fix extra newlines with readline vi mode indicator (#11377)
Use OSC 133;P (prompt mark) instead of 133;A (fresh line + prompt mark)
inside PS1 and PS2. Readline redraws the prompt on vi mode switches,
Ctrl-L, and other events, and 133;A's fresh-line behavior would emit a
CR+LF whenever the cursor wasn't at column 0, causing visible extra
newlines.

The one-time 133;A is now emitted via printf in __ghostty_precmd, which
only runs once per prompt cycle via PROMPT_COMMAND. On SIGWINCH, bash
redraws PS1 (firing the 133;P marks) but doesn't re-run PROMPT_COMMAND,
so there's no unwanted fresh-line on resize either. The redraw=last flag
persists from the initial printf.

This is a little less optimal than our previous approach, in terms of
number of prompt marks we emit, but it produces an overall more correct
result, which is the important thing.

Because readline prints its output outside the scope of PS1, those
characters "inherit" the surrounded prompt scope. This is usually fine,
but it can sometimes get out of sync (especially during redraws). This
is inherently a limitation of the fact that it's a separate output
channel, so we just have to accept that can happen.

Fixes: #10953
See: #11267
2026-03-11 09:54:46 -07:00
Jon Parise e31615d00b bash: fix extra newlines with readline vi mode indicator
Use OSC 133;P (prompt mark) instead of 133;A (fresh line + prompt mark)
inside PS1 and PS2. Readline redraws the prompt on vi mode switches,
Ctrl-L, and other events, and 133;A's fresh-line behavior would emit a
CR+LF whenever the cursor wasn't at column 0, causing visible extra
newlines.

The one-time 133;A is now emitted via printf in __ghostty_precmd, which
only runs once per prompt cycle via PROMPT_COMMAND. On SIGWINCH, bash
redraws PS1 (firing the 133;P marks) but doesn't re-run PROMPT_COMMAND,
so there's no unwanted fresh-line on resize either. The redraw=last flag
persists from the initial printf.

This is a little less optimal than our previous approach, in terms of
number of prompt marks we emit, but it produces an overall more correct
result, which is the important thing.

Because readline prints its output outside the scope of PS1, those
characters "inherit" the surrounded prompt scope. This is usually fine,
but it can sometimes get out of sync (especially during redraws). This
is inherently a limitation of the fact that it's a separate output
channel, so we just have to accept that can happen.

See: #11267
2026-03-11 12:46:14 -04:00
Lukas 596d502a75
macOS: restore window frame under certain conditions 2026-03-11 17:45:10 +01:00
Lukas 45d360dc68
macOS: set the initial window position after window is loaded 2026-03-11 17:45:09 +01:00
Lukas e8c82ca1af
macOS: save frame only if the window is visible 2026-03-11 17:45:09 +01:00
Lukas 0af9938ad2
macos: add UI test for window position restore across titlebar styles
Tests that window position and size are correctly restored after
reopen for all four macos-titlebar-style variants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 17:45:09 +01:00
faukah 9503fa0786
nix: bump zig-overlay version 2026-03-11 17:39:21 +01:00
Mitchell Hashimoto 8ad9ec8e88
add direct set_surface_title and set_tab_title actions (#11373)
Fixes #11316

This mirrors the `prompt` actions (hence why there is no window action
here) and enables setting titles via keybind actions which importantly
lets this work via command palettes, App Intents, AppleScript, etc.
2026-03-11 09:35:56 -07:00
ghostty-vouch[bot] a8d38fe5d8
Update VOUCHED list (#11374)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11372#discussioncomment-16086042)
from @mitchellh.

Vouch: @faukah

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-11 16:28:08 +00:00
Mitchell Hashimoto 86c2a2e87f
input: add direct set_surface_title and set_tab_title actions
Fixes #11316

This mirrors the `prompt` actions (hence why there is no window action
here) and enables setting titles via keybind actions which importantly
lets this work via command palettes, App Intents, AppleScript, etc.
2026-03-11 09:25:08 -07:00
Mitchell Hashimoto d48b6ba085
ci: skip vouched PRs for milestone attachment (#11371) 2026-03-11 09:21:51 -07:00
Mitchell Hashimoto f571c806fe
ci: skip vouched PRs for milestone attachment 2026-03-11 08:38:54 -07:00
Mitchell Hashimoto 660767c77d
bash: fix multiline PS1 with command substitutions (#11369)
Only replace the \n prompt escape when inserting secondary prompt marks,
not literal newlines `($'\n')`. Literal newlines may appear inside
`$(...)` or `...` command substitutions, and inserting escape sequences
there breaks the shell syntax. For example:

      PS1='$(if [ $? -eq 0 ]; then echo -e "P";
                    else echo -e "F";
                    fi) $ '

The literal newlines between the if/else/fi are part of the shell syntax
inside the command substitution. The previous code replaced all literal
newlines in PS1 with newline + OSC 133 escape sequences, which injected
terminal escapes into the middle of the command substitution and caused
bash to report a syntax error when evaluating it.

The \n prompt escape is PS1-specific and safe to replace globally. This
means prompts using literal newlines for line breaks (rather than \n)
won't get per-line secondary marks, but this is the conventional form
and avoids the need for complex shell parsing.

Fixes: #11267
2026-03-11 08:36:36 -07:00
Jon Parise 26d8bd9e71 bash: fix multiline PS1 with command substitutions
Only replace the \n prompt escape when inserting secondary prompt marks,
not literal newlines ($'\n'). Literal newlines may appear inside $(...)
or `...` command substitutions, and inserting escape sequences there
breaks the shell syntax. For example:

      PS1='$(if [ $? -eq 0 ]; then echo -e "P";
                    else echo -e "F";
                    fi) $ '

The literal newlines between the if/else/fi are part of the shell syntax
inside the command substitution. The previous code replaced all literal
newlines in PS1 with newline + OSC 133 escape sequences, which injected
terminal escapes into the middle of the command substitution and caused
bash to report a syntax error when evaluating it.

The \n prompt escape is PS1-specific and safe to replace globally. This
means prompts using literal newlines for line breaks (rather than \n)
won't get per-line secondary marks, but this is the conventional form
and avoids the need for complex shell parsing.

Fixes: #11267
2026-03-11 10:46:43 -04:00
Mitchell Hashimoto 61865bc37f
zsh: improve prompt marking with dynamic themes (#11367)
Replace the strip-in-preexec / re-add-in-precmd pattern for OSC 133
marks with a save/restore approach. Instead of pattern-matching marks
out of PS1 (which exposes PS1 in intermediate states to other hooks), we
save the original PS1/PS2 before adding marks and then restore them.

This also adds dynamic theme detection: if PS1 changed between cycles
(e.g., a theme rebuilt it), we skip injecting continuation marks into
newlines. This prevents breaking plugins like Pure that use pattern
matching to strip/rebuild the prompt.

Additionally, move _ghostty_precmd to the end of precmd_functions in
_ghostty_deferred_init (instead of substituting in-place) so that the
first prompt is properly marked even when other hooks were appended
after our auto-injection.

There's one scenario that we still don't complete cover:

    precmd_functions+=(_test_overwrite_ps1)
    _test_overwrite_ps1() {
        PS1="test> "
    }

... which results in the first prompt not printing its prompt marks
because _test_overwrite_ps1 becomes the last thing to run, overwriting
our marks, but this will be fixed for subsequent prompts when we move
our handler back to the last index.

Fixes: #11282
2026-03-11 07:30:02 -07:00
Mitchell Hashimoto 048a2d043a
Merge fix-fullscreen-tab-title-rename-hit into main 2026-03-11 07:25:02 -07:00
ydah c2206542d3 macos: fix tab title rename hit testing and focus handling in fullscreen mode 2026-03-11 07:24:49 -07:00
ghostty-vouch[bot] 87e496b30f
Update VOUCHED list (#11368)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11365#issuecomment-4039534706)
from @mitchellh.

Vouch: @ydah

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-11 14:17:51 +00:00
Jon Parise 23f3cd5f10 zsh: improve prompt marking with dynamic themes
Replace the strip-in-preexec / re-add-in-precmd pattern for OSC 133
marks with a save/restore approach. Instead of pattern-matching marks
out of PS1 (which exposes PS1 in intermediate states to other hooks), we
save the original PS1/PS2 before adding marks and then restore them.

This also adds dynamic theme detection: if PS1 changed between cycles
(e.g., a theme rebuilt it), we skip injecting continuation marks into
newlines. This prevents breaking plugins like Pure that use pattern
matching to strip/rebuild the prompt.

Additionally, move _ghostty_precmd to the end of precmd_functions in
_ghostty_deferred_init (instead of substituting in-place) so that the
first prompt is properly marked even when other hooks were appended
after our auto-injection.

There's one scenario that we still don't complete cover:

    precmd_functions+=(_test_overwrite_ps1)
    _test_overwrite_ps1() {
        PS1="test> "
    }

... which results in the first prompt not printing its prompt marks
because _test_overwrite_ps1 becomes the last thing to run, overwriting
our marks, but this will be fixed for subsequent prompts when we move
our handler back to the last index.

Fixes: #11282
2026-03-11 10:07:54 -04:00
Leah Amelia Chen 76e9ee7d37
gtk: fix +new-window `--working-directory` inferrence. (#11357) 2026-03-11 17:16:06 +08:00
Leah Amelia Chen b992b66050
docs: fix backtick rendering in selection-word-chars default value (#11361) 2026-03-11 17:02:33 +08:00
Paul Oliver 82a805296c
docs: fix backtick rendering in selection-word-chars default value
The default value contains a literal backtick which broke inline code
rendering on the website. Use double backtick delimiters to properly
contain it.
2026-03-11 21:15:20 +13:00
ghostty-vouch[bot] a644fca5c5
Update VOUCHED list (#11360)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11358#discussioncomment-16080010)
from @jcollie.

Vouch: @puzza007

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-11 08:02:29 +00:00
Jeffrey C. Ollie ad6d3665c2
gtk: fix +new-window `--working-directory` inferrence.
If the CLI argument `--working-directory` is not used with
`+new-window`, the current working directory that `ghostty +new-window`
is run from will be appended to the list of configuration data sent
to the main Ghostty process. If `-e` _was_ used on the CLI, the
`--working-directory` that was appended will be interpreted as part of
the command to be executed, likely causing it to fail.

Instead, insert `--working-directory` at the beginning of the list of
configuration that it sent to the main Ghostty process.

Fixes #11356
2026-03-11 02:23:12 -05:00
Mitchell Hashimoto dc18b25f86
macos: disable Tahoe one-time codes (#11351)
This disables all the automatic one-time code inputs in Ghostty. It'd be
really neat to actually dynamically change this (not sure if it's
possible with NSTextContext or how often thats cached) but for now we
should just fully disable it.

Thanks to Ricky Mondello for the heads up on this.
2026-03-10 19:52:30 -07:00
Mitchell Hashimoto 6dd5b856b0
macos: disable Tahoe one-time codes
This disables all the automatic one-time code inputs in Ghostty.
It'd be really neat to actually dynamically change this (not sure if its
possible with NSTextContext or how often thats cached) but for now we
should just fully disable it.
2026-03-10 19:41:22 -07:00
Mitchell Hashimoto 2a170b50c3
macos: add test cases for Ghostty.Config properties (#11263)
### AI Disclosure

Test cases is written using the Claude Agent in Xcode
2026-03-10 19:34:49 -07:00
Jeffrey C. Ollie d5dab554aa
build(deps): bump cachix/install-nix-action from 31.10.0 to 31.10.1 (#11347)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.10.0 to 31.10.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.10.1</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.34.0 -&gt; 2.34.1 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/269">cachix/install-nix-action#269</a>
Fixes a bug introduced in 2.34.0 that made the Nix daemon fail to load
authentication keys configured by <code>cachix-action</code>.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31.10.0...v31.10.1">https://github.com/cachix/install-nix-action/compare/v31.10.0...v31.10.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1ca7d21a94"><code>1ca7d21</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/269">#269</a>
from cachix/create-pull-request/patch</li>
<li><a
href="b613734327"><code>b613734</code></a>
nix: 2.34.0 -&gt; 2.34.1</li>
<li>See full diff in <a
href="19effe9fe7...1ca7d21a94">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.10.0&new-version=31.10.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-03-10 21:23:32 -05:00
dependabot[bot] 85bec80334
build(deps): bump cachix/install-nix-action from 31.10.0 to 31.10.1
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.10.0 to 31.10.1.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](19effe9fe7...1ca7d21a94)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 00:14:04 +00:00
Jeffrey C. Ollie 818e170ec0
GTK does support scrollbars (#11345)
Native GTK scrollbars are supported in 1.3.0:
https://ghostty.org/docs/install/release-notes/1-3-0#scrollbars
2026-03-10 18:46:20 -05:00
ghostty-vouch[bot] 615af975f3
Update VOUCHED list (#11344)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11343#discussioncomment-16075282)
from @jcollie.

Vouch: @hulet

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-10 23:26:26 +00:00
Steve Hulet f9862cd4e2 GTK does support scrollbars 2026-03-10 16:14:18 -07:00
Mitchell Hashimoto 0cb189bfbb
config: working-directory expands ~/ prefix (#11337)
Fixes #11336

Introduce a proper WorkingDirectory tagged union type with home,
inherit, and path variants. The field is now an optional
(?WorkingDirectory) where null represents "use platform default" which
is resolved during Config.finalize to .inherit (CLI) or .home (desktop
launcher).
2026-03-10 14:40:43 -07:00
Mitchell Hashimoto 04d5efc8eb
config: working-directory expands ~/ prefix
Fixes #11336

Introduce a proper WorkingDirectory tagged union type with home, inherit,
and path variants. The field is now an optional (?WorkingDirectory) where
null represents "use platform default" which is resolved during Config.finalize
to .inherit (CLI) or .home (desktop launcher).
2026-03-10 14:33:40 -07:00
Lukas 90dc4315e2
macos: add test cases for Ghostty.Config properties
Test boolean, string, enum, and numeric config properties using
TemporaryConfig to verify defaults and parsed values.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-10 20:03:17 +01:00
Mitchell Hashimoto a4cc37db72
tests: disable tests that fail if you have locally installed fonts (#11285)
If you have "Noto Sans Tai Tham" and/or "Noto Sans Javanese" installed
locally on Linux, three tests fail. This PR disables those tests until a
more permanent solution can be found.
2026-03-10 11:53:23 -07:00
Lukas 32934445cf
macos: add TemporaryConfig for AI to write test cases 2026-03-10 19:45:52 +01:00
Jeffrey C. Ollie c1313294cd
add comments about why tests are disabled 2026-03-10 13:29:50 -05:00
Mitchell Hashimoto 8784636547
macos: remove IntrinsicSizeTimingTests temporarily (#11332)
These were too flaky.

cc @bo2themax
2026-03-10 11:23:16 -07:00
Mitchell Hashimoto 71f81527ad
macos: remove IntrinsicSizeTimingTests temporarily
These were too flaky.
2026-03-10 11:08:47 -07:00
Mitchell Hashimoto f88b42ad39
macos: add enum type for macos-titlebar-style (#11262) 2026-03-10 10:58:47 -07:00
Mitchell Hashimoto 7fb8e0ac90
fix jump_to_prompt forward behavior for multiline prompts (#11331)
Fixes #11330.

When jumping forward from prompt content, skip prompt continuation rows
so a multiline prompt is treated as a single prompt block.
2026-03-10 10:51:17 -07:00
Mitchell Hashimoto 53637ec7b2
fix jump_to_prompt forward behavior for multiline prompts
Fixes #11330.

When jumping forward from prompt content, skip prompt continuation rows so a 
multiline prompt is treated as a single prompt block.
2026-03-10 10:47:18 -07:00
ghostty-vouch[bot] f8d7876203
Update VOUCHED list (#11329)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11313#issuecomment-4033213188)
from @mitchellh.

Vouch: @VaughanAndrews

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-10 17:31:32 +00:00
Mitchell Hashimoto c06ede5849
macos: make paste_from_clipboard performable on macos (#11328)
Fixes #10751
2026-03-10 10:31:22 -07:00
Mitchell Hashimoto aaad43c235
macos: make paste_from_clipboard performable on macos
Fixes #10751
2026-03-10 10:25:14 -07:00
Mitchell Hashimoto 119ce0bc1d
macos: reset mouse state on focus loss to prevent phantom drag (#11276)
Fixes https://github.com/ghostty-org/ghostty/discussions/11203

The `suppressNextLeftMouseUp` flag from #11167 wasn't being reset on
focus loss, causing stale state that led to phantom drags/selections and
scrolls if you're lucky enough.

I've followed the #11167 's path and made it reset on focus loss.

As I stated in the [vouch
request](https://github.com/ghostty-org/ghostty/discussions/11274); I'm
not experienced in Swift, just following the prior PR's steps to reset
the state. I've been using this patch for couple days and the change
looks trivial to me tho not 100% sure if I'm missing anything.

> [!NOTE]
> Used Claude Code -Opus 4.6- for navigating the codebase and reviewing
the change.
2026-03-10 09:56:39 -07:00
Selman Kayrancioglu 6092c299d5 macos: reset mouse state on focus loss to prevent phantom drag
Fixes phantom mouse drag/selection when switching splits or apps.
The suppressNextLeftMouseUp flag and core mouse click_state were not
being reset on focus transitions, causing stale state that led to
unexpected drag behavior.

- Reset suppressNextLeftMouseUp in focusDidChange when losing focus
- Defensively reset the flag when processing normal clicks
- Reset core mouse.click_state and left_click_count on focus loss
2026-03-10 09:54:08 -07:00
Mitchell Hashimoto 4e24adf717
ci: skip xcode tests for freetype build 2026-03-10 09:40:28 -07:00
Mitchell Hashimoto 9759787847
config: don't double load app support path on macOS (#11326)
Fixes #11323
2026-03-10 09:28:59 -07:00
Mitchell Hashimoto d9039eb85a
config: don't double load app support path on macOS
Fixes #11323
2026-03-10 09:23:51 -07:00
Lukas de0f2ab22d
macos: add enum type for macos-titlebar-style 2026-03-10 17:15:14 +01:00
Mitchell Hashimoto 3782d118e1
macOS: restore keyboard focus after inline tab title edit (#11320)
## Summary

- After finishing an inline tab title edit (via keybind or
double-click), all keyboard input is lost because
`TabTitleEditor.finishEditing()` sets `makeFirstResponder(nil)`, leaving
the window itself as first responder with no path back to the terminal
surface.
- Adds a `tabTitleEditorDidFinishEditing` delegate callback to
`TabTitleEditorDelegate` that fires after every edit (commit or cancel).
- `TerminalWindow` implements it by calling
`makeFirstResponder(focusedSurface)` to restore keyboard focus to the
terminal.

Fixes https://github.com/ghostty-org/ghostty/discussions/11315

## Testing

- [x] Bind `prompt_tab_title` to a keybind (e.g. `keybind =
cmd+shift+i=prompt_tab_title`)
- [x] Trigger inline tab title edit via keybind, press Enter — verify
keyboard input works immediately
- [x] Trigger inline tab title edit via keybind, press Escape — verify
keyboard input works immediately
- [x] Double-click a tab title, press Enter — verify keyboard input
works immediately
- [x] Double-click a tab title, press Escape — verify keyboard input
works immediately
- [x] Verify Cmd+number tab switching works after all of the above
- [x] Verify split pane focus is correct after editing tab title with
splits open

AI disclosure: Codebase exploration and review via [Claude
Code](https://claude.com/claude-code)
2026-03-10 08:59:51 -07:00
Mitchell Hashimoto 85f0972b39
macOS: fix intrinsicContentSize race in windowDidLoad (#11322)
This should fix #11256 and #11271. 

Tested manually with various combination of `window-width/height` and
`macos-titlebar-style`.


https://github.com/user-attachments/assets/90c12728-b195-47bf-abfd-8a4034b1e7a2


### AI Disclosure

All the commits are generated by Claude, but orchestrated and manually
tested by myself.
2026-03-10 08:59:40 -07:00
chronologos 7629130fb4 macOS: restore keyboard focus after inline tab title edit
After finishing an inline tab title edit (via keybind or double-click),
`TabTitleEditor.finishEditing()` calls `makeFirstResponder(nil)` to
clear focus from the text field, leaving the window itself as first
responder. No code path restores focus to the terminal surface, so all
keyboard input is lost until the user clicks into a pane.

Add a `tabTitleEditorDidFinishEditing` delegate callback that fires
after every edit (commit or cancel). TerminalWindow implements it by
calling `makeFirstResponder(focusedSurface)` to hand focus back to the
terminal.

Fixes https://github.com/ghostty-org/ghostty/discussions/11315

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-10 08:52:00 -07:00
Mitchell Hashimoto 1592cafa32
Update AGENTS.md 2026-03-10 08:48:24 -07:00
Lukas a6cd1b08af
macOS: fix intrinsicContentSize race in windowDidLoad (#11256)
Add initialContentSize fallback on TerminalViewContainer so
intrinsicContentSize returns the correct value immediately,
without waiting for @FocusedValue to propagate. This removes
the need for the DispatchQueue.main.asyncAfter 40ms delay.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:35:49 +01:00
Lukas cfedda1a0e
macOS: add regression tests for intrinsicContentSize race (#11256)
Tests that validate intrinsicContentSize returns a correct value when
TerminalController.windowDidLoad() reads it. Currently fail, proving
the race condition where @FocusedValue hasn't propagated
lastFocusedSurface before the 40ms timer fires.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:27:38 +01:00
ghostty-vouch[bot] 6c7309196f
Update VOUCHED list (#11321)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11320#issuecomment-4031703556)
from @mitchellh.

Vouch: @chronologos

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-10 14:15:21 +00:00
Mitchell Hashimoto e11f350e8e
docs: update bell-features docs for macOS (#11279)
PR #11154 didn't fully update the docs regarding `bell-features=audio`
on macOS.
2026-03-10 07:12:02 -07:00
ghostty-vouch[bot] c83dea49fd
Update VOUCHED list (#11318)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11309#discussioncomment-16069391)
from @mitchellh.

Vouch: @dzhlobo

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-10 14:09:14 +00:00
ghostty-vouch[bot] 327783ff6c
Update VOUCHED list (#11314)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11287#discussioncomment-16069141)
from @mitchellh.

Vouch: @ocean6954

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-10 13:58:50 +00:00
Jeffrey C. Ollie 96f9772cd8
tests: disable tests that fail if you have locally installed fonts
If you have "Noto Sans Tai Tham" and/or "Noto Sans Javanese" installed
locally on Linux, three tests fail. This PR disables those tests until a
more permanent solution can be found.
2026-03-09 19:59:21 -05:00
Jeffrey C. Ollie f8f431ba67
docs: update bell-features docs for macOS
PR #11154 didn't fully update the docs regarding `bell-features=audio`
on macOS.
2026-03-09 16:47:07 -05:00
ghostty-vouch[bot] f8a0a45963
Update VOUCHED list (#11275)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/11274#discussioncomment-16057271)
from @jcollie.

Vouch: @seruman

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-09 19:20:32 +00:00
Jake Guthmiller bec4c61d4d PR feedback: heap-allocate primary_output_name 2026-03-03 21:28:02 -06:00
Jake Guthmiller b823c07ae3 PR feedback - simplify 2026-03-03 20:56:24 -06:00
Jake Guthmiller beeb810c04 gtk: address PR review feedback for quick-terminal-screen 2026-03-02 23:33:19 -06:00
Jake Guthmiller 18fa161222 gtk: simplify Wayland output-order state handling 2026-03-01 18:23:08 -06:00
Jake Guthmiller c982253543 gtk: handle replacement Wayland globals before remove
Track registry global names for kde decoration manager and kde_output_order bindings so we can distinguish same-global duplicates from valid replacements announced before global_remove.

On global_remove, match and clear these bindings by registry global name to avoid dropping a replacement when the old global is removed.
2026-03-01 18:23:08 -06:00
Jake Guthmiller 19feaa058b gtk: improve readability of Wayland quick-terminal monitor code
Flatten resolveQuickTerminalMonitor by replacing the labeled-block
switch with early returns, extract max_output_name_len constant, and
reduce nesting in the output-order event handler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:23:08 -06:00
Jake Guthmiller 34473b069b gtk: simplify quick-terminal monitor resolution and state management
Restructure resolveQuickTerminalMonitor into a two-phase approach
(match by name, then fall back to first monitor) to eliminate the
interleaved fallback/match ref tracking. Remove redundant switch in
enteredMonitor that duplicated the .mouse handling already in
resolveQuickTerminalMonitor. Hoist the primary_output_match_failed_logged
reset above the name-length branches in outputOrderListener.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:23:08 -06:00
Jake Guthmiller e25d8a6f2f gtk: harden quick-terminal output-order state handling
Install Wayland protocol listeners at bind time so late-added globals
still receive events and listener setup stays tied to object lifetime.

Track whether kde_output_order_v1 emitted any outputs in a cycle and
clear cached primary-output state on empty or invalid updates. Also
reset this cycle tracking when the protocol global is removed to avoid
stale monitor selection.
2026-03-01 18:23:08 -06:00
Jake Guthmiller 630c2dff19 gtk: fix monitor ref ownership in Wayland quick terminal
Handle g_list_model_get_object transfer-full semantics in resolveQuickTerminalMonitor by retaining exactly one monitor reference to return and unreffing the rest.

Update init/sync/sizing call sites to unref the resolved monitor after setMonitor/getGeometry so monitor lifetimes are explicit and consistent.

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
2026-03-01 18:23:08 -06:00
Jake Guthmiller 6da660a9a5 gtk: implement quick-terminal-screen for Wayland
Implement the quick-terminal-screen config option on Linux/Wayland so
users can pin the quick terminal to a specific monitor instead of
always following the mouse cursor.

Use the kde_output_order_v1 protocol to identify the compositor's
primary monitor by connector name (e.g. "DP-1"). When the protocol is
unavailable, fall back to the first monitor in the GDK list.

- Add resolveQuickTerminalMonitor() to map config values to a
  gdk.Monitor: .mouse returns null (compositor decides), .main and
  .macos-menu-bar match by connector name via the protocol
- Call layer_shell.setMonitor() in both initQuickTerminal and
  syncQuickTerminal so config reloads take effect
- Update enteredMonitor to size the window using the configured
  monitor rather than whichever monitor was entered
- Update config documentation to reflect Linux support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:23:08 -06:00
Jake Guthmiller 96f8f0d93c gtk: add setMonitor binding and kde-output-order-v1 protocol
Add the missing setMonitor() function to the gtk4-layer-shell Zig
bindings and provide the gdk module so it can reference gdk.Monitor.

Register the kde-output-order-v1 Wayland protocol from
plasma-wayland-protocols and generate its scanner binding. This
protocol reports the compositor's monitor priority ordering and is
needed to correctly identify the primary monitor for
quick-terminal-screen support on Linux.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:23:08 -06:00
543 changed files with 94536 additions and 41624 deletions

View File

@ -1,64 +0,0 @@
#!/usr/bin/env nu
# A command to generate an agent prompt to diagnose and formulate
# a plan for resolving a GitHub issue.
#
# IMPORTANT: This command is prompted to NOT write any code and to ONLY
# produce a plan. You should still be vigilant when running this but that
# is the expected behavior.
#
# The `<issue>` parameter can be either an issue number or a full GitHub
# issue URL.
def main [
issue: any, # Ghostty issue number or URL
--repo: string = "ghostty-org/ghostty" # GitHub repository in the format "owner/repo"
] {
# TODO: This whole script doesn't handle errors very well. I actually
# don't know Nu well enough to know the proper way to handle it all.
let issueData = gh issue view $issue --json author,title,number,body,comments | from json
let comments = $issueData.comments | each { |comment|
$"
### Comment by ($comment.author.login)
($comment.body)
" | str trim
} | str join "\n\n"
$"
Deep-dive on this GitHub issue. Find the problem and generate a plan.
Do not write code. Explain the problem clearly and propose a comprehensive plan
to solve it.
# ($issueData.title) \(($issueData.number)\)
## Description
($issueData.body)
## Comments
($comments)
## Your Tasks
You are an experienced software developer tasked with diagnosing issues.
1. Review the issue context and details.
2. Examine the relevant parts of the codebase. Analyze the code thoroughly
until you have a solid understanding of how it works.
3. Explain the issue in detail, including the problem and its root cause.
4. Create a comprehensive plan to solve the issue. The plan should include:
- Required code changes
- Potential impacts on other parts of the system
- Necessary tests to be written or updated
- Documentation updates
- Performance considerations
- Security implications
- Backwards compatibility \(if applicable\)
- Include the reference link to the source issue and any related discussions
4. Think deeply about all aspects of the task. Consider edge cases, potential
challenges, and best practices for addressing the issue. Review the plan
with the oracle and adjust it based on its feedback.
**ONLY CREATE A PLAN. DO NOT WRITE ANY CODE.** Your task is to create
a thorough, comprehensive strategy for understanding and resolving the issue.
" | str trim
}

View File

@ -0,0 +1,62 @@
---
name: writing-commit-messages
description: >-
Writes Git commit messages. Activates when the user asks to write
a commit message, draft a commit message, or similar.
---
# Writing Commit Messages
Write commit messages that follow commit style guidelines for the project.
## Format
```
<subsystem>: <summary>
<reference issues/PRs/etc.>
<long form description>
```
## Rules
### Subject line
- **Subsystem prefix**: Use a short, lowercase identifier for the
area of code changed (e.g., `terminal`, `vt`, `lib`, `config`,
`font`). Determine this from the file paths in the diff. If
changes span the macOS app, use `macos`. For GTK, use `gtk`. For
build system, use `build`. Use nested subsystems with `/` when
helpful and exclusive (e.g., `terminal/osc`).
- **Summary**: Lowercase start (not capitalized), imperative mood,
no trailing period. Keep it concise—ideally under 60 characters
total for the whole subject line.
### References
- If the change relates to a GitHub issue, PR, or discussion, list
the relevant numbers on their own lines after the subject, separated
by a blank line. E.g. `#1234`
- If there are no references, omit this section entirely (no blank
line).
### Long form description
- Describe **what changed**, **what the previous behavior was**,
and **how the new behavior works** at a high level.
- Use plain prose, not bullet points. Wrap lines at ~72 characters.
- Focus on the _why_ and _how_ rather than restating the diff.
- Keep the tone direct and technical without no filler phrases.
- Don't exceed a handful of paragraphs; less is more.
## Workflow
- If `.jj` is present, use `jj` instead of `git` for all commands.
- Run a diff to see what changes are present since the last commit.
- Identify the subsystem from the changed file paths.
- Identify any referenced issues/PRs from the diff context or
branch name.
- Draft the commit message following the format above.
- Apply the commit
- Don't push the commit; leave that to the user.

44
.gitattributes vendored
View File

@ -1,3 +1,47 @@
#--------------------------------------------------------------------
# Line endings
#--------------------------------------------------------------------
# Source code - always LF
*.zig text eol=lf
*.c text eol=lf
*.h text eol=lf
*.cpp text eol=lf
*.m text eol=lf
*.swift text eol=lf
*.py text eol=lf
*.sh text eol=lf
*.glsl text eol=lf
*.blp text eol=lf
# Config/build files - always LF
*.zon text eol=lf
*.nix text eol=lf
*.md text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.toml text eol=lf
CMakeLists.txt text eol=lf
*.cmake text eol=lf
Makefile text eol=lf
# Text data files - always LF (embedded in Zig, parsed with \n split)
*.txt text eol=lf
# Windows resource files - preserve as-is (native Windows tooling)
*.rc -text
*.manifest -text
# Binary files
*.png binary
*.ico binary
*.icns binary
*.ttf binary
*.otf binary
#--------------------------------------------------------------------
# Linguist
#--------------------------------------------------------------------
build.zig.zon.nix linguist-generated=true build.zig.zon.nix linguist-generated=true
build.zig.zon.txt linguist-generated=true build.zig.zon.txt linguist-generated=true
build.zig.zon.json linguist-generated=true build.zig.zon.json linguist-generated=true

114
.github/VOUCHED.td vendored
View File

@ -19,142 +19,256 @@
# discussion by the author. Maintainers can denounce users by commenting # discussion by the author. Maintainers can denounce users by commenting
# "!denounce" or "!denounce [username]" on a discussion. # "!denounce" or "!denounce [username]" on a discussion.
00-kat 00-kat
007hacky007
00jciv00
04cb 04cb
0xdvc
-4rh1t3ct0r7
52dyd
aalhendi aalhendi
aaron-ang
abdurrahmanski abdurrahmanski
abudvytis abudvytis
adrum adrum
agoodkind
aindriu80 aindriu80
ajiblock
akimiojr
alaasdk alaasdk
alanmoyano alanmoyano
alaviss
alexfeijoo44 alexfeijoo44
alexjuca alexjuca
alosarjos
amadeus amadeus
andrejdaskalov andrejdaskalov
anhthang
anmitalidev
anthonyzhoon anthonyzhoon
athaapa
atomk atomk
b0uks
b1nar10
balazs-szucs balazs-szucs
barutsrb
bch
bennettp123 bennettp123
benodiwal benodiwal
bernsno bernsno
beryesa beryesa
bitigchi bitigchi
bkircher bkircher
bleikurr
bo2themax bo2themax
brentschroeter brentschroeter
brianc442
c0x0o
cespare cespare
charliie-dev charliie-dev
chernetskyi chernetskyi
chronologos
cmwetherell cmwetherell
crayxt
craziestowl craziestowl
curtismoncoq curtismoncoq
-cznorth Automated advertising + likely AI communication
d-dudas d-dudas
-daedaevibin
daiimus daiimus
damyanbogoev damyanbogoev
danneu
danulqua danulqua
dariogriffo dariogriffo
davidsanchez222
deblasis
dervedro dervedro
devsunb
diaaeddin diaaeddin
dkinzler
dmehala dmehala
dobbylee
doprz doprz
douglance douglance
douglas douglas
douglas-macgregor
drepper drepper
dzhlobo
ekaterinepapava
elias8 elias8
-enkr1
enzowilliam
ephemera ephemera
-eric-assetpass Try talking, not botting
eriksremess eriksremess
erral
-f1813483-netizen
faukah
filip7 filip7
flou flou
fornwall
francescarpi francescarpi
fru1tworld
gagbo gagbo
ghokun ghokun
gmile gmile
gordonbondon gordonbondon
gpanders gpanders
guilhermetk guilhermetk
h3nock
hakonhagland hakonhagland
halosatrio halosatrio
heaths
heddxh heddxh
-highimpact-dev Disrespectful AI user
hlcfan
hqnna hqnna
hulet
i999rri
icodesign icodesign
illiakrauchanka
j0hnm4r5
jacobsandlund jacobsandlund
jake-stewart jake-stewart
jamylak
jarred-sumner
jcollie jcollie
jesusvazquez
jguthmiller jguthmiller
jmcgover jmcgover
jmr
johnslavik johnslavik
jordandm
josephmart josephmart
jparise jparise
juniqlim juniqlim
justonia
karesansui-u
kataokatsuki
kawarimidoll kawarimidoll
kayleung
kenvandine kenvandine
khipp khipp
kierancanter
kirwiisp kirwiisp
kjvdven kjvdven
kloneets kloneets
knu
-kody-w
koranir koranir
kristina8888 kristina8888
kristofersoler kristofersoler
kylesower
laxystem laxystem
lebdron
lepips
liby liby
linustalacko linustalacko
lonsagisawa lonsagisawa
louisunlimited
luisnquin
lynicis
mac0ne mac0ne
mahnokropotkinvich mahnokropotkinvich
marijagjorgjieva marijagjorgjieva
markdorison markdorison
markhuot markhuot
marler8997
marrocco-simone marrocco-simone
masterflitzer
matkotiric matkotiric
mattn
micaeljarniac
michielvk michielvk
miguelelgallo miguelelgallo
mihi314 mihi314
mikailmm mikailmm
minorcell
misairuzame misairuzame
mischief mischief
mitchellh mitchellh
miupa miupa
mjbommar
mohshami
molechowski molechowski
moonmao42
-morgengeluk Appears to be using AI inappropriately even after it was requested they abide by the AI policy (there is clear evidence of the person-in-the-loop not attempting to clean up AI generated text, and their AI disclosure itself reads like AI-generated text and shows no signs of remorse or intent to improve).
mpatankar6
mrconnorkenway
mrmage mrmage
mtak mtak
natesmyth natesmyth
neo773 neo773
neurosnap
nicholas-ochoa
nicosuave nicosuave
nikicat
nmggithub nmggithub
noib3 noib3
nolinmcfarland
nouritsu
nwehg nwehg
ocean6954
oshdubh oshdubh
otomn
paaloeye
pan93412 pan93412
pangoraw pangoraw
pauley-unsaturated pauley-unsaturated
peilingjiang peilingjiang
peterdavehello peterdavehello
philocalyst
phush0 phush0
piedrahitac piedrahitac
pluiedev pluiedev
pouwerkerk pouwerkerk
poweruser64
prakhar54-byte prakhar54-byte
priyans-hu priyans-hu
puzza007
qwerasd205 qwerasd205
raphamorim
reo101 reo101
rewdy
rgehan rgehan
rhodes-b rhodes-b
rightaditya
rjwittams
rmengelbrecht rmengelbrecht
rmunn rmunn
rockorager rockorager
rpfaeffle rpfaeffle
samasaur1
sandydoo
secrus secrus
seruman
seyoungjeong
silveirapf silveirapf
slsrepo slsrepo
sunshine-syz sunshine-syz
tbrundige
tdgroot
tdslot tdslot
thirstycrow
thoutbeckers
ticclick ticclick
tnagatomi tnagatomi
trag1c trag1c
tristan957 tristan957
turbolent
tweedbeetle tweedbeetle
uhojin uhojin
unphased
uzaaft uzaaft
vancluever
vaughanandrews
viruslobster
vlsi vlsi
voidnv
wyounas
yabbal
yamshta yamshta
ydah
-zaviro
zenyr zenyr
zeshi09 zeshi09
zubb

5
.github/issue-unvouched-message vendored Normal file
View File

@ -0,0 +1,5 @@
Hi @{author}, thanks for your interest!
Non-maintainers are not allowed to create issues in this repository — we ask that you create a discussion first. For more details on the why, see #3558 and our [CONTRIBUTING.md](https://github.com/ghostty-org/ghostty/blob/main/CONTRIBUTING.md).
This issue will be closed automatically.

View File

@ -30,7 +30,7 @@ jobs:
runs-on: ${{ matrix.variant.runner }} runs-on: ${{ matrix.variant.runner }}
steps: steps:
- name: Download Source Tarball Artifacts - name: Download Source Tarball Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
run-id: ${{ inputs.source-run-id }} run-id: ${{ inputs.source-run-id }}
artifact-ids: ${{ inputs.source-artifact-id }} artifact-ids: ${{ inputs.source-artifact-id }}
@ -41,7 +41,7 @@ jobs:
mkdir dist mkdir dist
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
- uses: flatpak/flatpak-github-actions/flatpak-builder@92ae9851ad316786193b1fd3f40c4b51eb5cb101 # v6.6 - uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb # v6.7
with: with:
bundle: com.mitchellh.ghostty bundle: com.mitchellh.ghostty
manifest-path: dist/flatpak/com.mitchellh.ghostty.yml manifest-path: dist/flatpak/com.mitchellh.ghostty.yml

View File

@ -11,12 +11,15 @@ on:
jobs: jobs:
update-milestone: update-milestone:
# Ignore bot-authored pull requests (dependabot, app bots, etc)
# and CI-only PRs.
if: github.event_name == 'issues' || (github.event.pull_request.user.type != 'Bot' && !startsWith(github.event.pull_request.title, 'ci:'))
runs-on: namespace-profile-ghostty-sm runs-on: namespace-profile-ghostty-sm
name: Milestone Update name: Milestone Update
steps: steps:
- name: Set Milestone for PR - name: Set Milestone for PR
uses: hustcer/milestone-action@ebed8d5daafd855a600d7e665c1b130f06d24130 # v3.1 uses: hustcer/milestone-action@ebed8d5daafd855a600d7e665c1b130f06d24130 # v3.1
if: github.event.pull_request.merged == true if: github.event.pull_request.merged == true && !contains(github.event.pull_request.title, 'VOUCHED') && !startsWith(github.event.pull_request.title, 'ci:')
with: with:
action: bind-pr # `bind-pr` is the default action action: bind-pr # `bind-pr` is the default action
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -39,18 +39,18 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
path: | path: |
/nix /nix
/zig /zig
- name: Setup Nix - name: Setup Nix
uses: cachix/install-nix-action@19effe9fe722874e6d46dd7182e4b8b7a43c4a99 # v31.10.0 uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"

View File

@ -56,7 +56,7 @@ jobs:
fi fi
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# Important so that build number generation works # Important so that build number generation works
fetch-depth: 0 fetch-depth: 0
@ -80,20 +80,20 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
path: | path: |
/nix /nix
/zig /zig
- uses: cachix/install-nix-action@19effe9fe722874e6d46dd7182e4b8b7a43c4a99 # v31.10.0 - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -113,7 +113,7 @@ jobs:
nix develop -c minisign -S -m "ghostty-source.tar.gz" -s minisign.key < minisign.password nix develop -c minisign -S -m "ghostty-source.tar.gz" -s minisign.key < minisign.password
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: source-tarball name: source-tarball
path: |- path: |-
@ -134,10 +134,10 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
cache: | cache: |
xcode xcode
@ -147,13 +147,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/nix-installer-action@main
with: with:
determinate: true determinate: true
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select - name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.2.app run: sudo xcode-select -s /Applications/Xcode_26.3.app
- name: Xcode Version - name: Xcode Version
run: xcodebuild -version run: xcodebuild -version
@ -282,7 +282,7 @@ jobs:
zip -9 -r --symlinks ../../../ghostty-macos-universal-dsym.zip Ghostty.app.dSYM/ zip -9 -r --symlinks ../../../ghostty-macos-universal-dsym.zip Ghostty.app.dSYM/
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: macos name: macos
path: |- path: |-
@ -299,7 +299,7 @@ jobs:
curl -sL https://sentry.io/get-cli/ | bash curl -sL https://sentry.io/get-cli/ | bash
- name: Download macOS Artifacts - name: Download macOS Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: macos name: macos
@ -319,10 +319,10 @@ jobs:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }} GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Download macOS Artifacts - name: Download macOS Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: macos name: macos
@ -353,7 +353,7 @@ jobs:
mv appcast_new.xml appcast.xml mv appcast_new.xml appcast.xml
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: sparkle name: sparkle
path: |- path: |-
@ -370,17 +370,17 @@ jobs:
GHOSTTY_VERSION: ${{ needs.setup.outputs.version }} GHOSTTY_VERSION: ${{ needs.setup.outputs.version }}
steps: steps:
- name: Download macOS Artifacts - name: Download macOS Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: macos name: macos
- name: Download Sparkle Artifacts - name: Download Sparkle Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: sparkle name: sparkle
- name: Download Source Tarball Artifacts - name: Download Source Tarball Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: source-tarball name: source-tarball

View File

@ -33,19 +33,19 @@ jobs:
commit: ${{ steps.extract_build_info.outputs.commit }} commit: ${{ steps.extract_build_info.outputs.commit }}
commit_long: ${{ steps.extract_build_info.outputs.commit_long }} commit_long: ${{ steps.extract_build_info.outputs.commit_long }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# Important so that build number generation works # Important so that build number generation works
fetch-depth: 0 fetch-depth: 0
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
path: | path: |
/nix /nix
- uses: cachix/install-nix-action@19effe9fe722874e6d46dd7182e4b8b7a43c4a99 # v31.10.0 - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -75,7 +75,7 @@ jobs:
needs: [setup, build-macos] needs: [setup, build-macos]
if: needs.setup.outputs.should_skip != 'true' if: needs.setup.outputs.should_skip != 'true'
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Tip Tag - name: Tip Tag
run: | run: |
git config user.name "github-actions[bot]" git config user.name "github-actions[bot]"
@ -90,7 +90,7 @@ jobs:
env: env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }} GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Install sentry-cli - name: Install sentry-cli
run: | run: |
@ -113,7 +113,7 @@ jobs:
env: env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }} GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Install sentry-cli - name: Install sentry-cli
run: | run: |
@ -136,7 +136,7 @@ jobs:
env: env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }} GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Install sentry-cli - name: Install sentry-cli
run: | run: |
@ -163,22 +163,22 @@ jobs:
github.ref_name == 'main' github.ref_name == 'main'
) )
) )
runs-on: namespace-profile-ghostty-md runs-on: namespace-profile-ghostty-sm
env: env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
path: | path: |
/nix /nix
/zig /zig
- uses: cachix/install-nix-action@19effe9fe722874e6d46dd7182e4b8b7a43c4a99 # v31.10.0 - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -195,7 +195,7 @@ jobs:
nix develop -c minisign -S -m ghostty-source.tar.gz -s minisign.key < minisign.password nix develop -c minisign -S -m ghostty-source.tar.gz -s minisign.key < minisign.password
- name: Update Release - name: Update Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with: with:
name: 'Ghostty Tip ("Nightly")' name: 'Ghostty Tip ("Nightly")'
prerelease: true prerelease: true
@ -206,6 +206,165 @@ jobs:
ghostty-source.tar.gz.minisig ghostty-source.tar.gz.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }} token: ${{ secrets.GH_RELEASE_TOKEN }}
source-tarball-lib-vt:
needs: [setup]
if: |
needs.setup.outputs.should_skip != 'true' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.repository_owner == 'ghostty-org' &&
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-sm
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Create Tarball
run: |
rm -rf zig-out/dist
nix develop -c zig build dist -Demit-lib-vt=true
cp zig-out/dist/*.tar.gz libghostty-vt-source.tar.gz
- name: Sign Tarball
run: |
echo -n "${{ secrets.MINISIGN_KEY }}" > minisign.key
echo -n "${{ secrets.MINISIGN_PASSWORD }}" > minisign.password
nix develop -c minisign -S -m libghostty-vt-source.tar.gz -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
tag_name: tip
target_commitish: ${{ github.sha }}
files: |
libghostty-vt-source.tar.gz
libghostty-vt-source.tar.gz.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
- name: Prep R2 Storage
run: |
mkdir -p blob/${GHOSTTY_COMMIT_LONG}
cp libghostty-vt-source.tar.gz blob/${GHOSTTY_COMMIT_LONG}/libghostty-vt-source.tar.gz
- name: Upload to R2
uses: ryand56/r2-upload-action@b801a390acbdeb034c5e684ff5e1361c06639e7c # v1.4
with:
r2-account-id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
r2-access-key-id: ${{ secrets.CF_R2_TIP_AWS_KEY }}
r2-secret-access-key: ${{ secrets.CF_R2_TIP_SECRET_KEY }}
r2-bucket: ghostty-tip
source-dir: blob
destination-dir: ./
- name: Echo Release URLs
run: |
echo "Release URLs:"
echo " Source Tarball: https://tip.files.ghostty.org/${GHOSTTY_COMMIT_LONG}/libghostty-vt-source.tar.gz"
build-lib-vt-xcframework:
needs: [setup]
if: |
needs.setup.outputs.should_skip != 'true' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.repository_owner == 'ghostty-org' &&
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-macos-tahoe
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
ZIG_LOCAL_CACHE_DIR: /Users/runner/zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with:
cache: |
xcode
path: |
/Users/runner/zig
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Xcode Select
run: sudo xcode-select -s /Applications/Xcode_26.3.app
- name: Build XCFramework
run: nix develop -c zig build -Demit-lib-vt -Doptimize=ReleaseFast
- name: Zip XCFramework
run: |
cd zig-out/lib
zip -9 -r ../../ghostty-vt.xcframework.zip ghostty-vt.xcframework
- name: Sign XCFramework
run: |
echo -n "${{ secrets.MINISIGN_KEY }}" > minisign.key
echo -n "${{ secrets.MINISIGN_PASSWORD }}" > minisign.password
nix develop -c minisign -S -m ghostty-vt.xcframework.zip -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
tag_name: tip
target_commitish: ${{ github.sha }}
files: |
ghostty-vt.xcframework.zip
ghostty-vt.xcframework.zip.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
- name: Prep R2 Storage
run: |
mkdir -p blob/${GHOSTTY_COMMIT_LONG}
cp ghostty-vt.xcframework.zip blob/${GHOSTTY_COMMIT_LONG}/ghostty-vt.xcframework.zip
- name: Upload to R2
uses: ryand56/r2-upload-action@b801a390acbdeb034c5e684ff5e1361c06639e7c # v1.4
with:
r2-account-id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
r2-access-key-id: ${{ secrets.CF_R2_TIP_AWS_KEY }}
r2-secret-access-key: ${{ secrets.CF_R2_TIP_SECRET_KEY }}
r2-bucket: ghostty-tip
source-dir: blob
destination-dir: ./
- name: Echo Release URLs
run: |
echo "Release URLs:"
echo " XCFramework: https://tip.files.ghostty.org/${GHOSTTY_COMMIT_LONG}/ghostty-vt.xcframework.zip"
build-macos: build-macos:
needs: [setup] needs: [setup]
if: | if: |
@ -228,13 +387,13 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# Important so that build number generation works # Important so that build number generation works
fetch-depth: 0 fetch-depth: 0
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
cache: | cache: |
xcode xcode
@ -245,13 +404,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/nix-installer-action@main
with: with:
determinate: true determinate: true
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select - name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.2.app run: sudo xcode-select -s /Applications/Xcode_26.3.app
- name: Xcode Version - name: Xcode Version
run: xcodebuild -version run: xcodebuild -version
@ -378,7 +537,7 @@ jobs:
# Update Release # Update Release
- name: Release - name: Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with: with:
name: 'Ghostty Tip ("Nightly")' name: 'Ghostty Tip ("Nightly")'
prerelease: true prerelease: true
@ -456,7 +615,7 @@ jobs:
EOF EOF
- name: Upload Release URLs - name: Upload Release URLs
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v6.0
with: with:
name: release-urls-${{ inputs.pr || '0' }} name: release-urls-${{ inputs.pr || '0' }}
path: release-urls.txt path: release-urls.txt
@ -484,13 +643,13 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# Important so that build number generation works # Important so that build number generation works
fetch-depth: 0 fetch-depth: 0
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
cache: | cache: |
xcode xcode
@ -501,13 +660,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/nix-installer-action@main
with: with:
determinate: true determinate: true
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select - name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.2.app run: sudo xcode-select -s /Applications/Xcode_26.3.app
- name: Xcode Version - name: Xcode Version
run: xcodebuild -version run: xcodebuild -version
@ -627,7 +786,7 @@ jobs:
# Update Release # Update Release
- name: Release - name: Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with: with:
name: 'Ghostty Tip ("Nightly")' name: 'Ghostty Tip ("Nightly")'
prerelease: true prerelease: true
@ -681,13 +840,13 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# Important so that build number generation works # Important so that build number generation works
fetch-depth: 0 fetch-depth: 0
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
cache: | cache: |
xcode xcode
@ -698,13 +857,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/nix-installer-action@main
with: with:
determinate: true determinate: true
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select - name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.2.app run: sudo xcode-select -s /Applications/Xcode_26.3.app
- name: Xcode Version - name: Xcode Version
run: xcodebuild -version run: xcodebuild -version
@ -824,7 +983,7 @@ jobs:
# Update Release # Update Release
- name: Release - name: Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with: with:
name: 'Ghostty Tip ("Nightly")' name: 'Ghostty Tip ("Nightly")'
prerelease: true prerelease: true

View File

@ -26,7 +26,7 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps: steps:
- name: Download Source Tarball Artifacts - name: Download Source Tarball Artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
run-id: ${{ inputs.source-run-id }} run-id: ${{ inputs.source-run-id }}
artifact-ids: ${{ inputs.source-artifact-id }} artifact-ids: ${{ inputs.source-artifact-id }}
@ -38,7 +38,7 @@ jobs:
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
path: | path: |
/nix /nix

File diff suppressed because it is too large Load Diff

View File

@ -17,22 +17,22 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Cache - name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with: with:
path: | path: |
/nix /nix
/zig /zig
- name: Setup Nix - name: Setup Nix
uses: cachix/install-nix-action@19effe9fe722874e6d46dd7182e4b8b7a43c4a99 # v31.10.0 uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: ghostty name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -79,7 +79,7 @@ jobs:
run: nix build .#ghostty run: nix build .#ghostty
- name: Create pull request - name: Create pull request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with: with:
title: Update iTerm2 colorschemes title: Update iTerm2 colorschemes
base: main base: main

View File

@ -8,15 +8,21 @@ jobs:
check: check:
runs-on: namespace-profile-ghostty-xsm runs-on: namespace-profile-ghostty-xsm
steps: steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token id: app-token
with: with:
app-id: ${{ secrets.VOUCH_APP_ID }} app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }} private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: mitchellh/vouch/action/check-issue@c6d80ead49839655b61b422700b7a3bc9d0804a9 # v1.4.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout: .github/issue-unvouched-message
- uses: mitchellh/vouch/action/check-issue@52aec3d64655edf2fdb58f298e02da754a056daf # unreleased main
with: with:
issue-number: ${{ github.event.issue.number }} issue-number: ${{ github.event.issue.number }}
auto-close: true auto-close: true
auto-lock: true
template-file: .github/issue-unvouched-message
env: env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}

View File

@ -8,7 +8,7 @@ jobs:
check: check:
runs-on: namespace-profile-ghostty-xsm runs-on: namespace-profile-ghostty-xsm
steps: steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token id: app-token
with: with:
app-id: ${{ secrets.VOUCH_APP_ID }} app-id: ${{ secrets.VOUCH_APP_ID }}

View File

@ -12,13 +12,13 @@ jobs:
manage: manage:
runs-on: namespace-profile-ghostty-xsm runs-on: namespace-profile-ghostty-xsm
steps: steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token id: app-token
with: with:
app-id: ${{ secrets.VOUCH_APP_ID }} app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }} private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
token: ${{ steps.app-token.outputs.token }} token: ${{ steps.app-token.outputs.token }}

View File

@ -12,13 +12,13 @@ jobs:
manage: manage:
runs-on: namespace-profile-ghostty-xsm runs-on: namespace-profile-ghostty-xsm
steps: steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token id: app-token
with: with:
app-id: ${{ secrets.VOUCH_APP_ID }} app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }} private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
token: ${{ steps.app-token.outputs.token }} token: ${{ steps.app-token.outputs.token }}

View File

@ -13,13 +13,13 @@ jobs:
sync: sync:
runs-on: namespace-profile-ghostty-xsm runs-on: namespace-profile-ghostty-xsm
steps: steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token id: app-token
with: with:
app-id: ${{ secrets.VOUCH_APP_ID }} app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }} private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
token: ${{ steps.app-token.outputs.token }} token: ${{ steps.app-token.outputs.token }}

3
.gitignore vendored
View File

@ -10,6 +10,9 @@
zig-cache/ zig-cache/
.zig-cache/ .zig-cache/
zig-out/ zig-out/
build-cmake/
CMakeCache.txt
CMakeFiles/
/build.zig.zon.bak /build.zig.zon.bak
/result* /result*
/.nixos-test-history /.nixos-test-history

View File

@ -26,3 +26,6 @@ website/.next
# fuzz corpus files # fuzz corpus files
test/fuzz-libghostty/corpus/ test/fuzz-libghostty/corpus/
test/fuzz-libghostty/afl-out/ test/fuzz-libghostty/afl-out/
# Swift example build outputs
example/swift-vt-xcframework/.build/

View File

@ -13,9 +13,18 @@ A file for [guiding coding agents](https://agents.md/).
test suite is slow to run. test suite is slow to run.
- **Test filter (Zig)**: `zig build test -Dtest-filter=<test name>` - **Test filter (Zig)**: `zig build test -Dtest-filter=<test name>`
- **Formatting (Zig)**: `zig fmt .` - **Formatting (Zig)**: `zig fmt .`
- **Formatting (Swift)**: `swiftlint lint --fix` - **Formatting (Swift)**: `swiftlint lint --strict --fix`
- **Formatting (other)**: `prettier -w .` - **Formatting (other)**: `prettier -w .`
## libghostty-vt
- Build: `zig build -Demit-lib-vt`
- Build WASM: `zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall`
- Test: `zig build test-lib-vt -Dtest-filter=<filter>`
- Prefer this when the change is in a libghostty-vt file
- All C enums in `include/ghostty/vt/` must have a `_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE`
sentinel as the last entry to force int enum sizing (pre-C23 portability).
## Directory Structure ## Directory Structure
- Shared Zig core: `src/` - Shared Zig core: `src/`

1
CLAUDE.md Symbolic link
View File

@ -0,0 +1 @@
AGENTS.md

377
CMakeLists.txt Normal file
View File

@ -0,0 +1,377 @@
# CMake wrapper for libghostty-vt
#
# This file delegates to `zig build -Demit-lib-vt` to produce the shared library,
# headers, and pkg-config file. It exists so that CMake-based projects can
# consume libghostty-vt without interacting with the Zig build system
# directly. However, downstream users do still require `zig` on the PATH.
# Please consult the Ghostty docs for the required Zig version:
#
# https://ghostty.org/docs/install/build
#
# Building within the Ghostty repo
# ---------------------------------
#
# cmake -B build
# cmake --build build
# cmake --install build --prefix /usr/local
#
# Pass extra flags to the Zig build with GHOSTTY_ZIG_BUILD_FLAGS:
#
# cmake -B build -DGHOSTTY_ZIG_BUILD_FLAGS="-Demit-macos-app=false"
#
# Integrating into a downstream CMake project
# ---------------------------------------------
#
# Option 1 FetchContent (recommended, no manual install step):
#
# include(FetchContent)
# FetchContent_Declare(ghostty
# GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
# GIT_TAG main
# )
# FetchContent_MakeAvailable(ghostty)
#
# target_link_libraries(myapp PRIVATE ghostty-vt) # shared
# target_link_libraries(myapp PRIVATE ghostty-vt-static) # static
#
# To use a local checkout instead of fetching:
#
# cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=/path/to/ghostty
#
# Option 2 find_package (after installing to a prefix):
#
# find_package(ghostty-vt REQUIRED)
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt) # shared
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt-static) # static
#
# Cross-compilation
# -------------------
#
# For building libghostty-vt for a non-native Zig target (e.g. cross-
# compiling), use the ghostty_vt_add_target() function after FetchContent:
#
# FetchContent_MakeAvailable(ghostty)
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
#
# target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64) # static
# target_link_libraries(myapp PRIVATE ghostty-vt-linux-amd64) # shared
#
# This handles zig discovery, build-type-to-optimize mapping, and output
# path conventions internally. Extra flags can be forwarded with ZIG_FLAGS:
#
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu
# ZIG_FLAGS -Dsimd=false)
#
# See dist/cmake/README.md for more details, example/c-vt-cmake/ for a
# complete working example, and example/c-vt-cmake-cross/ for a cross-
# compilation example.
cmake_minimum_required(VERSION 3.19)
project(ghostty-vt VERSION 0.1.0 LANGUAGES C)
# --- Options ----------------------------------------------------------------
set(GHOSTTY_ZIG_BUILD_FLAGS "" CACHE STRING "Additional flags to pass to zig build")
# Map CMake build types to Zig optimization levels. The result is stored in
# _GHOSTTY_ZIG_OPT_FLAG so both the native build and ghostty_vt_add_target()
# can reuse it without duplicating the mapping logic.
set(_GHOSTTY_ZIG_OPT_FLAG "")
if(CMAKE_BUILD_TYPE)
string(TOUPPER "${CMAKE_BUILD_TYPE}" _bt)
if(_bt STREQUAL "RELEASE" OR _bt STREQUAL "MINSIZEREL" OR _bt STREQUAL "RELWITHDEBINFO")
set(_GHOSTTY_ZIG_OPT_FLAG "-Doptimize=ReleaseFast")
endif()
unset(_bt)
endif()
if(_GHOSTTY_ZIG_OPT_FLAG)
list(APPEND GHOSTTY_ZIG_BUILD_FLAGS "${_GHOSTTY_ZIG_OPT_FLAG}")
endif()
# --- Find Zig ----------------------------------------------------------------
find_program(ZIG_EXECUTABLE zig REQUIRED)
message(STATUS "Found zig: ${ZIG_EXECUTABLE}")
# --- Build via zig build -----------------------------------------------------
# The zig build installs into zig-out/ relative to the source tree.
set(ZIG_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zig-out")
# Shared library names (zig build produces both shared and static).
if(APPLE)
set(GHOSTTY_VT_LIBNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(GHOSTTY_VT_SONAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt.0${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(GHOSTTY_VT_REALNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt.0.1.0${CMAKE_SHARED_LIBRARY_SUFFIX}")
elseif(WIN32)
set(GHOSTTY_VT_LIBNAME "ghostty-vt.dll")
set(GHOSTTY_VT_REALNAME "ghostty-vt.dll")
set(GHOSTTY_VT_IMPLIB "ghostty-vt.lib")
else()
set(GHOSTTY_VT_LIBNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(GHOSTTY_VT_SONAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}.0")
set(GHOSTTY_VT_REALNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}.0.1.0")
endif()
if(WIN32)
set(GHOSTTY_VT_SHARED_LIBRARY "${ZIG_OUT_DIR}/bin/${GHOSTTY_VT_REALNAME}")
else()
set(GHOSTTY_VT_SHARED_LIBRARY "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_REALNAME}")
endif()
# Static library name.
# On Windows, the static lib is named "ghostty-vt-static.lib" to avoid
# colliding with the DLL import library "ghostty-vt.lib".
if(WIN32)
set(GHOSTTY_VT_STATIC_REALNAME "ghostty-vt-static.lib")
else()
set(GHOSTTY_VT_STATIC_REALNAME "libghostty-vt.a")
endif()
set(GHOSTTY_VT_STATIC_LIBRARY "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_STATIC_REALNAME}")
# Ensure the output directories exist so CMake doesn't reject the
# INTERFACE_INCLUDE_DIRECTORIES before the zig build has run.
file(MAKE_DIRECTORY "${ZIG_OUT_DIR}/include")
# Custom command: run zig build -Demit-lib-vt (produces both shared and static)
add_custom_command(
OUTPUT "${GHOSTTY_VT_SHARED_LIBRARY}" "${GHOSTTY_VT_STATIC_LIBRARY}" "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}"
COMMAND "${ZIG_EXECUTABLE}" build -Demit-lib-vt ${GHOSTTY_ZIG_BUILD_FLAGS}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Building libghostty-vt via zig build..."
USES_TERMINAL
)
add_custom_target(zig_build_lib_vt ALL
DEPENDS "${GHOSTTY_VT_SHARED_LIBRARY}" "${GHOSTTY_VT_STATIC_LIBRARY}"
)
# Tell CMake's clean target to also remove Zig's output directory.
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_CLEAN_FILES "${ZIG_OUT_DIR}"
)
# --- IMPORTED library targets ------------------------------------------------
# Shared
add_library(ghostty-vt SHARED IMPORTED GLOBAL)
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_LOCATION "${GHOSTTY_VT_SHARED_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${ZIG_OUT_DIR}/include"
)
if(APPLE)
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_SONAME "@rpath/${GHOSTTY_VT_SONAME}"
)
elseif(WIN32)
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_IMPLIB "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}"
)
else()
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_SONAME "${GHOSTTY_VT_SONAME}"
)
endif()
add_dependencies(ghostty-vt zig_build_lib_vt)
# Static
#
# On Linux and macOS, the static library is a fat archive that bundles
# the vendored SIMD dependencies (highway, simdutf). Consumers
# only need to link libc.
#
# On Windows, the SIMD dependencies are not bundled and must be linked
# separately.
#
# Building with -Dsimd=false removes all runtime dependencies.
add_library(ghostty-vt-static STATIC IMPORTED GLOBAL)
set_target_properties(ghostty-vt-static PROPERTIES
IMPORTED_LOCATION "${GHOSTTY_VT_STATIC_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${ZIG_OUT_DIR}/include"
INTERFACE_COMPILE_DEFINITIONS "GHOSTTY_STATIC"
)
if(WIN32)
# On Windows, the Zig standard library uses NT API functions
# (NtClose, NtCreateSection, etc.) and kernel32 functions that
# consumers must link when using the static library.
set_target_properties(ghostty-vt-static PROPERTIES
INTERFACE_LINK_LIBRARIES "ntdll;kernel32"
)
endif()
add_dependencies(ghostty-vt-static zig_build_lib_vt)
# --- Install ------------------------------------------------------------------
include(GNUInstallDirs)
# Install shared library
if(WIN32)
# On Windows, install the DLL and PDB to bin/ and the import library to lib/
install(FILES "${GHOSTTY_VT_SHARED_LIBRARY}" "${ZIG_OUT_DIR}/bin/ghostty-vt.pdb" TYPE BIN)
install(FILES "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}" TYPE LIB)
else()
install(FILES "${GHOSTTY_VT_SHARED_LIBRARY}" TYPE LIB)
# Install symlinks
install(CODE "
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
\"${GHOSTTY_VT_REALNAME}\"
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${GHOSTTY_VT_SONAME}\")
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
\"${GHOSTTY_VT_SONAME}\"
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${GHOSTTY_VT_LIBNAME}\")
")
endif()
# Install static library
install(FILES "${GHOSTTY_VT_STATIC_LIBRARY}" TYPE LIB)
# Install headers
install(DIRECTORY "${ZIG_OUT_DIR}/include/ghostty" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
# --- CMake package config for find_package() ----------------------------------
include(CMakePackageConfigHelpers)
# Generate the config file
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/dist/cmake/ghostty-vt-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghostty-vt"
)
# Generate the version file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config-version.cmake"
VERSION "${PROJECT_VERSION}"
COMPATIBILITY SameMajorVersion
)
# Install the config files
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghostty-vt"
)
# --- Cross-compilation helper ------------------------------------------------
#
# For downstream projects that need to build libghostty-vt for a specific
# Zig target triple. For native builds, use the IMPORTED targets above
# (ghostty-vt, ghostty-vt-static) directly.
#
# Usage (in a downstream CMakeLists.txt after FetchContent_MakeAvailable):
#
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
#
# Creates:
# ghostty-vt-static-linux-amd64 (IMPORTED STATIC library)
# ghostty-vt-linux-amd64 (IMPORTED SHARED library)
#
# Optional ZIG_FLAGS to pass additional flags to zig build:
#
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu
# ZIG_FLAGS -Dsimd=false)
function(ghostty_vt_add_target)
cmake_parse_arguments(PARSE_ARGV 0 _GVT "" "NAME;ZIG_TARGET" "ZIG_FLAGS")
if(NOT _GVT_NAME)
message(FATAL_ERROR "ghostty_vt_add_target: NAME is required")
endif()
if(NOT _GVT_ZIG_TARGET)
message(FATAL_ERROR "ghostty_vt_add_target: ZIG_TARGET is required")
endif()
set(_src_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}")
set(_prefix "${CMAKE_CURRENT_BINARY_DIR}/ghostty-${_GVT_NAME}")
# Build flags
set(_flags
-Demit-lib-vt
-Dtarget=${_GVT_ZIG_TARGET}
--prefix "${_prefix}"
)
# Default to ReleaseFast when no build type is set. Debug builds enable
# UBSan in zig, and the sanitizer runtime is not available for all
# cross-compilation targets.
if(_GHOSTTY_ZIG_OPT_FLAG)
list(APPEND _flags "${_GHOSTTY_ZIG_OPT_FLAG}")
else()
list(APPEND _flags "-Doptimize=ReleaseFast")
endif()
if(_GVT_ZIG_FLAGS)
list(APPEND _flags ${_GVT_ZIG_FLAGS})
endif()
# Output paths
set(_include_dir "${_prefix}/include")
if(_GVT_ZIG_TARGET MATCHES "windows")
set(_static_lib "${_prefix}/lib/ghostty-vt-static.lib")
set(_shared_lib "${_prefix}/bin/ghostty-vt.dll")
set(_implib "${_prefix}/lib/ghostty-vt.lib")
elseif(_GVT_ZIG_TARGET MATCHES "darwin|macos")
set(_static_lib "${_prefix}/lib/libghostty-vt.a")
set(_shared_lib "${_prefix}/lib/libghostty-vt.0.1.0.dylib")
else()
set(_static_lib "${_prefix}/lib/libghostty-vt.a")
set(_shared_lib "${_prefix}/lib/libghostty-vt.so.0.1.0")
endif()
file(MAKE_DIRECTORY "${_include_dir}")
# Custom command: invoke zig build
add_custom_command(
OUTPUT "${_static_lib}" "${_shared_lib}"
COMMAND "${ZIG_EXECUTABLE}" build ${_flags}
WORKING_DIRECTORY "${_src_dir}"
COMMENT "Building libghostty-vt for ${_GVT_ZIG_TARGET}..."
USES_TERMINAL
)
set(_build_target "zig_build_lib_vt_${_GVT_NAME}")
add_custom_target(${_build_target} ALL
DEPENDS "${_static_lib}" "${_shared_lib}"
)
# Static target
set(_static_target "ghostty-vt-static-${_GVT_NAME}")
add_library(${_static_target} STATIC IMPORTED GLOBAL)
set_target_properties(${_static_target} PROPERTIES
IMPORTED_LOCATION "${_static_lib}"
INTERFACE_INCLUDE_DIRECTORIES "${_include_dir}"
INTERFACE_COMPILE_DEFINITIONS "GHOSTTY_STATIC"
)
if(_GVT_ZIG_TARGET MATCHES "windows")
set_target_properties(${_static_target} PROPERTIES
INTERFACE_LINK_LIBRARIES "ntdll;kernel32"
)
endif()
add_dependencies(${_static_target} ${_build_target})
# Shared target
set(_shared_target "ghostty-vt-${_GVT_NAME}")
add_library(${_shared_target} SHARED IMPORTED GLOBAL)
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_LOCATION "${_shared_lib}"
INTERFACE_INCLUDE_DIRECTORIES "${_include_dir}"
)
if(_GVT_ZIG_TARGET MATCHES "windows")
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_IMPLIB "${_implib}"
)
elseif(_GVT_ZIG_TARGET MATCHES "darwin|macos")
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_SONAME "@rpath/libghostty-vt.0.dylib"
)
else()
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_SONAME "libghostty-vt.so.0"
)
endif()
add_dependencies(${_shared_target} ${_build_target})
endfunction()

View File

@ -162,14 +162,17 @@
/src/surface_mouse.zig @ghostty-org/terminal /src/surface_mouse.zig @ghostty-org/terminal
# Localization # Localization
/po/README_TRANSLATORS.md @ghostty-org/localization /po/README_TRANSLATORS.md @ghostty-org/manager # *localization* manager.
/po/com.mitchellh.ghostty.pot @ghostty-org/localization /po/com.mitchellh.ghostty.pot @ghostty-org/manager
/src/os/i18n_locales.zig @ghostty-org/manager
/po/be.po @ghostty-org/be_BY
/po/bg.po @ghostty-org/bg_BG /po/bg.po @ghostty-org/bg_BG
/po/ca.po @ghostty-org/ca_ES /po/ca.po @ghostty-org/ca_ES
/po/de.po @ghostty-org/de_DE /po/de.po @ghostty-org/de_DE
/po/es_AR.po @ghostty-org/es_AR /po/es_AR.po @ghostty-org/es_AR
/po/es_BO.po @ghostty-org/es_BO /po/es_BO.po @ghostty-org/es_BO
/po/es_ES.po @ghostty-org/es_ES /po/es_ES.po @ghostty-org/es_ES
/po/eu.po @ghostty-org/eu_ES
/po/fr.po @ghostty-org/fr_FR /po/fr.po @ghostty-org/fr_FR
/po/ga.po @ghostty-org/ga_IE /po/ga.po @ghostty-org/ga_IE
/po/he.po @ghostty-org/he_IL /po/he.po @ghostty-org/he_IL

View File

@ -177,11 +177,6 @@ item is identified, it is moved to the issue tracker. **This pattern
makes it easier for maintainers or contributors to find issues to work on makes it easier for maintainers or contributors to find issues to work on
since _every issue_ is ready to be worked on.** since _every issue_ is ready to be worked on.**
If you are experiencing a bug and have clear steps to reproduce it, please
open an issue. If you are experiencing a bug but you are not sure how to
reproduce it or aren't sure if it's a bug, please open a discussion.
If you have an idea for a feature, please open a discussion.
### Pull Requests Implement an Issue ### Pull Requests Implement an Issue
Pull requests should be associated with a previously accepted issue. Pull requests should be associated with a previously accepted issue.

View File

@ -67,6 +67,14 @@ sudo xcode-select --switch /Applications/Xcode.app
> You do not need to be running on macOS 26 to build Ghostty, you can > You do not need to be running on macOS 26 to build Ghostty, you can
> still use Xcode 26 on macOS 15 stable. > still use Xcode 26 on macOS 15 stable.
> [!WARNING]
>
> Zig 0.15.x has a [known linking issue](https://codeberg.org/ziglang/zig/issues/31658)
> with **Xcode 26.4**. If you are on Xcode 26.4, you must use a
> Homebrew-installed Zig (`brew install zig@0.15`) or our Nix flake,
> both of which contain a patch that works around the issue. Alternatively,
> you can downgrade to **Xcode 26.3**.
## AI and Agents ## AI and Agents
If you're using AI assistance with Ghostty, Ghostty provides an If you're using AI assistance with Ghostty, Ghostty provides an

145
README.md
View File

@ -7,6 +7,8 @@
<p align="center"> <p align="center">
Fast, native, feature-rich terminal emulator pushing modern features. Fast, native, feature-rich terminal emulator pushing modern features.
<br /> <br />
A native GUI or embeddable library via <code>libghostty</code>.
<br />
<a href="#about">About</a> <a href="#about">About</a>
· ·
<a href="https://ghostty.org/download">Download</a> <a href="https://ghostty.org/download">Download</a>
@ -26,20 +28,13 @@ fast, feature-rich, and native. While there are many excellent terminal
emulators available, they all force you to choose between speed, emulators available, they all force you to choose between speed,
features, or native UIs. Ghostty provides all three. features, or native UIs. Ghostty provides all three.
In all categories, I am not trying to claim that Ghostty is the **`libghostty`** is a cross-platform, zero-dependency C and Zig library
best (i.e. the fastest, most feature-rich, or most native). But for building terminal emulators or utilizing terminal functionality
Ghostty is competitive in all three categories and Ghostty (such as style parsing). Anyone can use `libghostty` to build a terminal
doesn't make you choose between them. emulator or embed a terminal into their own applications. See
[Ghostling](https://github.com/ghostty-org/ghostling) for a minimal complete project
Ghostty also intends to push the boundaries of what is possible with a example or the [`examples` directory](https://github.com/ghostty-org/ghostty/tree/main/example)
terminal emulator by exposing modern, opt-in features that enable CLI tool for smaller examples of using `libghostty` in C and Zig.
developers to build more feature rich, interactive applications.
While aiming for this ambitious goal, our first step is to make Ghostty
one of the best fully standards compliant terminal emulator, remaining
compatible with all existing shells and software while supporting all of
the latest terminal innovations in the ecosystem. You can use Ghostty
as a drop-in replacement for your existing terminal emulator.
For more details, see [About Ghostty](https://ghostty.org/docs/about). For more details, see [About Ghostty](https://ghostty.org/docs/about).
@ -61,30 +56,37 @@ to get involved with Ghostty's development as well should also read the
## Roadmap and Status ## Roadmap and Status
Ghostty is stable and in use by millions of people and machines daily.
The high-level ambitious plan for the project, in order: The high-level ambitious plan for the project, in order:
| # | Step | Status | | # | Step | Status |
| :-: | --------------------------------------------------------- | :----: | | :-: | ------------------------------------------------------- | :----: |
| 1 | Standards-compliant terminal emulation | ✅ | | 1 | Standards-compliant terminal emulation | ✅ |
| 2 | Competitive performance | ✅ | | 2 | Competitive performance | ✅ |
| 3 | Basic customizability -- fonts, bg colors, etc. | ✅ | | 3 | Rich windowing features -- multi-window, tabbing, panes | ✅ |
| 4 | Richer windowing features -- multi-window, tabbing, panes | ✅ | | 4 | Native Platform Experiences | ✅ |
| 5 | Native Platform Experiences (i.e. Mac Preference Panel) | ⚠️ | | 5 | Cross-platform `libghostty` for Embeddable Terminals | ✅ |
| 6 | Cross-platform `libghostty` for Embeddable Terminals | ⚠️ | | 6 | Ghostty-only Terminal Control Sequences | ❌ |
| 7 | Windows Terminals (including PowerShell, Cmd, WSL) | ❌ |
| N | Fancy features (to be expanded upon later) | ❌ |
Additional details for each step in the big roadmap below: Additional details for each step in the big roadmap below:
#### Standards-Compliant Terminal Emulation #### Standards-Compliant Terminal Emulation
Ghostty implements enough control sequences to be used by hundreds of Ghostty implements all of the regularly used control sequences and
testers daily for over the past year. Further, we've done a can run every mainstream terminal program without issue. For legacy sequences,
[comprehensive xterm audit](https://github.com/ghostty-org/ghostty/issues/632) we've done a [comprehensive xterm audit](https://github.com/ghostty-org/ghostty/issues/632)
comparing Ghostty's behavior to xterm and building a set of conformance comparing Ghostty's behavior to xterm and building a set of conformance
test cases. test cases.
We believe Ghostty is one of the most compliant terminal emulators available. In addition to legacy sequences (what you'd call real "terminal" emulation),
Ghostty also supports more modern sequences than almost any other terminal
emulator. These features include things like the Kitty graphics protocol,
Kitty image protocol, clipboard sequences, synchronized rendering,
light/dark mode notifications, and many, many more.
We believe Ghostty is one of the most compliant and feature-rich terminal
emulators available.
Terminal behavior is partially a de jure standard Terminal behavior is partially a de jure standard
(i.e. [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/)) (i.e. [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/))
@ -96,33 +98,30 @@ views as a "standard."
#### Competitive Performance #### Competitive Performance
We need better benchmarks to continuously verify this, but Ghostty is Ghostty is generally in the same performance category as the other highest
generally in the same performance category as the other highest performing performing terminal emulators.
terminal emulators.
For rendering, we have a multi-renderer architecture that uses OpenGL on "The same performance category" means that Ghostty is much faster than
Linux and Metal on macOS. As far as I'm aware, we're the only terminal traditional or "slow" terminals and is within an unnoticeable margin of the
emulator other than iTerm that uses Metal directly. And we're the only well-known "fast" terminals. For example, Ghostty and Alacritty are usually within
terminal emulator that has a Metal renderer that supports ligatures (iTerm a few percentage points of each other on various benchmarks, but are both
uses a CPU renderer if ligatures are enabled). We can maintain around 60fps something like 100x faster than Terminal.app and iTerm. However, Ghostty
under heavy load and much more generally -- though the terminal is is much more feature rich than Alacritty and has a much more native app
usually rendering much lower due to little screen changes. experience.
For IO, we have a dedicated IO thread that maintains very little jitter This performance is achieved through high-level architectural decisions and
under heavy IO load (i.e. `cat <big file>.txt`). On benchmarks for IO, low-level optimizations. At a high-level, Ghostty has a multi-threaded
we're usually within a small margin of other fast terminal emulators. architecture with a dedicated read thread, write thread, and render thread
For example, reading a dump of plain text is 4x faster compared to iTerm and per terminal. Our renderer uses OpenGL on Linux and Metal on macOS.
Kitty, and 2x faster than Terminal.app. Alacritty is very fast but we're still Our read thread has a heavily optimized terminal parser that leverages
around the same speed (give or take) and our app experience is much more CPU-specific SIMD instructions. Etc.
feature rich.
> [!NOTE] #### Rich Windowing Features
> Despite being _very fast_, there is a lot of room for improvement here.
#### Richer Windowing Features
The Mac and Linux (build with GTK) apps support multi-window, tabbing, and The Mac and Linux (build with GTK) apps support multi-window, tabbing, and
splits. splits with additional features such as tab renaming, coloring, etc. These
features allow for a higher degree of organization and customization than
single-window terminals.
#### Native Platform Experiences #### Native Platform Experiences
@ -133,10 +132,15 @@ in Zig but we do a lot of platform-native things:
- The macOS app is a true SwiftUI-based application with all the things you - The macOS app is a true SwiftUI-based application with all the things you
would expect such as real windowing, menu bars, a settings GUI, etc. would expect such as real windowing, menu bars, a settings GUI, etc.
- macOS uses a true Metal renderer with CoreText for font discovery. - macOS uses a true Metal renderer with CoreText for font discovery.
- macOS supports AppleScript, Apple Shortcuts (AppIntents), etc.
- The Linux app is built with GTK. - The Linux app is built with GTK.
- The Linux app integrates deeply with systemd if available for things
like always-on, new windows in a single instance, cgroup isolation, etc.
There are more improvements to be made. The macOS settings window is still Our goal with Ghostty is for users of whatever platform they run Ghostty
a work-in-progress. Similar improvements will follow with Linux. on to think that Ghostty was built for their platform first and maybe even
exclusively. We want Ghostty to feel like a native app on every platform,
for the best definition of "native" on each platform.
#### Cross-platform `libghostty` for Embeddable Terminals #### Cross-platform `libghostty` for Embeddable Terminals
@ -145,21 +149,40 @@ C-compatible library for embedding a fast, feature-rich terminal emulator
in any 3rd party project. This library is called `libghostty`. in any 3rd party project. This library is called `libghostty`.
Due to the scope of this project, we're breaking libghostty down into Due to the scope of this project, we're breaking libghostty down into
separate actually libraries, starting with `libghostty-vt`. The goal of separate libraries, starting with `libghostty-vt`. The goal of
this project is to focus on parsing terminal sequences and maintaining this project is to focus on parsing terminal sequences and maintaining
terminal state. This is covered in more detail in this terminal state. This is covered in more detail in this
[blog post](https://mitchellh.com/writing/libghostty-is-coming). [blog post](https://mitchellh.com/writing/libghostty-is-coming).
`libghostty-vt` is already available and usable today for Zig and C and `libghostty-vt` is already available and usable today for Zig and C and
is compatible for macOS, Linux, Windows, and WebAssembly. At the time of is compatible for macOS, Linux, Windows, and WebAssembly. The functionality
writing this, the API isn't stable yet and we haven't tagged an official is extremely stable (since its been proven in Ghostty GUI for a long time),
release, but the core logic is well proven (since Ghostty uses it) and but the API signatures are still in flux.
we're working hard on it now.
The ultimate goal is not hypothetical! The macOS app is a `libghostty` consumer. `libghostty` is already heavily in use. See [`examples`](https://github.com/ghostty-org/ghostty/tree/main/example)
The macOS app is a native Swift app developed in Xcode and `main()` is for small examples of using `libghostty` in C and Zig or the
within Swift. The Swift app links to `libghostty` and uses the C API to [Ghostling](https://github.com/ghostty-org/ghostling) project for a
render terminals. complete example. See [awesome-libghostty](https://github.com/Uzaaft/awesome-libghostty)
for a list of projects and resources related to `libghostty`.
We haven't tagged libghostty with a version yet and we're still working
on a better docs experience, but our [Doxygen website](https://libghostty.tip.ghostty.org/)
is a good resource for the C API.
#### Ghostty-only Terminal Control Sequences
We want and believe that terminal applications can and should be able
to do so much more. We've worked hard to support a wide variety of modern
sequences created by other terminal emulators towards this end, but we also
want to fill the gaps by creating our own sequences.
We've been hesitant to do this up until now because we don't want to create
more fragmentation in the terminal ecosystem by creating sequences that only
work in Ghostty. But, we do want to balance that with the desire to push the
terminal forward with stagnant standards and the slow pace of change in the
terminal ecosystem.
We haven't done any of this yet.
## Crash Reports ## Crash Reports

124
build.zig
View File

@ -3,11 +3,17 @@ const assert = std.debug.assert;
const builtin = @import("builtin"); const builtin = @import("builtin");
const buildpkg = @import("src/build/main.zig"); const buildpkg = @import("src/build/main.zig");
const appVersion = @import("build.zig.zon").version; /// App version from build.zig.zon.
const minimumZigVersion = @import("build.zig.zon").minimum_zig_version; const app_zon_version = @import("build.zig.zon").version;
/// Libghostty version. We use a separate version from the app.
const lib_version = "0.1.0-dev";
/// Minimum required zig version.
const minimum_zig_version = @import("build.zig.zon").minimum_zig_version;
comptime { comptime {
buildpkg.requireZig(minimumZigVersion); buildpkg.requireZig(minimum_zig_version);
} }
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
@ -15,7 +21,24 @@ pub fn build(b: *std.Build) !void {
// want to know what options are available, you can run `--help` or // want to know what options are available, you can run `--help` or
// you can read `src/build/Config.zig`. // you can read `src/build/Config.zig`.
const config = try buildpkg.Config.init(b, appVersion); // If we have a VERSION file (present in source tarballs) then we
// use that as the version source of truth. Otherwise we fall back
// to what is in the build.zig.zon.
const file_version: ?[]const u8 = if (b.build_root.handle.readFileAlloc(
b.allocator,
"VERSION",
128,
)) |content| std.mem.trim(
u8,
content,
&std.ascii.whitespace,
) else |_| null;
const config = try buildpkg.Config.init(
b,
file_version orelse app_zon_version,
lib_version,
);
const test_filters = b.option( const test_filters = b.option(
[][]const u8, [][]const u8,
"test-filter", "test-filter",
@ -35,7 +58,6 @@ pub fn build(b: *std.Build) !void {
// All our steps which we'll hook up later. The steps are shown // All our steps which we'll hook up later. The steps are shown
// up here just so that they are more self-documenting. // up here just so that they are more self-documenting.
const libvt_step = b.step("lib-vt", "Build libghostty-vt");
const run_step = b.step("run", "Run the app"); const run_step = b.step("run", "Run the app");
const run_valgrind_step = b.step( const run_valgrind_step = b.step(
"run-valgrind", "run-valgrind",
@ -91,16 +113,6 @@ pub fn build(b: *std.Build) !void {
check_step.dependOn(dist.install_step); check_step.dependOn(dist.install_step);
} }
// libghostty (internal, big)
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
b,
&deps,
);
const libghostty_static = try buildpkg.GhosttyLib.initStatic(
b,
&deps,
);
// libghostty-vt // libghostty-vt
const libghostty_vt_shared = shared: { const libghostty_vt_shared = shared: {
if (config.target.result.cpu.arch.isWasm()) { if (config.target.result.cpu.arch.isWasm()) {
@ -115,9 +127,49 @@ pub fn build(b: *std.Build) !void {
&mod, &mod,
); );
}; };
libghostty_vt_shared.install(libvt_step);
libghostty_vt_shared.install(b.getInstallStep()); libghostty_vt_shared.install(b.getInstallStep());
// libghostty-vt static lib
const libghostty_vt_static = try buildpkg.GhosttyLibVt.initStatic(
b,
&mod,
);
if (config.is_dep) {
// If we're a dependency, we need to install everything as-is
// so that dep.artifact("ghostty-vt-static") works.
libghostty_vt_static.install(b.getInstallStep());
} else {
// If we're not a dependency, we rename the static lib to
// be idiomatic. On Windows, we use a distinct name to avoid
// colliding with the DLL import library (ghostty-vt.lib).
const static_lib_name = if (config.target.result.os.tag == .windows)
"ghostty-vt-static.lib"
else
"libghostty-vt.a";
b.getInstallStep().dependOn(&b.addInstallLibFile(
libghostty_vt_static.output,
static_lib_name,
).step);
}
// libghostty-vt xcframework (Apple only, universal binary).
// Only when building on macOS (not cross-compiling) since
// xcodebuild is required.
if (config.emit_lib_vt and
config.emit_xcframework and
builtin.os.tag.isDarwin() and
config.target.result.os.tag.isDarwin())
{
const apple_libs = try buildpkg.GhosttyLibVt.initStaticAppleUniversal(
b,
&config,
&deps,
&mod,
);
const xcframework = buildpkg.GhosttyLibVt.xcframework(&apple_libs, b);
b.getInstallStep().dependOn(xcframework.step);
}
// Helpgen // Helpgen
if (config.emit_helpgen) deps.help_strings.install(); if (config.emit_helpgen) deps.help_strings.install();
@ -128,26 +180,35 @@ pub fn build(b: *std.Build) !void {
resources.install(); resources.install();
if (i18n) |v| v.install(); if (i18n) |v| v.install();
} }
} else { } else if (!config.emit_lib_vt) {
// Libghostty // The macOS Ghostty Library
// //
// Note: libghostty is not stable for general purpose use. It is used // This is NOT libghostty (even though its named that for historical
// heavily by Ghostty on macOS but it isn't built to be reusable yet. // reasons). It is just the glue between Ghostty GUI on macOS and
// As such, these build steps are lacking. For example, the Darwin // the full Ghostty GUI core.
// build only produces an xcframework. const lib_shared = try buildpkg.GhosttyLib.initShared(b, &deps);
const lib_static = try buildpkg.GhosttyLib.initStatic(b, &deps);
// We shouldn't have this guard but we don't currently // We shouldn't have this guard but we don't currently
// build on macOS this way ironically so we need to fix that. // build on macOS this way ironically so we need to fix that.
if (!config.target.result.os.tag.isDarwin()) { if (!config.target.result.os.tag.isDarwin()) {
libghostty_shared.installHeader(); // Only need one header lib_shared.installHeader(); // Only need one header
libghostty_shared.install("libghostty.so"); if (config.target.result.os.tag == .windows) {
libghostty_static.install("libghostty.a"); lib_shared.install("ghostty-internal.dll");
lib_static.install("ghostty-internal-static.lib");
} else {
lib_shared.install("ghostty-internal.so");
lib_static.install("ghostty-internal.a");
}
} }
} }
// macOS only artifacts. These will error if they're initialized for // macOS only artifacts. These will error if they're initialized for
// other targets. // other targets. In lib-vt mode emit_xcframework controls the lib-vt
if (config.target.result.os.tag.isDarwin()) { // xcframework above, not this one.
if (!config.emit_lib_vt and config.target.result.os.tag.isDarwin() and
(config.emit_xcframework or config.emit_macos_app))
{
// Ghostty xcframework // Ghostty xcframework
const xcframework = try buildpkg.GhosttyXCFramework.init( const xcframework = try buildpkg.GhosttyXCFramework.init(
b, b,
@ -202,7 +263,10 @@ pub fn build(b: *std.Build) !void {
// On macOS we can run the macOS app. For "run" we always force // On macOS we can run the macOS app. For "run" we always force
// a native-only build so that we can run as quickly as possible. // a native-only build so that we can run as quickly as possible.
if (config.target.result.os.tag.isDarwin()) { if (!config.emit_lib_vt and
config.target.result.os.tag.isDarwin() and
(config.emit_xcframework or config.emit_macos_app))
{
const xcframework_native = try buildpkg.GhosttyXCFramework.init( const xcframework_native = try buildpkg.GhosttyXCFramework.init(
b, b,
&deps, &deps,
@ -271,8 +335,8 @@ pub fn build(b: *std.Build) !void {
test_lib_vt_step.dependOn(&mod_vt_c_test_run.step); test_lib_vt_step.dependOn(&mod_vt_c_test_run.step);
} }
// Tests // Tests (skip when building libghostty-vt)
{ if (!config.emit_lib_vt) {
// Full unit tests // Full unit tests
const test_exe = b.addTest(.{ const test_exe = b.addTest(.{
.name = "ghostty-test", .name = "ghostty-test",

View File

@ -1,6 +1,6 @@
.{ .{
.name = .ghostty, .name = .ghostty,
.version = "1.3.0", .version = "1.3.2-dev",
.paths = .{""}, .paths = .{""},
.fingerprint = 0x64407a2a0b4147e5, .fingerprint = 0x64407a2a0b4147e5,
.minimum_zig_version = "0.15.2", .minimum_zig_version = "0.15.2",
@ -76,7 +76,6 @@
.opengl = .{ .path = "./pkg/opengl", .lazy = true }, .opengl = .{ .path = "./pkg/opengl", .lazy = true },
.sentry = .{ .path = "./pkg/sentry", .lazy = true }, .sentry = .{ .path = "./pkg/sentry", .lazy = true },
.simdutf = .{ .path = "./pkg/simdutf", .lazy = true }, .simdutf = .{ .path = "./pkg/simdutf", .lazy = true },
.utfcpp = .{ .path = "./pkg/utfcpp", .lazy = true },
.wuffs = .{ .path = "./pkg/wuffs", .lazy = true }, .wuffs = .{ .path = "./pkg/wuffs", .lazy = true },
.zlib = .{ .path = "./pkg/zlib", .lazy = true }, .zlib = .{ .path = "./pkg/zlib", .lazy = true },
@ -91,8 +90,8 @@
.lazy = true, .lazy = true,
}, },
.wayland_protocols = .{ .wayland_protocols = .{
.url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz", .url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
.hash = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S", .hash = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
.lazy = true, .lazy = true,
}, },
.plasma_wayland_protocols = .{ .plasma_wayland_protocols = .{
@ -117,8 +116,8 @@
.apple_sdk = .{ .path = "./pkg/apple-sdk" }, .apple_sdk = .{ .path = "./pkg/apple-sdk" },
.android_ndk = .{ .path = "./pkg/android-ndk" }, .android_ndk = .{ .path = "./pkg/android-ndk" },
.iterm2_themes = .{ .iterm2_themes = .{
.url = "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz", .url = "https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz",
.hash = "N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF", .hash = "N-V-__8AAGi9AwC7QV7hLqjN6iBkXA2y5dxw285nkSLlVB7I",
.lazy = true, .lazy = true,
}, },
}, },

36
build.zig.zon.json generated
View File

@ -32,7 +32,7 @@
"gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-": { "gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-": {
"name": "gobject", "name": "gobject",
"url": "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst", "url": "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst",
"hash": "sha256-2b1DBvAIHY5LhItq3+q9L6tJgi7itnnrSAHc7fXWDEg=" "hash": "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc="
}, },
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": { "N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
"name": "gtk4_layer_shell", "name": "gtk4_layer_shell",
@ -54,10 +54,10 @@
"url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz", "url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
"hash": "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs=" "hash": "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs="
}, },
"N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF": { "N-V-__8AAGi9AwC7QV7hLqjN6iBkXA2y5dxw285nkSLlVB7I": {
"name": "iterm2_themes", "name": "iterm2_themes",
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz", "url": "https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz",
"hash": "sha256-FCALuGoMgUq2lgnVALKAs5a20uuDXt8Gdt5KeJwKqP0=" "hash": "sha256-HGujRdQdWtVIf3GwCgQgjV9lbwWxJSIDJOWq3gOX3kU="
}, },
"N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": { "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": {
"name": "jetbrains_mono", "name": "jetbrains_mono",
@ -72,7 +72,7 @@
"libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs": { "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs": {
"name": "libxev", "name": "libxev",
"url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz", "url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
"hash": "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc=" "hash": "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg="
}, },
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": { "N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
"name": "libxml2", "name": "libxml2",
@ -109,11 +109,6 @@
"url": "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz", "url": "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz",
"hash": "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M=" "hash": "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M="
}, },
"N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH": {
"name": "utfcpp",
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
"hash": "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8="
},
"uucode-0.1.0-ZZjBPj96QADXyt5sqwBJUnhaDYs_qBeeKijZvlRa0eqM": { "uucode-0.1.0-ZZjBPj96QADXyt5sqwBJUnhaDYs_qBeeKijZvlRa0eqM": {
"name": "uucode", "name": "uucode",
"url": "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732", "url": "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732",
@ -122,12 +117,12 @@
"uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9": { "uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9": {
"name": "uucode", "name": "uucode",
"url": "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz", "url": "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz",
"hash": "sha256-0KvuD0+L1urjwFF3fhbnxC2JZKqqAVWRxOVlcD9GX5U=" "hash": "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg="
}, },
"vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": { "vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": {
"name": "vaxis", "name": "vaxis",
"url": "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz", "url": "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz",
"hash": "sha256-LnIzK8icW1Qexua9SHaeHz+3V8QAbz0a+UC1T5sIjvY=" "hash": "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y="
}, },
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": { "N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
"name": "wayland", "name": "wayland",
@ -139,6 +134,11 @@
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz", "url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
"hash": "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg=" "hash": "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg="
}, },
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
"name": "wayland_protocols",
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
},
"N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs": { "N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs": {
"name": "wuffs", "name": "wuffs",
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz", "url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
@ -147,32 +147,32 @@
"z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ": { "z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ": {
"name": "z2d", "name": "z2d",
"url": "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz", "url": "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz",
"hash": "sha256-afIdou/V7gk3/lXE0J5Ir8T7L5GgHvFnyMJ1rgRnl/c=" "hash": "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E="
}, },
"zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh": { "zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh": {
"name": "zf", "name": "zf",
"url": "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz", "url": "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz",
"hash": "sha256-OwFdkorwTp4mJyvBXrTbtNmp1GnrbSkKDdrmc7d8RWg=" "hash": "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY="
}, },
"zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi": { "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi": {
"name": "zig_js", "name": "zig_js",
"url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz", "url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
"hash": "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M=" "hash": "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4="
}, },
"zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": { "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": {
"name": "zig_objc", "name": "zig_objc",
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz", "url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
"hash": "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw=" "hash": "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM="
}, },
"wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": { "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": {
"name": "zig_wayland", "name": "zig_wayland",
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz", "url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
"hash": "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4=" "hash": "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw="
}, },
"zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": { "zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": {
"name": "zigimg", "name": "zigimg",
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz", "url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
"hash": "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM=" "hash": "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A="
}, },
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": { "N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
"name": "zlib", "name": "zlib",

97
build.zig.zon.nix generated
View File

@ -2,10 +2,12 @@
{ {
lib, lib,
linkFarm, linkFarm,
fetchzip,
fetchurl, fetchurl,
fetchgit, fetchgit,
runCommandLocal, runCommandLocal,
zig_0_15, zig_0_15,
zstd,
name ? "zig-packages", name ? "zig-packages",
}: let }: let
unpackZigArtifact = { unpackZigArtifact = {
@ -17,7 +19,7 @@
nativeBuildInputs = [zig_0_15]; nativeBuildInputs = [zig_0_15];
} }
'' ''
hash="$(zig fetch --global-cache-dir "$TMPDIR" ${artifact})" hash="$(cd "$TMPDIR" && zig fetch --global-cache-dir "$TMPDIR" ${artifact})"
mv "$TMPDIR/p/$hash" "$out" mv "$TMPDIR/p/$hash" "$out"
chmod 755 "$out" chmod 755 "$out"
''; '';
@ -26,8 +28,16 @@
name, name,
url, url,
hash, hash,
unpack,
}: let }: let
artifact = fetchurl {inherit url hash;}; artifact =
if unpack
then
fetchzip {
inherit url hash;
nativeBuildInputs = [zstd];
}
else fetchurl {inherit url hash;};
in in
unpackZigArtifact {inherit name artifact;}; unpackZigArtifact {inherit name artifact;};
@ -56,6 +66,7 @@
name, name,
url, url,
hash, hash,
unpack,
}: let }: let
parts = lib.splitString "://" url; parts = lib.splitString "://" url;
proto = builtins.elemAt parts 0; proto = builtins.elemAt parts 0;
@ -70,11 +81,11 @@
url = "https://${path}"; url = "https://${path}";
}; };
http = fetchZig { http = fetchZig {
inherit name hash; inherit name hash unpack;
url = "http://${path}"; url = "http://${path}";
}; };
https = fetchZig { https = fetchZig {
inherit name hash; inherit name hash unpack;
url = "https://${path}"; url = "https://${path}";
}; };
}; };
@ -88,6 +99,7 @@ in
name = "bindings"; name = "bindings";
url = "https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz"; url = "https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz";
hash = "sha256-i/7FAOAJJvZ5hT7iPWfMOS08MYFzPKRwRzhlHT9wuqM="; hash = "sha256-i/7FAOAJJvZ5hT7iPWfMOS08MYFzPKRwRzhlHT9wuqM=";
unpack = false;
}; };
} }
{ {
@ -96,6 +108,7 @@ in
name = "breakpad"; name = "breakpad";
url = "https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz"; url = "https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz";
hash = "sha256-bMqYlD0amQdmzvYQd8Ca/1k4Bj/heh7+EijlQSttatk="; hash = "sha256-bMqYlD0amQdmzvYQd8Ca/1k4Bj/heh7+EijlQSttatk=";
unpack = false;
}; };
} }
{ {
@ -104,6 +117,7 @@ in
name = "fontconfig"; name = "fontconfig";
url = "https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz"; url = "https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz";
hash = "sha256-O6LdkhWHGKzsXKrxpxYEO1qgVcJ7CB2RSvPMtA3OilU="; hash = "sha256-O6LdkhWHGKzsXKrxpxYEO1qgVcJ7CB2RSvPMtA3OilU=";
unpack = false;
}; };
} }
{ {
@ -112,6 +126,7 @@ in
name = "freetype"; name = "freetype";
url = "https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz"; url = "https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz";
hash = "sha256-QnIB9dUVFnDQXB9bRb713aHy592XHvVPD+qqf/0quQw="; hash = "sha256-QnIB9dUVFnDQXB9bRb713aHy592XHvVPD+qqf/0quQw=";
unpack = false;
}; };
} }
{ {
@ -120,6 +135,7 @@ in
name = "gettext"; name = "gettext";
url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz"; url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz";
hash = "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc="; hash = "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc=";
unpack = false;
}; };
} }
{ {
@ -128,6 +144,7 @@ in
name = "glslang"; name = "glslang";
url = "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz"; url = "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz";
hash = "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U="; hash = "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U=";
unpack = false;
}; };
} }
{ {
@ -135,7 +152,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "gobject"; name = "gobject";
url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst"; url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst";
hash = "sha256-2b1DBvAIHY5LhItq3+q9L6tJgi7itnnrSAHc7fXWDEg="; hash = "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc=";
unpack = true;
}; };
} }
{ {
@ -144,6 +162,7 @@ in
name = "gtk4_layer_shell"; name = "gtk4_layer_shell";
url = "https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz"; url = "https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz";
hash = "sha256-mChCgSYKXu9bT2OlXxbEv2p4ihAgptsDfssPcfozaYg="; hash = "sha256-mChCgSYKXu9bT2OlXxbEv2p4ihAgptsDfssPcfozaYg=";
unpack = false;
}; };
} }
{ {
@ -152,6 +171,7 @@ in
name = "harfbuzz"; name = "harfbuzz";
url = "https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz"; url = "https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz";
hash = "sha256-8WNRuv4hRyX+LB1bWfDZPkmQWkskeJn7kNcM/5U6K5s="; hash = "sha256-8WNRuv4hRyX+LB1bWfDZPkmQWkskeJn7kNcM/5U6K5s=";
unpack = false;
}; };
} }
{ {
@ -160,6 +180,7 @@ in
name = "highway"; name = "highway";
url = "https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz"; url = "https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz";
hash = "sha256-h9T4iT704I8iSXNgj/6/lCaKgTgLp5wS6IQZaMgKohI="; hash = "sha256-h9T4iT704I8iSXNgj/6/lCaKgTgLp5wS6IQZaMgKohI=";
unpack = false;
}; };
} }
{ {
@ -168,14 +189,16 @@ in
name = "imgui"; name = "imgui";
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz"; url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz";
hash = "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs="; hash = "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs=";
unpack = false;
}; };
} }
{ {
name = "N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF"; name = "N-V-__8AAGi9AwC7QV7hLqjN6iBkXA2y5dxw285nkSLlVB7I";
path = fetchZigArtifact { path = fetchZigArtifact {
name = "iterm2_themes"; name = "iterm2_themes";
url = "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz"; url = "https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz";
hash = "sha256-FCALuGoMgUq2lgnVALKAs5a20uuDXt8Gdt5KeJwKqP0="; hash = "sha256-HGujRdQdWtVIf3GwCgQgjV9lbwWxJSIDJOWq3gOX3kU=";
unpack = false;
}; };
} }
{ {
@ -184,6 +207,7 @@ in
name = "jetbrains_mono"; name = "jetbrains_mono";
url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz"; url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz";
hash = "sha256-xXppHouCrQmLWWPzlZAy5AOPORCHr3cViFulkEYQXMQ="; hash = "sha256-xXppHouCrQmLWWPzlZAy5AOPORCHr3cViFulkEYQXMQ=";
unpack = false;
}; };
} }
{ {
@ -192,6 +216,7 @@ in
name = "libpng"; name = "libpng";
url = "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz"; url = "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz";
hash = "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo="; hash = "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo=";
unpack = false;
}; };
} }
{ {
@ -199,7 +224,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "libxev"; name = "libxev";
url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz"; url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz";
hash = "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc="; hash = "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg=";
unpack = true;
}; };
} }
{ {
@ -208,6 +234,7 @@ in
name = "libxml2"; name = "libxml2";
url = "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz"; url = "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz";
hash = "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU="; hash = "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU=";
unpack = false;
}; };
} }
{ {
@ -216,6 +243,7 @@ in
name = "nerd_fonts_symbols_only"; name = "nerd_fonts_symbols_only";
url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz"; url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz";
hash = "sha256-EWTRuVbUveJI17LwmYxDzJT1ICQxoVZKeTiVsec7DQQ="; hash = "sha256-EWTRuVbUveJI17LwmYxDzJT1ICQxoVZKeTiVsec7DQQ=";
unpack = false;
}; };
} }
{ {
@ -224,6 +252,7 @@ in
name = "oniguruma"; name = "oniguruma";
url = "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz"; url = "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz";
hash = "sha256-ABqhIC54RI9MC/GkjHblVodrNvFtks4yB+zP1h2Z8qA="; hash = "sha256-ABqhIC54RI9MC/GkjHblVodrNvFtks4yB+zP1h2Z8qA=";
unpack = false;
}; };
} }
{ {
@ -232,6 +261,7 @@ in
name = "pixels"; name = "pixels";
url = "https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz"; url = "https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz";
hash = "sha256-Veg7FtCRCCUCvxSb9FfzH0IJLFmCZQ4/+657SIcb8Ro="; hash = "sha256-Veg7FtCRCCUCvxSb9FfzH0IJLFmCZQ4/+657SIcb8Ro=";
unpack = false;
}; };
} }
{ {
@ -240,6 +270,7 @@ in
name = "plasma_wayland_protocols"; name = "plasma_wayland_protocols";
url = "https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz"; url = "https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz";
hash = "sha256-XFi6IUrNjmvKNCbcCLAixGqN2Zeymhs+KLrfccIN9EE="; hash = "sha256-XFi6IUrNjmvKNCbcCLAixGqN2Zeymhs+KLrfccIN9EE=";
unpack = false;
}; };
} }
{ {
@ -248,6 +279,7 @@ in
name = "sentry"; name = "sentry";
url = "https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz"; url = "https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz";
hash = "sha256-KsZJfMjWGo0xCT5HrduMmyxFsWsHBbszSoNbZCPDGN8="; hash = "sha256-KsZJfMjWGo0xCT5HrduMmyxFsWsHBbszSoNbZCPDGN8=";
unpack = false;
}; };
} }
{ {
@ -256,14 +288,7 @@ in
name = "spirv_cross"; name = "spirv_cross";
url = "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz"; url = "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz";
hash = "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M="; hash = "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M=";
}; unpack = false;
}
{
name = "N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH";
path = fetchZigArtifact {
name = "utfcpp";
url = "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz";
hash = "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8=";
}; };
} }
{ {
@ -272,6 +297,7 @@ in
name = "uucode"; name = "uucode";
url = "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732"; url = "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732";
hash = "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8="; hash = "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8=";
unpack = true;
}; };
} }
{ {
@ -279,7 +305,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "uucode"; name = "uucode";
url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz"; url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz";
hash = "sha256-0KvuD0+L1urjwFF3fhbnxC2JZKqqAVWRxOVlcD9GX5U="; hash = "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg=";
unpack = true;
}; };
} }
{ {
@ -287,7 +314,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "vaxis"; name = "vaxis";
url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz"; url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz";
hash = "sha256-LnIzK8icW1Qexua9SHaeHz+3V8QAbz0a+UC1T5sIjvY="; hash = "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y=";
unpack = true;
}; };
} }
{ {
@ -296,6 +324,7 @@ in
name = "wayland"; name = "wayland";
url = "https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz"; url = "https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz";
hash = "sha256-6kGR1o5DdnflHzqs3ieCmBAUTpMdOXoyfcYDXiw5xQ0="; hash = "sha256-6kGR1o5DdnflHzqs3ieCmBAUTpMdOXoyfcYDXiw5xQ0=";
unpack = false;
}; };
} }
{ {
@ -304,6 +333,16 @@ in
name = "wayland_protocols"; name = "wayland_protocols";
url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz"; url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz";
hash = "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg="; hash = "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg=";
unpack = false;
};
}
{
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
path = fetchZigArtifact {
name = "wayland_protocols";
url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz";
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
unpack = false;
}; };
} }
{ {
@ -312,6 +351,7 @@ in
name = "wuffs"; name = "wuffs";
url = "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz"; url = "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz";
hash = "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="; hash = "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM=";
unpack = false;
}; };
} }
{ {
@ -319,7 +359,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "z2d"; name = "z2d";
url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz"; url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz";
hash = "sha256-afIdou/V7gk3/lXE0J5Ir8T7L5GgHvFnyMJ1rgRnl/c="; hash = "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E=";
unpack = true;
}; };
} }
{ {
@ -327,7 +368,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "zf"; name = "zf";
url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz"; url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz";
hash = "sha256-OwFdkorwTp4mJyvBXrTbtNmp1GnrbSkKDdrmc7d8RWg="; hash = "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY=";
unpack = true;
}; };
} }
{ {
@ -335,7 +377,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "zig_js"; name = "zig_js";
url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz"; url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz";
hash = "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M="; hash = "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4=";
unpack = true;
}; };
} }
{ {
@ -343,7 +386,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "zig_objc"; name = "zig_objc";
url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz"; url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz";
hash = "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw="; hash = "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM=";
unpack = true;
}; };
} }
{ {
@ -351,7 +395,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "zig_wayland"; name = "zig_wayland";
url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz"; url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz";
hash = "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4="; hash = "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw=";
unpack = true;
}; };
} }
{ {
@ -359,7 +404,8 @@ in
path = fetchZigArtifact { path = fetchZigArtifact {
name = "zigimg"; name = "zigimg";
url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz"; url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz";
hash = "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM="; hash = "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A=";
unpack = true;
}; };
} }
{ {
@ -368,6 +414,7 @@ in
name = "zlib"; name = "zlib";
url = "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz"; url = "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz";
hash = "sha256-F+iIY/NgBnKrSRgvIXKBtvxNPHYr3jYZNeQ2qVIU0Fw="; hash = "sha256-F+iIY/NgBnKrSRgvIXKBtvxNPHYr3jYZNeQ2qVIU0Fw=";
unpack = false;
}; };
} }
] ]

4
build.zig.zon.txt generated
View File

@ -6,7 +6,7 @@ https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918
https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz
https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz
https://deps.files.ghostty.org/gettext-0.24.tar.gz https://deps.files.ghostty.org/gettext-0.24.tar.gz
https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz
https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz
https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst
https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz
@ -20,7 +20,6 @@ https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d8
https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz
https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz
https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz
https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz
https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz
https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz
@ -34,3 +33,4 @@ https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz

74
dist/cmake/GhosttyZigCompiler.cmake vendored Normal file
View File

@ -0,0 +1,74 @@
# GhosttyZigCompiler.cmake set up zig cc as a cross compiler
#
# Provides ghostty_zig_compiler() which configures zig cc / zig c++ as
# the C/CXX compiler for a given Zig target triple. It creates small
# wrapper scripts (shell on Unix, .cmd on Windows) and sets the
# following CMake variables in the caller's scope:
#
# CMAKE_C_COMPILER, CMAKE_CXX_COMPILER,
# CMAKE_C_COMPILER_FORCED, CMAKE_CXX_COMPILER_FORCED,
# CMAKE_SYSTEM_NAME, CMAKE_EXECUTABLE_SUFFIX (Windows only)
#
# This file is self-contained with no dependencies on the ghostty
# source tree. Copy it into your project and include it directly.
# It cannot be consumed via FetchContent because it must run before
# project(), but FetchContent_MakeAvailable triggers project()
# internally.
#
# Must be called BEFORE project() CMake reads the compiler variables
# at project() time and won't re-detect after that.
#
# Usage:
#
# cmake_minimum_required(VERSION 3.19)
#
# include(cmake/GhosttyZigCompiler.cmake)
# ghostty_zig_compiler(ZIG_TARGET x86_64-linux-gnu)
#
# project(myapp LANGUAGES C CXX)
#
# FetchContent_MakeAvailable(ghostty)
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
# target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
#
# See example/c-vt-cmake-cross/ for a complete working example.
include_guard(GLOBAL)
function(ghostty_zig_compiler)
cmake_parse_arguments(PARSE_ARGV 0 _GZC "" "ZIG_TARGET" "")
if(NOT _GZC_ZIG_TARGET)
message(FATAL_ERROR "ghostty_zig_compiler: ZIG_TARGET is required")
endif()
find_program(_GZC_ZIG zig REQUIRED)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(_cc "${CMAKE_CURRENT_BINARY_DIR}/zig-cc.cmd")
set(_cxx "${CMAKE_CURRENT_BINARY_DIR}/zig-cxx.cmd")
file(WRITE "${_cc}" "@\"${_GZC_ZIG}\" cc -target ${_GZC_ZIG_TARGET} %*\n")
file(WRITE "${_cxx}" "@\"${_GZC_ZIG}\" c++ -target ${_GZC_ZIG_TARGET} %*\n")
else()
set(_cc "${CMAKE_CURRENT_BINARY_DIR}/zig-cc")
set(_cxx "${CMAKE_CURRENT_BINARY_DIR}/zig-c++")
file(WRITE "${_cc}" "#!/bin/sh\nexec \"${_GZC_ZIG}\" cc -target ${_GZC_ZIG_TARGET} \"$@\"\n")
file(WRITE "${_cxx}" "#!/bin/sh\nexec \"${_GZC_ZIG}\" c++ -target ${_GZC_ZIG_TARGET} \"$@\"\n")
file(CHMOD "${_cc}" "${_cxx}"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
endif()
set(CMAKE_C_COMPILER "${_cc}" PARENT_SCOPE)
set(CMAKE_CXX_COMPILER "${_cxx}" PARENT_SCOPE)
set(CMAKE_C_COMPILER_FORCED TRUE PARENT_SCOPE)
set(CMAKE_CXX_COMPILER_FORCED TRUE PARENT_SCOPE)
if(_GZC_ZIG_TARGET MATCHES "windows")
set(CMAKE_SYSTEM_NAME Windows PARENT_SCOPE)
set(CMAKE_EXECUTABLE_SUFFIX ".exe" PARENT_SCOPE)
elseif(_GZC_ZIG_TARGET MATCHES "linux")
set(CMAKE_SYSTEM_NAME Linux PARENT_SCOPE)
elseif(_GZC_ZIG_TARGET MATCHES "darwin|macos")
set(CMAKE_SYSTEM_NAME Darwin PARENT_SCOPE)
endif()
endfunction()

102
dist/cmake/README.md vendored Normal file
View File

@ -0,0 +1,102 @@
# CMake Support for libghostty-vt
The top-level `CMakeLists.txt` wraps the Zig build system so that CMake
projects can consume libghostty-vt without invoking `zig build` manually.
Running `cmake --build` triggers `zig build -Demit-lib-vt` automatically.
This means downstream projects do require a working Zig compiler on
`PATH` to build, but don't need to know any Zig-specific details.
## Using FetchContent (recommended)
Add the following to your project's `CMakeLists.txt`:
```cmake
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt)
```
This fetches the Ghostty source, builds libghostty-vt via Zig during your
CMake build, and links it into your target. Headers are added to the
include path automatically.
### Using a local checkout
If you already have the Ghostty source checked out, skip the download by
pointing CMake at it:
```shell-session
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=/path/to/ghostty
cmake --build build
```
## Using find_package (install-based)
Build and install libghostty-vt first:
```shell-session
cd /path/to/ghostty
cmake -B build
cmake --build build
cmake --install build --prefix /usr/local
```
Then in your project:
```cmake
find_package(ghostty-vt REQUIRED)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt)
```
## Cross-compilation
For cross-compiling to a different Zig target triple, use
`ghostty_vt_add_target()` after `FetchContent_MakeAvailable`:
```cmake
FetchContent_MakeAvailable(ghostty)
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
```
### Using zig cc as the C/CXX compiler
When cross-compiling, the host C compiler can't link binaries for the
target platform. `GhosttyZigCompiler.cmake` provides
`ghostty_zig_compiler()` to set up `zig cc` as the C/CXX compiler for
the cross target. It creates wrapper scripts (shell on Unix, `.cmd` on
Windows) and configures `CMAKE_C_COMPILER`, `CMAKE_CXX_COMPILER`, and
`CMAKE_SYSTEM_NAME`.
The module is self-contained — copy it into your project (e.g. to
`cmake/`) and include it directly. It cannot be consumed via
FetchContent because it must run before `project()`, but
`FetchContent_MakeAvailable` triggers `project()` internally:
```cmake
cmake_minimum_required(VERSION 3.19)
include(cmake/GhosttyZigCompiler.cmake)
ghostty_zig_compiler(ZIG_TARGET x86_64-linux-gnu)
project(myapp LANGUAGES C CXX)
FetchContent_MakeAvailable(ghostty)
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
```
See `example/c-vt-cmake-cross/` for a complete working example.

65
dist/cmake/ghostty-vt-config.cmake.in vendored Normal file
View File

@ -0,0 +1,65 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
set(_ghostty_vt_libdir "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@")
# Shared library target
if(NOT TARGET ghostty-vt::ghostty-vt)
add_library(ghostty-vt::ghostty-vt SHARED IMPORTED)
if(WIN32)
set(_ghostty_vt_shared_location "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_BINDIR@/@GHOSTTY_VT_REALNAME@")
else()
set(_ghostty_vt_shared_location "${_ghostty_vt_libdir}/@GHOSTTY_VT_REALNAME@")
endif()
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_LOCATION "${_ghostty_vt_shared_location}"
INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@"
)
unset(_ghostty_vt_shared_location)
if(APPLE)
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_SONAME "@rpath/@GHOSTTY_VT_SONAME@"
INTERFACE_LINK_DIRECTORIES "${_ghostty_vt_libdir}"
)
# Ensure consumers can find the @rpath dylib at runtime
set_property(TARGET ghostty-vt::ghostty-vt APPEND PROPERTY
INTERFACE_LINK_OPTIONS "LINKER:-rpath,${_ghostty_vt_libdir}"
)
elseif(WIN32)
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_IMPLIB "${_ghostty_vt_libdir}/@GHOSTTY_VT_IMPLIB@"
)
else()
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_SONAME "@GHOSTTY_VT_SONAME@"
)
endif()
endif()
# Static library target
#
# Consumers must link transitive dependencies themselves. By default (with
# SIMD enabled): libc, libc++ (or libstdc++ on Linux), highway, and
# simdutf. Building with -Dsimd=false removes the C++ / highway / simdutf
# dependencies.
if(NOT TARGET ghostty-vt::ghostty-vt-static)
add_library(ghostty-vt::ghostty-vt-static STATIC IMPORTED)
set_target_properties(ghostty-vt::ghostty-vt-static PROPERTIES
IMPORTED_LOCATION "${_ghostty_vt_libdir}/@GHOSTTY_VT_STATIC_REALNAME@"
INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@"
)
if(WIN32)
set_target_properties(ghostty-vt::ghostty-vt-static PROPERTIES
INTERFACE_LINK_LIBRARIES "ntdll;kernel32"
)
endif()
endif()
unset(_ghostty_vt_libdir)
check_required_components(ghostty-vt)

View File

@ -52,6 +52,9 @@
<releases> <releases>
<!-- TODO: Generate this automatically --> <!-- TODO: Generate this automatically -->
<release version="1.3.1" date="2026-03-13">
<url type="details">https://ghostty.org/docs/install/release-notes/1-3-1</url>
</release>
<release version="1.3.0" date="2026-03-09"> <release version="1.3.0" date="2026-03-09">
<url type="details">https://ghostty.org/docs/install/release-notes/1-3-0</url> <url type="details">https://ghostty.org/docs/install/release-notes/1-3-0</url>
</release> </release>

View File

@ -7,5 +7,4 @@ Actions=RunGhosttyDir
[Desktop Action RunGhosttyDir] [Desktop Action RunGhosttyDir]
Name=Open Ghostty Here Name=Open Ghostty Here
Icon=com.mitchellh.ghostty Icon=com.mitchellh.ghostty
Exec=ghostty --working-directory=%F --gtk-single-instance=false Exec=ghostty +new-window --working-directory=%F

2
example/.gitignore vendored
View File

@ -2,3 +2,5 @@
dist/ dist/
node_modules/ node_modules/
example.wasm* example.wasm*
build/
.build/

39
example/AGENTS.md Normal file
View File

@ -0,0 +1,39 @@
# Example Libghostty Projects
Each example is a standalone project with its own `build.zig`,
`build.zig.zon`, `README.md`, and `src/main.c` (or `.zig`). Examples are
auto-discovered by CI via `example/*/build.zig.zon`, so no workflow file
edits are needed when adding a new example.
## Adding a New Example
1. Copy an existing example directory (e.g., `c-vt-encode-focus/`) as a
starting point.
2. Update `build.zig.zon`: change `.name`, generate a **new unique**
`.fingerprint` value (a random `u64` hex literal), and keep
`.minimum_zig_version` matching the others.
3. Update `build.zig`: change the executable `.name` to match the directory.
4. Write a `README.md` following the existing format.
## Doxygen Snippet Tags
Example source files use Doxygen `@snippet` tags so the corresponding
header in `include/ghostty/vt/` can reference them. Wrap the relevant
code with `//! [snippet-name]` markers:
```c
//! [my-snippet]
int main() { ... }
//! [my-snippet]
```
The header then uses `@snippet <dir>/src/main.c my-snippet` instead of
inline `@code` blocks. Never duplicate example code inline in the
headers — always use `@snippet`. When modifying example code, keep the
snippet markers in sync with the headers in `include/ghostty/vt/`.
## Conventions
- Executable names use underscores: `c_vt_encode_focus` (not hyphens).
- All C examples link `ghostty-vt` via `lazyDependency("ghostty", ...)`.
- `build.zig` files follow a common template — keep them consistent.

17
example/README.md Normal file
View File

@ -0,0 +1,17 @@
# Examples
Standalone projects demonstrating the Ghostty library APIs.
The directories starting with `c-` use the C API and the directories
starting with `zig-` use the Zig API.
Every example can be built and run using `zig build` and `zig build run`
from within the respective example directory.
Even the C API examples use the Zig build system (not the language) to
build the project.
## Running an Example
```shell-session
cd example/<dir>
zig build run
```

View File

@ -0,0 +1,17 @@
# Example: `ghostty-vt` Build Info
This contains a simple example of how to use the `ghostty-vt` build info
API to query compile-time build configuration.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -29,7 +29,7 @@ pub fn build(b: *std.Build) void {
// Exe // Exe
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "c_vt_key_encode", .name = "c_vt_build_info",
.root_module = exe_mod, .root_module = exe_mod,
}); });
b.installArtifact(exe); b.installArtifact(exe);

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_build_info,
.version = "0.0.0",
.fingerprint = 0xc6b57ed4f83fb16,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,52 @@
#include <stdio.h>
#include <ghostty/vt.h>
//! [build-info-query]
void query_build_info() {
bool simd = false;
bool kitty_graphics = false;
bool tmux_control_mode = false;
ghostty_build_info(GHOSTTY_BUILD_INFO_SIMD, &simd);
ghostty_build_info(GHOSTTY_BUILD_INFO_KITTY_GRAPHICS, &kitty_graphics);
ghostty_build_info(GHOSTTY_BUILD_INFO_TMUX_CONTROL_MODE, &tmux_control_mode);
printf("SIMD: %s\n", simd ? "enabled" : "disabled");
printf("Kitty graphics: %s\n", kitty_graphics ? "enabled" : "disabled");
printf("Tmux control mode: %s\n", tmux_control_mode ? "enabled" : "disabled");
GhosttyString version_string = {0};
size_t version_major = 0;
size_t version_minor = 0;
size_t version_patch = 0;
GhosttyString version_pre = {0};
GhosttyString version_build = {0};
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_STRING, &version_string);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_MAJOR, &version_major);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_MINOR, &version_minor);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_PATCH, &version_patch);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_PRE, &version_pre);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_BUILD, &version_build);
printf("Version: %.*s\n", (int)version_string.len, version_string.ptr);
printf("Version major: %zu\n", version_major);
printf("Version minor: %zu\n", version_minor);
printf("Version patch: %zu\n", version_patch);
if (version_pre.len > 0) {
printf("Version pre : %.*s\n", (int)version_pre.len, version_pre.ptr);
} else {
printf("Version pre : (none)\n");
}
if (version_build.len > 0) {
printf("Version build: %.*s\n", (int)version_build.len, version_build.ptr);
} else {
printf("Version build: (none)\n");
}
}
//! [build-info-query]
int main() {
query_build_info();
return 0;
}

View File

@ -0,0 +1,59 @@
cmake_minimum_required(VERSION 3.19)
# --- Determine cross-compilation target before project() --------------------
#
# We need to know the target before project() so we can set up zig cc as the
# C/C++ compiler for the cross target.
# Pick a cross-compilation target: build for a different OS than the host.
# Can be overridden with -DZIG_TARGET=... on the command line.
if(NOT ZIG_TARGET)
# CMAKE_HOST_SYSTEM_PROCESSOR may not be set before project(), so
# fall back to `uname -m`.
if(CMAKE_HOST_SYSTEM_PROCESSOR)
set(_arch "${CMAKE_HOST_SYSTEM_PROCESSOR}")
else()
execute_process(COMMAND uname -m OUTPUT_VARIABLE _arch OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if(_arch MATCHES "^(x86_64|AMD64)$")
set(_arch "x86_64")
elseif(_arch MATCHES "^(aarch64|arm64|ARM64)$")
set(_arch "aarch64")
endif()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
set(ZIG_TARGET "${_arch}-windows-gnu")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(ZIG_TARGET "${_arch}-linux-gnu")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
set(ZIG_TARGET "${_arch}-linux-gnu")
else()
message(FATAL_ERROR
"Cannot derive ZIG_TARGET for ${CMAKE_HOST_SYSTEM_NAME}. "
"Pass -DZIG_TARGET=... manually.")
endif()
message(STATUS "Cross-compiling for ZIG_TARGET: ${ZIG_TARGET}")
endif()
# --- Set up zig cc as the cross compiler ------------------------------------
# GhosttyZigCompiler.cmake must be called before project().
# Downstream projects would copy this file into their tree; here we
# include it directly from the repo.
include(../../dist/cmake/GhosttyZigCompiler.cmake)
ghostty_zig_compiler(ZIG_TARGET "${ZIG_TARGET}")
project(c-vt-cmake-cross LANGUAGES C CXX)
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)
ghostty_vt_add_target(NAME cross ZIG_TARGET "${ZIG_TARGET}")
add_executable(c_vt_cmake_cross src/main.c)
target_link_libraries(c_vt_cmake_cross PRIVATE ghostty-vt-static-cross)

View File

@ -0,0 +1,21 @@
# c-vt-cmake-cross
Demonstrates using `ghostty_vt_add_target()` to cross-compile
libghostty-vt with static linking. The target OS is chosen automatically:
| Host | Target |
| ------- | --------------- |
| Linux | Windows (MinGW) |
| Windows | Linux (glibc) |
| macOS | Linux (glibc) |
Override with `-DZIG_TARGET=...` if needed.
## Building
```shell-session
cd example/c-vt-cmake-cross
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
cmake --build build
file build/c_vt_cmake_cross
```

View File

@ -0,0 +1,52 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
// Create a terminal with a small grid
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
// Write some VT-encoded content into the terminal
const char *commands[] = {
"Hello from a \033[1mCMake\033[0m-built program!\r\n",
"Line 2: \033[4munderlined\033[0m text\r\n",
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
};
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i],
strlen(commands[i]));
}
// Format the terminal contents as plain text
GhosttyFormatterTerminalOptions fmt_opts =
GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
fmt_opts.trim = true;
GhosttyFormatter formatter;
result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts);
assert(result == GHOSTTY_SUCCESS);
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
printf("Plain text (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.19)
project(c-vt-cmake-static LANGUAGES C)
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
set(GHOSTTY_ZIG_BUILD_FLAGS "-Dsimd=false" CACHE STRING "" FORCE)
FetchContent_MakeAvailable(ghostty)
add_executable(c_vt_cmake_static src/main.c)
target_link_libraries(c_vt_cmake_static PRIVATE ghostty-vt-static)

View File

@ -0,0 +1,21 @@
# c-vt-cmake-static
Demonstrates consuming libghostty-vt as a **static** library from a CMake
project using `FetchContent`. Creates a terminal, writes VT sequences into
it, and formats the screen contents as plain text.
## Building
```shell-session
cd example/c-vt-cmake-static
cmake -B build
cmake --build build
./build/c_vt_cmake_static
```
To build against a local checkout instead of fetching from GitHub:
```shell-session
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
cmake --build build
```

View File

@ -0,0 +1,52 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
// Create a terminal with a small grid
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
// Write some VT-encoded content into the terminal
const char *commands[] = {
"Hello from a \033[1mCMake\033[0m-built program (static)!\r\n",
"Line 2: \033[4munderlined\033[0m text\r\n",
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
};
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i],
strlen(commands[i]));
}
// Format the terminal contents as plain text
GhosttyFormatterTerminalOptions fmt_opts =
GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
fmt_opts.trim = true;
GhosttyFormatter formatter;
result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts);
assert(result == GHOSTTY_SUCCESS);
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
printf("Plain text (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.19)
project(c-vt-cmake LANGUAGES C)
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)
add_executable(c_vt_cmake src/main.c)
target_link_libraries(c_vt_cmake PRIVATE ghostty-vt)

View File

@ -0,0 +1,21 @@
# c-vt-cmake
Demonstrates consuming libghostty-vt from a CMake project using
`FetchContent`. Creates a terminal, writes VT sequences into it, and
formats the screen contents as plain text.
## Building
```shell-session
cd example/c-vt-cmake
cmake -B build
cmake --build build
./build/c_vt_cmake
```
To build against a local checkout instead of fetching from GitHub:
```shell-session
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
cmake --build build
```

View File

@ -0,0 +1,52 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
// Create a terminal with a small grid
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
// Write some VT-encoded content into the terminal
const char *commands[] = {
"Hello from a \033[1mCMake\033[0m-built program!\r\n",
"Line 2: \033[4munderlined\033[0m text\r\n",
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
};
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i],
strlen(commands[i]));
}
// Format the terminal contents as plain text
GhosttyFormatterTerminalOptions fmt_opts =
GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
fmt_opts.trim = true;
GhosttyFormatter formatter;
result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts);
assert(result == GHOSTTY_SUCCESS);
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
printf("Plain text (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -0,0 +1,18 @@
# Example: `ghostty-vt` Terminal Colors
This contains a simple example of how to set default terminal colors,
read effective and default color values, and observe how OSC overrides
layer on top of defaults using the `ghostty-vt` C library.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_colors",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_colors,
.version = "0.0.0",
.fingerprint = 0xe7ec4247f16d4fce,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,121 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [colors-set-defaults]
/// Set up a dark color theme with custom palette entries.
void set_color_theme(GhosttyTerminal terminal) {
// Set default foreground (light gray) and background (dark)
GhosttyColorRgb fg = { .r = 0xDD, .g = 0xDD, .b = 0xDD };
GhosttyColorRgb bg = { .r = 0x1E, .g = 0x1E, .b = 0x2E };
GhosttyColorRgb cursor = { .r = 0xF5, .g = 0xE0, .b = 0xDC };
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_FOREGROUND, &fg);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_BACKGROUND, &bg);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_CURSOR, &cursor);
// Set a custom palette — start from the built-in default and override
// the first 8 entries with a custom dark theme.
GhosttyColorRgb palette[256];
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_PALETTE, palette);
palette[GHOSTTY_COLOR_NAMED_BLACK] = (GhosttyColorRgb){ 0x45, 0x47, 0x5A };
palette[GHOSTTY_COLOR_NAMED_RED] = (GhosttyColorRgb){ 0xF3, 0x8B, 0xA8 };
palette[GHOSTTY_COLOR_NAMED_GREEN] = (GhosttyColorRgb){ 0xA6, 0xE3, 0xA1 };
palette[GHOSTTY_COLOR_NAMED_YELLOW] = (GhosttyColorRgb){ 0xF9, 0xE2, 0xAF };
palette[GHOSTTY_COLOR_NAMED_BLUE] = (GhosttyColorRgb){ 0x89, 0xB4, 0xFA };
palette[GHOSTTY_COLOR_NAMED_MAGENTA] = (GhosttyColorRgb){ 0xF5, 0xC2, 0xE7 };
palette[GHOSTTY_COLOR_NAMED_CYAN] = (GhosttyColorRgb){ 0x94, 0xE2, 0xD5 };
palette[GHOSTTY_COLOR_NAMED_WHITE] = (GhosttyColorRgb){ 0xBA, 0xC2, 0xDE };
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_PALETTE, palette);
}
//! [colors-set-defaults]
//! [colors-read]
/// Print the effective and default values for a color, showing how
/// OSC overrides layer on top of defaults.
void print_color(GhosttyTerminal terminal,
const char* name,
GhosttyTerminalData effective_data,
GhosttyTerminalData default_data) {
GhosttyColorRgb color;
GhosttyResult res = ghostty_terminal_get(terminal, effective_data, &color);
if (res == GHOSTTY_SUCCESS) {
printf(" %-12s effective: #%02X%02X%02X", name, color.r, color.g, color.b);
} else {
printf(" %-12s effective: (not set)", name);
}
res = ghostty_terminal_get(terminal, default_data, &color);
if (res == GHOSTTY_SUCCESS) {
printf(" default: #%02X%02X%02X\n", color.r, color.g, color.b);
} else {
printf(" default: (not set)\n");
}
}
void print_all_colors(GhosttyTerminal terminal, const char* label) {
printf("%s:\n", label);
print_color(terminal, "foreground",
GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND,
GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND_DEFAULT);
print_color(terminal, "background",
GHOSTTY_TERMINAL_DATA_COLOR_BACKGROUND,
GHOSTTY_TERMINAL_DATA_COLOR_BACKGROUND_DEFAULT);
print_color(terminal, "cursor",
GHOSTTY_TERMINAL_DATA_COLOR_CURSOR,
GHOSTTY_TERMINAL_DATA_COLOR_CURSOR_DEFAULT);
// Show palette index 0 (black) as an example
GhosttyColorRgb palette[256];
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_PALETTE, palette);
printf(" %-12s effective: #%02X%02X%02X", "palette[0]",
palette[0].r, palette[0].g, palette[0].b);
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_PALETTE_DEFAULT,
palette);
printf(" default: #%02X%02X%02X\n", palette[0].r, palette[0].g, palette[0].b);
}
//! [colors-read]
//! [colors-main]
int main() {
// Create a terminal
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create terminal\n");
return 1;
}
// Before setting any colors, everything is unset
print_all_colors(terminal, "Before setting defaults");
// Set our color theme defaults
set_color_theme(terminal);
print_all_colors(terminal, "\nAfter setting defaults");
// Simulate an OSC override (e.g. a program running inside the
// terminal changes the foreground via OSC 10)
const char* osc_fg = "\x1B]10;rgb:FF/00/00\x1B\\";
ghostty_terminal_vt_write(terminal, (const uint8_t*)osc_fg,
strlen(osc_fg));
print_all_colors(terminal, "\nAfter OSC foreground override");
// Clear the foreground default — the OSC override is still active
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_FOREGROUND, NULL);
print_all_colors(terminal, "\nAfter clearing foreground default");
ghostty_terminal_free(terminal);
return 0;
}
//! [colors-main]

View File

@ -0,0 +1,18 @@
# Example: `ghostty-vt` Terminal Effects
This contains a simple example of how to register and use terminal
effect callbacks (`write_pty`, `bell`, `title_changed`) with the
`ghostty-vt` C library.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_effects",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_effects,
.version = "0.0.0",
.fingerprint = 0xc02634cd65f5b583,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,97 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [effects-write-pty]
void on_write_pty(GhosttyTerminal terminal,
void* userdata,
const uint8_t* data,
size_t len) {
(void)terminal;
(void)userdata;
printf(" write_pty (%zu bytes): ", len);
fwrite(data, 1, len, stdout);
printf("\n");
}
//! [effects-write-pty]
//! [effects-bell]
void on_bell(GhosttyTerminal terminal, void* userdata) {
(void)terminal;
int* count = (int*)userdata;
(*count)++;
printf(" bell! (count=%d)\n", *count);
}
//! [effects-bell]
//! [effects-title-changed]
void on_title_changed(GhosttyTerminal terminal, void* userdata) {
(void)userdata;
// Query the cursor position to confirm the terminal processed the
// title change (the title itself is tracked by the embedder via the
// OSC parser or its own state).
uint16_t col = 0;
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_CURSOR_X, &col);
printf(" title changed (cursor at col %u)\n", col);
}
//! [effects-title-changed]
//! [effects-register]
int main() {
// Create a terminal
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create terminal\n");
return 1;
}
// Set up userdata — a simple bell counter
int bell_count = 0;
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_USERDATA, &bell_count);
// Register effect callbacks
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_WRITE_PTY,
(const void *)on_write_pty);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_BELL,
(const void *)on_bell);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_TITLE_CHANGED,
(const void *)on_title_changed);
// Feed VT data that triggers effects:
// 1. Bell (BEL = 0x07)
printf("Sending BEL:\n");
const uint8_t bel = 0x07;
ghostty_terminal_vt_write(terminal, &bel, 1);
// 2. Title change (OSC 2 ; <title> ST)
printf("Sending title change:\n");
const char* title_seq = "\x1B]2;Hello Effects\x1B\\";
ghostty_terminal_vt_write(terminal, (const uint8_t*)title_seq,
strlen(title_seq));
// 3. Device status report (DECRQM for wraparound mode ?7)
// triggers write_pty with the response
printf("Sending DECRQM query:\n");
const char* decrqm = "\x1B[?7$p";
ghostty_terminal_vt_write(terminal, (const uint8_t*)decrqm,
strlen(decrqm));
// 4. Another bell to show the counter increments
printf("Sending another BEL:\n");
ghostty_terminal_vt_write(terminal, &bel, 1);
printf("Total bells: %d\n", bell_count);
ghostty_terminal_free(terminal);
return 0;
}
//! [effects-register]

View File

@ -0,0 +1,17 @@
# Example: `ghostty-vt` Encode Focus
This contains a simple example of how to use the `ghostty-vt` focus
encoding API to encode focus gained/lost events into escape sequences.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_encode_focus",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_encode_focus,
.version = "0.0.0",
.fingerprint = 0x89f01fd829fcc550,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <ghostty/vt.h>
//! [focus-encode]
int main() {
char buf[8];
size_t written = 0;
GhosttyResult result = ghostty_focus_encode(
GHOSTTY_FOCUS_GAINED, buf, sizeof(buf), &written);
if (result == GHOSTTY_SUCCESS) {
printf("Encoded %zu bytes: ", written);
fwrite(buf, 1, written, stdout);
printf("\n");
}
return 0;
}
//! [focus-encode]

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_encode_key",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,40 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [key-encode]
int main() {
// Create encoder
GhosttyKeyEncoder encoder;
GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Enable Kitty keyboard protocol with all features
ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS,
&(uint8_t){GHOSTTY_KITTY_KEY_ALL});
// Create and configure key event for Ctrl+C press
GhosttyKeyEvent event;
result = ghostty_key_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_PRESS);
ghostty_key_event_set_key(event, GHOSTTY_KEY_C);
ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
// Encode the key event
char buf[128];
size_t written = 0;
result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
// Use the encoded sequence (e.g., write to terminal)
fwrite(buf, 1, written, stdout);
// Cleanup
ghostty_key_event_free(event);
ghostty_key_encoder_free(encoder);
return 0;
}
//! [key-encode]

View File

@ -0,0 +1,23 @@
# Example: `ghostty-vt` C Mouse Encoding
This example demonstrates how to use the `ghostty-vt` C library to encode mouse
events into terminal escape sequences.
This example specifically shows how to:
1. Create a mouse encoder with the C API
2. Configure tracking mode and output format (this example uses SGR)
3. Set terminal geometry for pixel-to-cell coordinate mapping
4. Create and configure a mouse event
5. Encode the mouse event into a terminal escape sequence
The example encodes a left button press at pixel position (50, 40) using SGR
format, producing an escape sequence like `\x1b[<0;6;3M`.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_encode_mouse",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt,
.version = "0.0.0",
.fingerprint = 0x413a8529a6dd3c51,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,52 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [mouse-encode]
int main() {
// Create encoder
GhosttyMouseEncoder encoder;
GhosttyResult result = ghostty_mouse_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Configure SGR format with normal tracking
ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_EVENT,
&(GhosttyMouseTrackingMode){GHOSTTY_MOUSE_TRACKING_NORMAL});
ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_FORMAT,
&(GhosttyMouseFormat){GHOSTTY_MOUSE_FORMAT_SGR});
// Set terminal geometry for coordinate mapping
ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_SIZE,
&(GhosttyMouseEncoderSize){
.size = sizeof(GhosttyMouseEncoderSize),
.screen_width = 800, .screen_height = 600,
.cell_width = 10, .cell_height = 20,
});
// Create and configure a left button press event
GhosttyMouseEvent event;
result = ghostty_mouse_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_mouse_event_set_action(event, GHOSTTY_MOUSE_ACTION_PRESS);
ghostty_mouse_event_set_button(event, GHOSTTY_MOUSE_BUTTON_LEFT);
ghostty_mouse_event_set_position(event,
(GhosttyMousePosition){.x = 50.0f, .y = 40.0f});
// Encode the mouse event
char buf[128];
size_t written = 0;
result = ghostty_mouse_encoder_encode(encoder, event,
buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
// Use the encoded sequence (e.g., write to terminal)
fwrite(buf, 1, written, stdout);
// Cleanup
ghostty_mouse_event_free(event);
ghostty_mouse_encoder_free(encoder);
return 0;
}
//! [mouse-encode]

View File

@ -0,0 +1,18 @@
# Example: `ghostty-vt` Terminal Formatter
This contains a simple example of how to use the `ghostty-vt` terminal and
formatter APIs to create a terminal, write VT-encoded content into it, and
format the screen contents as plain text.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_formatter",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_formatter,
.version = "0.0.0",
.fingerprint = 0x9e3758265677a0c4,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,63 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
// Create a terminal with a small grid
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
// Write VT-encoded content into the terminal to exercise various
// cursor movement and styling sequences.
const char *commands[] = {
"Line 1: Hello World!\r\n", // Simple text on row 1
"Line 2: \033[1mBold\033[0m and " // Bold text on row 2
"\033[4mUnderline\033[0m\r\n",
"Line 3: placeholder\r\n", // Will be overwritten below
"\033[3;1H", // CUP: move cursor back to row 3, col 1
"\033[2K", // EL: erase the entire line
"Line 3: Overwritten!\r\n", // Rewrite row 3 with new content
"\033[5;10H", // CUP: jump to row 5, col 10
"Placed at (5,10)", // Write at that position
"\033[1;72H", // CUP: jump to row 1, col 72
"RIGHT->", // Near the right edge of row 1
};
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i],
strlen(commands[i]));
}
// Create a plain-text formatter for the terminal
GhosttyFormatterTerminalOptions fmt_opts = GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
fmt_opts.trim = true;
GhosttyFormatter formatter;
result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts);
assert(result == GHOSTTY_SUCCESS);
// Format into an allocated buffer
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
// Print the formatted output
printf("Formatted output (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
// Clean up
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -0,0 +1,19 @@
# Example: `ghostty-vt` Tracked Grid References
This contains a simple example of how to use the `ghostty-vt` terminal and
tracked grid reference APIs to keep a long-lived reference to a cell as the
terminal scrolls, detect when that reference loses its meaningful location,
and move the same tracked handle to a new point.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_grid_ref_tracked",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_grid_ref_tracked,
.version = "0.0.0",
.fingerprint = 0x64bd14b59e76c294,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,94 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [grid-ref-tracked]
static uint32_t codepoint_at_tracked_ref(GhosttyTrackedGridRef tracked) {
GhosttyGridRef snapshot = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyResult result = ghostty_tracked_grid_ref_snapshot(tracked, &snapshot);
assert(result == GHOSTTY_SUCCESS);
GhosttyCell cell;
result = ghostty_grid_ref_cell(&snapshot, &cell);
assert(result == GHOSTTY_SUCCESS);
bool has_text = false;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_HAS_TEXT, &has_text);
assert(has_text);
uint32_t codepoint = 0;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_CODEPOINT, &codepoint);
return codepoint;
}
int main() {
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 8,
.rows = 3,
.max_scrollback = 100,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
const char *text = "alpha\r\n"
"bravo\r\n"
"charlie";
ghostty_terminal_vt_write(
terminal, (const uint8_t *)text, strlen(text));
GhosttyTrackedGridRef tracked = NULL;
GhosttyPoint alpha = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = 0 } },
};
result = ghostty_terminal_grid_ref_track(terminal, alpha, &tracked);
assert(result == GHOSTTY_SUCCESS);
// Writing another line scrolls the original "alpha" row into scrollback.
// The tracked ref still follows the same cell.
const char *more = "\r\ndelta";
ghostty_terminal_vt_write(
terminal, (const uint8_t *)more, strlen(more));
assert(ghostty_tracked_grid_ref_has_value(tracked));
printf("tracked codepoint after scroll: %c\n",
(char)codepoint_at_tracked_ref(tracked));
GhosttyPointCoordinate screen = {0};
result = ghostty_tracked_grid_ref_point(
tracked, GHOSTTY_POINT_TAG_SCREEN, &screen);
assert(result == GHOSTTY_SUCCESS);
printf("tracked screen point: %u,%u\n", screen.x, screen.y);
// Resetting the terminal discards the old grid contents. The tracked
// handle remains valid, but no longer has a meaningful location.
ghostty_terminal_reset(terminal);
assert(!ghostty_tracked_grid_ref_has_value(tracked));
GhosttyGridRef discarded = GHOSTTY_INIT_SIZED(GhosttyGridRef);
result = ghostty_tracked_grid_ref_snapshot(tracked, &discarded);
assert(result == GHOSTTY_NO_VALUE);
// The same handle can be moved to a new point after it loses its value.
const char *replacement = "echo";
ghostty_terminal_vt_write(
terminal, (const uint8_t *)replacement, strlen(replacement));
GhosttyPoint echo = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = 0 } },
};
result = ghostty_tracked_grid_ref_set(tracked, terminal, echo);
assert(result == GHOSTTY_SUCCESS);
assert(ghostty_tracked_grid_ref_has_value(tracked));
printf("tracked codepoint after reset/set: %c\n",
(char)codepoint_at_tracked_ref(tracked));
ghostty_tracked_grid_ref_free(tracked);
ghostty_terminal_free(terminal);
return 0;
}
//! [grid-ref-tracked]

View File

@ -0,0 +1,19 @@
# Example: `ghostty-vt` Grid Traversal
This contains a simple example of how to use the `ghostty-vt` terminal and
grid reference APIs to create a terminal, write content into it, and then
traverse the entire grid cell-by-cell using grid refs to inspect codepoints,
row state, and styles.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_grid_traverse",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_grid_traverse,
.version = "0.0.0",
.fingerprint = 0xf694dd12db9be040,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,85 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [grid-ref-traverse]
int main() {
// Create a small terminal
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 10,
.rows = 3,
.max_scrollback = 0,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
// Write some content so the grid has interesting data
const char *text = "Hello!\r\n" // Row 0: H e l l o !
"World\r\n" // Row 1: W o r l d
"\033[1mBold"; // Row 2: B o l d (bold style)
ghostty_terminal_vt_write(
terminal, (const uint8_t *)text, strlen(text));
// Get terminal dimensions
uint16_t cols, rows;
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLS, &cols);
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_ROWS, &rows);
// Traverse the entire grid using grid refs
for (uint16_t row = 0; row < rows; row++) {
printf("Row %u: ", row);
for (uint16_t col = 0; col < cols; col++) {
// Resolve the point to a grid reference
GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint pt = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = col, .y = row } },
};
result = ghostty_terminal_grid_ref(terminal, pt, &ref);
assert(result == GHOSTTY_SUCCESS);
// Read the cell from the grid ref
GhosttyCell cell;
result = ghostty_grid_ref_cell(&ref, &cell);
assert(result == GHOSTTY_SUCCESS);
// Check if the cell has text
bool has_text = false;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_HAS_TEXT, &has_text);
if (has_text) {
uint32_t codepoint = 0;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_CODEPOINT, &codepoint);
printf("%c", (char)codepoint);
} else {
printf(".");
}
}
// Also inspect the row for wrap state
GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint pt = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = row } },
};
ghostty_terminal_grid_ref(terminal, pt, &ref);
GhosttyRow grid_row;
ghostty_grid_ref_row(&ref, &grid_row);
bool wrap = false;
ghostty_row_get(grid_row, GHOSTTY_ROW_DATA_WRAP, &wrap);
printf(" (wrap=%s", wrap ? "true" : "false");
// Check the style of the first cell with text
GhosttyStyle style = GHOSTTY_INIT_SIZED(GhosttyStyle);
ghostty_grid_ref_style(&ref, &style);
printf(", bold=%s)\n", style.bold ? "true" : "false");
}
ghostty_terminal_free(terminal);
return 0;
}
//! [grid-ref-traverse]

View File

@ -1,59 +0,0 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
GhosttyKeyEncoder encoder;
GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Set kitty flags with all features enabled
ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS, &(uint8_t){GHOSTTY_KITTY_KEY_ALL});
// Create key event
GhosttyKeyEvent event;
result = ghostty_key_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_RELEASE);
ghostty_key_event_set_key(event, GHOSTTY_KEY_CONTROL_LEFT);
ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
printf("Encoding event: left ctrl release with all Kitty flags enabled\n");
// Optionally, encode with null buffer to get required size. You can
// skip this step and provide a sufficiently large buffer directly.
// If there isn't enoug hspace, the function will return an out of memory
// error.
size_t required = 0;
result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
assert(result == GHOSTTY_OUT_OF_MEMORY);
printf("Required buffer size: %zu bytes\n", required);
// Encode the key event. We don't use our required size above because
// that was just an example; we know 128 bytes is enough.
char buf[128];
size_t written = 0;
result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
printf("Encoded %zu bytes\n", written);
// Print the encoded sequence (hex and string)
printf("Hex: ");
for (size_t i = 0; i < written; i++) printf("%02x ", (unsigned char)buf[i]);
printf("\n");
printf("String: ");
for (size_t i = 0; i < written; i++) {
if (buf[i] == 0x1b) {
printf("\\x1b");
} else {
printf("%c", buf[i]);
}
}
printf("\n");
ghostty_key_event_free(event);
ghostty_key_encoder_free(encoder);
return 0;
}

View File

@ -0,0 +1,18 @@
# Example: `ghostty-vt` Kitty Graphics Protocol
This contains a simple example of how to use the system interface
(`ghostty_sys_set`) to install a PNG decoder callback, then send
a Kitty Graphics Protocol image via `ghostty_terminal_vt_write`.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_kitty_graphics",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_kitty_graphics,
.version = "0.0.0",
.fingerprint = 0x432d40ecc8f15589,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,211 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [kitty-graphics-decode-png]
/**
* Minimal PNG decoder callback for the sys interface.
*
* A real implementation would use a PNG library (libpng, stb_image, etc.)
* to decode the PNG data. This example uses a hardcoded 1x1 red pixel
* since we know exactly what image we're sending.
*
* WARNING: This is only an example for providing a callback, it DOES NOT
* actually decode the PNG it is passed. It hardcodes a response.
*/
bool decode_png(void* userdata,
const GhosttyAllocator* allocator,
const uint8_t* data,
size_t data_len,
GhosttySysImage* out) {
int* count = (int*)userdata;
(*count)++;
printf(" decode_png called (size=%zu, call #%d)\n", data_len, *count);
/* Allocate RGBA pixel data through the provided allocator. */
const size_t pixel_len = 4; /* 1x1 RGBA */
uint8_t* pixels = ghostty_alloc(allocator, pixel_len);
if (!pixels) return false;
/* Fill with red (R=255, G=0, B=0, A=255). */
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
out->width = 1;
out->height = 1;
out->data = pixels;
out->data_len = pixel_len;
return true;
}
//! [kitty-graphics-decode-png]
//! [kitty-graphics-write-pty]
/**
* write_pty callback to capture terminal responses.
*
* The Kitty graphics protocol sends an APC response back to the pty
* when an image is loaded (unless suppressed with q=2).
*/
void on_write_pty(GhosttyTerminal terminal,
void* userdata,
const uint8_t* data,
size_t len) {
(void)terminal;
(void)userdata;
printf(" response (%zu bytes): ", len);
fwrite(data, 1, len, stdout);
printf("\n");
}
//! [kitty-graphics-write-pty]
//! [kitty-graphics-main]
int main() {
/* Install the PNG decoder via the sys interface. */
int decode_count = 0;
ghostty_sys_set(GHOSTTY_SYS_OPT_USERDATA, &decode_count);
ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, (const void*)decode_png);
/* Create a terminal with Kitty graphics enabled. */
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create terminal\n");
return 1;
}
/* Set cell pixel dimensions so kitty graphics can compute grid sizes. */
ghostty_terminal_resize(terminal, 80, 24, 8, 16);
/* Set a storage limit to enable Kitty graphics. */
uint64_t storage_limit = 64 * 1024 * 1024; /* 64 MiB */
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT,
&storage_limit);
/* Install write_pty to see the protocol response. */
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_WRITE_PTY,
(const void*)on_write_pty);
/*
* Send a Kitty graphics command with an inline 1x1 PNG image.
*
* The escape sequence is:
* ESC _G a=T,f=100,q=1; <base64 PNG data> ESC \
*
* Where:
* a=T transmit and display
* f=100 PNG format
* q=1 request a response (q=0 would suppress it)
*/
printf("Sending Kitty graphics PNG image:\n");
const char* kitty_cmd =
"\x1b_Ga=T,f=100,q=1;"
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAA"
"DUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg=="
"\x1b\\";
ghostty_terminal_vt_write(terminal, (const uint8_t*)kitty_cmd,
strlen(kitty_cmd));
printf("PNG decode calls: %d\n", decode_count);
/* Query the kitty graphics storage to verify the image was stored. */
GhosttyKittyGraphics graphics = NULL;
if (ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS,
&graphics) != GHOSTTY_SUCCESS || !graphics) {
fprintf(stderr, "Failed to get kitty graphics storage\n");
return 1;
}
printf("\nKitty graphics storage is available.\n");
/* Iterate placements to find the image ID. */
GhosttyKittyGraphicsPlacementIterator iter = NULL;
if (ghostty_kitty_graphics_placement_iterator_new(NULL, &iter) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create placement iterator\n");
return 1;
}
if (ghostty_kitty_graphics_get(graphics,
GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR, &iter) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to get placement iterator\n");
return 1;
}
int placement_count = 0;
while (ghostty_kitty_graphics_placement_next(iter)) {
placement_count++;
uint32_t image_id = 0;
uint32_t placement_id = 0;
bool is_virtual = false;
int32_t z = 0;
ghostty_kitty_graphics_placement_get_multi(iter, 4,
(GhosttyKittyGraphicsPlacementData[]){
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z,
},
(void*[]){ &image_id, &placement_id, &is_virtual, &z },
NULL);
printf(" placement #%d: image_id=%u placement_id=%u virtual=%s z=%d\n",
placement_count, image_id, placement_id,
is_virtual ? "true" : "false", z);
/* Look up the image and print its properties. */
GhosttyKittyGraphicsImage image =
ghostty_kitty_graphics_image(graphics, image_id);
if (!image) {
fprintf(stderr, "Failed to look up image %u\n", image_id);
return 1;
}
uint32_t width = 0, height = 0, number = 0;
GhosttyKittyImageFormat format = 0;
size_t data_len = 0;
ghostty_kitty_graphics_image_get_multi(image, 5,
(GhosttyKittyGraphicsImageData[]){
GHOSTTY_KITTY_IMAGE_DATA_NUMBER,
GHOSTTY_KITTY_IMAGE_DATA_WIDTH,
GHOSTTY_KITTY_IMAGE_DATA_HEIGHT,
GHOSTTY_KITTY_IMAGE_DATA_FORMAT,
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN,
},
(void*[]){ &number, &width, &height, &format, &data_len },
NULL);
printf(" image: number=%u size=%ux%u format=%d data_len=%zu\n",
number, width, height, format, data_len);
/* Compute the rendered pixel size and grid size. */
uint32_t px_w = 0, px_h = 0, cols = 0, rows = 0;
if (ghostty_kitty_graphics_placement_pixel_size(iter, image, terminal,
&px_w, &px_h) == GHOSTTY_SUCCESS) {
printf(" rendered pixel size: %ux%u\n", px_w, px_h);
}
if (ghostty_kitty_graphics_placement_grid_size(iter, image, terminal,
&cols, &rows) == GHOSTTY_SUCCESS) {
printf(" grid size: %u cols x %u rows\n", cols, rows);
}
}
printf("Total placements: %d\n", placement_count);
ghostty_kitty_graphics_placement_iterator_free(iter);
/* Clean up. */
ghostty_terminal_free(terminal);
/* Clear the sys callbacks. */
ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, NULL);
ghostty_sys_set(GHOSTTY_SYS_OPT_USERDATA, NULL);
return 0;
}
//! [kitty-graphics-main]

View File

@ -0,0 +1,18 @@
# Example: `ghostty-vt` Mode Utilities
This contains a simple example of how to use the `ghostty-vt` mode
utilities to pack and unpack terminal mode identifiers and encode
DECRPM responses.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_modes",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_modes,
.version = "0.0.0",
.fingerprint = 0x67ce079ebc70a02a,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,45 @@
#include <stdio.h>
#include <ghostty/vt.h>
//! [modes-pack-unpack]
void modes_example() {
// Create a mode for DEC mode 25 (cursor visible)
GhosttyMode tag = ghostty_mode_new(25, false);
printf("value=%u ansi=%d packed=0x%04x\n",
ghostty_mode_value(tag),
ghostty_mode_ansi(tag),
tag);
// Create a mode for ANSI mode 4 (insert mode)
GhosttyMode ansi_tag = ghostty_mode_new(4, true);
printf("value=%u ansi=%d packed=0x%04x\n",
ghostty_mode_value(ansi_tag),
ghostty_mode_ansi(ansi_tag),
ansi_tag);
}
//! [modes-pack-unpack]
//! [modes-decrpm]
void decrpm_example() {
char buf[32];
size_t written = 0;
// Encode a report that DEC mode 25 (cursor visible) is set
GhosttyResult result = ghostty_mode_report_encode(
GHOSTTY_MODE_CURSOR_VISIBLE,
GHOSTTY_MODE_REPORT_SET,
buf, sizeof(buf), &written);
if (result == GHOSTTY_SUCCESS) {
printf("Encoded %zu bytes: ", written);
fwrite(buf, 1, written, stdout);
printf("\n"); // prints: ESC[?25;1$y
}
}
//! [modes-decrpm]
int main() {
modes_example();
decrpm_example();
return 0;
}

View File

@ -1,7 +1,7 @@
# Example: `ghostty-vt` Paste Safety Check # Example: `ghostty-vt` Paste Utilities
This contains a simple example of how to use the `ghostty-vt` paste This contains a simple example of how to use the `ghostty-vt` paste
utilities to check if paste data is safe. utilities to check if paste data is safe and encode it for terminal input.
This uses a `build.zig` and `Zig` to build the C program so that we This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source can reuse a lot of our build logic and depend directly on our source

View File

@ -2,18 +2,41 @@
#include <string.h> #include <string.h>
#include <ghostty/vt.h> #include <ghostty/vt.h>
int main() { //! [paste-safety]
// Test safe paste data void safety_example() {
const char *safe_data = "hello world"; const char* safe_data = "hello world";
const char* unsafe_data = "rm -rf /\n";
if (ghostty_paste_is_safe(safe_data, strlen(safe_data))) { if (ghostty_paste_is_safe(safe_data, strlen(safe_data))) {
printf("'%s' is safe to paste\n", safe_data); printf("Safe to paste\n");
} }
// Test unsafe paste data with newline if (!ghostty_paste_is_safe(unsafe_data, strlen(unsafe_data))) {
const char *unsafe_newline = "rm -rf /\n"; printf("Unsafe! Contains newline\n");
if (!ghostty_paste_is_safe(unsafe_newline, strlen(unsafe_newline))) {
printf("'%s' is UNSAFE - contains newline\n", unsafe_newline);
} }
}
//! [paste-safety]
//! [paste-encode]
void encode_example() {
// The input buffer is modified in place (unsafe bytes are stripped).
char data[] = "hello\nworld";
char buf[64];
size_t written = 0;
GhosttyResult result = ghostty_paste_encode(
data, strlen(data), true, buf, sizeof(buf), &written);
if (result == GHOSTTY_SUCCESS) {
printf("Encoded %zu bytes: ", written);
fwrite(buf, 1, written, stdout);
printf("\n");
}
}
//! [paste-encode]
int main() {
safety_example();
// Test unsafe paste data with bracketed paste end sequence // Test unsafe paste data with bracketed paste end sequence
const char *unsafe_escape = "evil\x1b[201~code"; const char *unsafe_escape = "evil\x1b[201~code";
@ -27,5 +50,7 @@ int main() {
printf("Empty data is safe\n"); printf("Empty data is safe\n");
} }
encode_example();
return 0; return 0;
} }

View File

@ -0,0 +1,19 @@
# Example: `ghostty-vt` Render State
This contains an example of how to use the `ghostty-vt` render-state API
to create a render state, update it from terminal content, iterate rows
and cells, read styles and colors, inspect cursor and row-local selection
state, and manage dirty tracking.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_render",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@ -0,0 +1,24 @@
.{
.name = .c_vt_render,
.version = "0.0.0",
.fingerprint = 0xb10e18b2fab773c9,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@ -0,0 +1,272 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
/// Helper: resolve a style color to an RGB value using the palette.
static GhosttyColorRgb resolve_color(GhosttyStyleColor color,
const GhosttyRenderStateColors* colors,
GhosttyColorRgb fallback) {
switch (color.tag) {
case GHOSTTY_STYLE_COLOR_RGB:
return color.value.rgb;
case GHOSTTY_STYLE_COLOR_PALETTE:
return colors->palette[color.value.palette];
default:
return fallback;
}
}
int main(void) {
GhosttyResult result;
//! [render-state-update]
// Create a terminal and render state, then update the render state
// from the terminal. The render state captures a snapshot of everything
// needed to draw a frame.
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions terminal_opts = {
.cols = 40,
.rows = 5,
.max_scrollback = 10000,
};
result = ghostty_terminal_new(NULL, &terminal, terminal_opts);
assert(result == GHOSTTY_SUCCESS);
GhosttyRenderState render_state = NULL;
result = ghostty_render_state_new(NULL, &render_state);
assert(result == GHOSTTY_SUCCESS);
// Feed some styled content into the terminal.
const char* content =
"Hello, \033[1;32mworld\033[0m!\r\n" // bold green "world"
"\033[4munderlined\033[0m text\r\n" // underlined text
"\033[38;2;255;128;0morange\033[0m\r\n"; // 24-bit orange fg
ghostty_terminal_vt_write(
terminal, (const uint8_t*)content, strlen(content));
// Select "underlined" on the second row. Render state exposes this
// later as a row-local selected cell range.
GhosttyGridRef selection_start = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint selection_start_pt = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = 1 } },
};
result = ghostty_terminal_grid_ref(
terminal, selection_start_pt, &selection_start);
assert(result == GHOSTTY_SUCCESS);
GhosttyGridRef selection_end = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint selection_end_pt = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 9, .y = 1 } },
};
result = ghostty_terminal_grid_ref(terminal, selection_end_pt, &selection_end);
assert(result == GHOSTTY_SUCCESS);
GhosttySelection selection = GHOSTTY_INIT_SIZED(GhosttySelection);
selection.start = selection_start;
selection.end = selection_end;
result = ghostty_terminal_set(
terminal, GHOSTTY_TERMINAL_OPT_SELECTION, &selection);
assert(result == GHOSTTY_SUCCESS);
result = ghostty_render_state_update(render_state, terminal);
assert(result == GHOSTTY_SUCCESS);
//! [render-state-update]
//! [render-dirty-check]
// Check the global dirty state to decide how much work the renderer
// needs to do. After rendering, reset it to false.
GhosttyRenderStateDirty dirty;
result = ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_DIRTY, &dirty);
assert(result == GHOSTTY_SUCCESS);
switch (dirty) {
case GHOSTTY_RENDER_STATE_DIRTY_FALSE:
printf("Frame is clean, nothing to draw.\n");
break;
case GHOSTTY_RENDER_STATE_DIRTY_PARTIAL:
printf("Partial redraw needed.\n");
break;
case GHOSTTY_RENDER_STATE_DIRTY_FULL:
printf("Full redraw needed.\n");
break;
}
//! [render-dirty-check]
//! [render-colors]
// Retrieve colors (background, foreground, palette) from the render
// state. These are needed to resolve palette-indexed cell colors.
GhosttyRenderStateColors colors =
GHOSTTY_INIT_SIZED(GhosttyRenderStateColors);
result = ghostty_render_state_colors_get(render_state, &colors);
assert(result == GHOSTTY_SUCCESS);
printf("Background: #%02x%02x%02x\n",
colors.background.r, colors.background.g, colors.background.b);
printf("Foreground: #%02x%02x%02x\n",
colors.foreground.r, colors.foreground.g, colors.foreground.b);
//! [render-colors]
//! [render-cursor]
// Read cursor position and visual style from the render state.
bool cursor_visible = false;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE,
&cursor_visible);
bool cursor_in_viewport = false;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE,
&cursor_in_viewport);
if (cursor_visible && cursor_in_viewport) {
uint16_t cx, cy;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X, &cx);
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y, &cy);
GhosttyRenderStateCursorVisualStyle style;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VISUAL_STYLE,
&style);
const char* style_name = "unknown";
switch (style) {
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BAR:
style_name = "bar";
break;
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK:
style_name = "block";
break;
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_UNDERLINE:
style_name = "underline";
break;
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK_HOLLOW:
style_name = "hollow";
break;
}
printf("Cursor at (%u, %u), style: %s\n", cx, cy, style_name);
}
//! [render-cursor]
//! [render-row-iterate]
// Iterate rows via the row iterator. For each dirty row, iterate its
// cells, read codepoints/graphemes and styles, and emit ANSI-colored
// output as a simple "renderer".
GhosttyRenderStateRowIterator row_iter = NULL;
result = ghostty_render_state_row_iterator_new(NULL, &row_iter);
assert(result == GHOSTTY_SUCCESS);
result = ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR, &row_iter);
assert(result == GHOSTTY_SUCCESS);
GhosttyRenderStateRowCells cells = NULL;
result = ghostty_render_state_row_cells_new(NULL, &cells);
assert(result == GHOSTTY_SUCCESS);
int row_index = 0;
while (ghostty_render_state_row_iterator_next(row_iter)) {
// Check per-row dirty state; a real renderer would skip clean rows.
bool row_dirty = false;
ghostty_render_state_row_get(
row_iter, GHOSTTY_RENDER_STATE_ROW_DATA_DIRTY, &row_dirty);
printf("Row %2d [%s]: ", row_index,
row_dirty ? "dirty" : "clean");
// Query the row-local selection range. Rows without a selection return
// GHOSTTY_NO_VALUE; selected rows return inclusive start/end columns.
GhosttyRenderStateRowSelection row_selection =
GHOSTTY_INIT_SIZED(GhosttyRenderStateRowSelection);
result = ghostty_render_state_row_get(
row_iter, GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION, &row_selection);
assert(result == GHOSTTY_SUCCESS || result == GHOSTTY_NO_VALUE);
if (result == GHOSTTY_SUCCESS) {
printf("selection=%u..%u ",
row_selection.start_x, row_selection.end_x);
}
// Get cells for this row (reuses the same cells handle).
result = ghostty_render_state_row_get(
row_iter, GHOSTTY_RENDER_STATE_ROW_DATA_CELLS, &cells);
assert(result == GHOSTTY_SUCCESS);
while (ghostty_render_state_row_cells_next(cells)) {
// Get the grapheme length; 0 means the cell is empty.
uint32_t grapheme_len = 0;
ghostty_render_state_row_cells_get(
cells, GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN,
&grapheme_len);
if (grapheme_len == 0) {
putchar(' ');
continue;
}
// Read the style for this cell. Returns the default style for
// cells that have no explicit styling.
GhosttyStyle style = GHOSTTY_INIT_SIZED(GhosttyStyle);
ghostty_render_state_row_cells_get(
cells, GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_STYLE, &style);
// Resolve foreground color for this cell.
GhosttyColorRgb fg =
resolve_color(style.fg_color, &colors, colors.foreground);
// Emit ANSI true-color escape for the foreground.
printf("\033[38;2;%u;%u;%um", fg.r, fg.g, fg.b);
if (style.bold) printf("\033[1m");
if (style.underline) printf("\033[4m");
// Read grapheme codepoints into a buffer and print them.
// The buffer must be at least grapheme_len elements.
uint32_t codepoints[16];
uint32_t len = grapheme_len < 16 ? grapheme_len : 16;
ghostty_render_state_row_cells_get(
cells, GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF,
codepoints);
for (uint32_t i = 0; i < len; i++) {
// Simple ASCII print; a real renderer would handle UTF-8.
if (codepoints[i] < 128)
putchar((char)codepoints[i]);
else
printf("U+%04X", codepoints[i]);
}
printf("\033[0m"); // Reset style after each cell.
}
printf("\n");
// Clear per-row dirty flag after "rendering" it.
bool clean = false;
ghostty_render_state_row_set(
row_iter, GHOSTTY_RENDER_STATE_ROW_OPTION_DIRTY, &clean);
row_index++;
}
//! [render-row-iterate]
//! [render-dirty-reset]
// After finishing the frame, reset the global dirty state so the next
// update can report changes accurately.
GhosttyRenderStateDirty clean_state = GHOSTTY_RENDER_STATE_DIRTY_FALSE;
result = ghostty_render_state_set(
render_state, GHOSTTY_RENDER_STATE_OPTION_DIRTY, &clean_state);
assert(result == GHOSTTY_SUCCESS);
//! [render-dirty-reset]
// Cleanup
ghostty_render_state_row_cells_free(cells);
ghostty_render_state_row_iterator_free(row_iter);
ghostty_render_state_free(render_state);
ghostty_terminal_free(terminal);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More