Commit Graph

16001 Commits

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