Commit Graph

15801 Commits

Author SHA1 Message Date
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
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
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