Merge upstream/ghostty into sidequery/ghostree#39
Open
DevEstacion wants to merge 1013 commits intosidequery:mainfrom
Open
Merge upstream/ghostty into sidequery/ghostree#39DevEstacion wants to merge 1013 commits intosidequery:mainfrom
DevEstacion wants to merge 1013 commits intosidequery:mainfrom
Conversation
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.
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.
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>
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.
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.
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.
Revert .gitattributes, CI test-windows job, and CRLF octants.txt fix back to main. These belong in their own branches/PRs.
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.
Add test-windows job running zig build -Dapp-runtime=none test on windows-2025. Added to required checks.
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.
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.
## 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.
## Summary This PR effectively enables testing for all the Windows related stuff that is coming soon. > [!IMPORTANT] >This PR builds on top of ghostty-org#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 c5092b0 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 ghostty-org#11782 -> backslash path handling in CommaSplitter/Theme - PR ghostty-org#11807 -> freetype compilation fix - PR ghostty-org#11810 -> ssize_t typedef for MSVC - PR ghostty-org#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.
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 ghostty-org#11897
Triggered by [comment](ghostty-org#11916 (comment)) from @pluiedev. Denounce: @daedaevibin Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Triggered by [discussion comment](ghostty-org#11921 (comment)) from @jcollie. Vouch: @i999rri Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.
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.
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.
…org#11910) Documenting some hidden implementation details. Basically extracted from the swift NSEvent extension.
ghostty-org#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.
…ts (ghostty-org#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 ghostty-org#11897
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.
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.
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](cachix/install-nix-action@96951a3...6165592) --- 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>
…hostty-org#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 -> 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="https://github.com/cachix/install-nix-action/commit/616559265b40713947b9c190a8ff4b507b5df49b"><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="https://github.com/cachix/install-nix-action/commit/b9f700df68e7810cde515c356dcf7787c9c7737d"><code>b9f700d</code></a> nix: 2.34.4 -> 2.34.5</li> <li>See full diff in <a href="https://github.com/cachix/install-nix-action/compare/96951a368ba55167b55f1c916f7d416bac6505fe...616559265b40713947b9c190a8ff4b507b5df49b">compare view</a></li> </ul> </details> <br /> [](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>
Fixes ghostty-org#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.
…-org#12206) Fixes ghostty-org#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.
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.
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.
Triggered by [discussion comment](ghostty-org#12213 (reply in thread)) from @pluiedev. Vouch: @otomn Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Previously with `macos-titlebar-style = tabs`, double clicking title will do nothing
Previously with `macos-titlebar-style = tabs`, double clicking title would do nothing
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.
Triggered by [discussion comment](ghostty-org#12223 (comment)) from @jcollie. Vouch: @kataokatsuki Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…#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.
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.
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.
…rg#12224) Fixes ghostty-org#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.
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.
…#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.
Regression of ghostty-org#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`
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.
Regression of ghostty-org#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`
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.
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.
) 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. 😄
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.
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.
Merge upstream/ghostty main into merge-upstream-ghostty
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changes
Testing